diff --git a/.gitattributes b/.gitattributes index 8c0c9b8b3f..11a25d44e3 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,4 @@ /dev/unicode/17.0.0/** -text +/src/main/perl/lib/unicore/Name.pl text eol=lf /src/main/java/org/perlonjava/runtime/regex/PerlUnicodeBlockData.java text eol=lf /src/main/java/org/perlonjava/runtime/regex/PerlUnicodeNumericValueData.java text eol=lf diff --git a/AGENTS.md b/AGENTS.md index 5324d3b6b0..bbf0d2c91c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -202,6 +202,7 @@ | 2026-08-17 | (no source work lost — stale workers removed) Failed `make` runs were interrupted after their known Joni failures, but their Gradle unit-shard workers survived and competed with later builds. | Agent sent Ctrl-C to the parent build session before all parallel workers had exited. Recovery: identified stale workers by PID, start time, and shard work directory, terminated only those exact PIDs, and left the current build and sibling repositories untouched. Fix: let failed parallel `make` runs finish naturally, or verify and clean up their exact child PIDs before starting another build. | | 2026-08-17 | (no source work lost — CPAN run rerun) A concurrent `make` replaced the development shadow JAR while an active `jcpan` process was spawning a child JVM, causing a transient `ClassNotFoundException`. | Agent waited for another worktree's build but did not wait for the same worktree's bounded CPAN runs before rebuilding `target/perlonjava-5.44.0.jar`. Recovery: let `make` finish and rerun the affected CPAN target. Fix: never rebuild a worktree's development JAR while that worktree has active `jperl` or `jcpan` processes. | | 2026-08-18 | (no source work lost — wrong local WIP ref recovered) A test-snapshot cherry-pick landed in the original checkout instead of its newly created continuation worktree. | Agent chained `git worktree add` and `git cherry-pick` while the shell remained in the original working directory. Recovery: preserved the mistaken commit on a recovery branch, restored the original WIP ref to its exact prior commit without reset, then cherry-picked in the intended worktree. Fix: run post-creation Git commands with the new worktree as the explicit working directory and verify `git branch --show-current` before committing. | +| 2026-08-20 | (no source work lost — green build evidence discarded) A coordinator cherry-picked an integrated worker commit into a checkout while `make` was still validating an earlier supposedly immutable commit. | Integration and validation shared one worktree, and the coordinator continued integration before the build session drained. Recovery: let the exact build processes finish untouched, mark the result invalid regardless of exit status, and rerun from an immutable barrier. Fix: never mutate, cherry-pick, rebase, or regenerate a checkout with an active build/test gate; integrate in a separate worktree or wait for the gate to finish. | When you cause a new incident, append a row here in the same commit that fixes it. Future agents need to see that these warnings are real. @@ -273,6 +274,13 @@ PerlOnJava does **not** implement the following Perl features: **NEVER modify or delete existing tests.** Tests are the source of truth. If a test fails, fix the code, not the test. When in doubt, verify expected behavior with system Perl (`perl`, not `jperl`). +**NEVER mutate a checkout while a build or test gate is running in it.** A gate +validates one immutable source commit. Wait for the process and all children to +finish before cherry-picking, rebasing, editing, or regenerating that checkout, +or run integration in a separate worktree. If mutation occurs, let the exact +processes drain without interruption, discard the result even if green, and +rerun from a clean immutable barrier. + **ALWAYS validate new unit tests with standard Perl before relying on them.** Unit tests in `src/test/resources/unit` must encode standard Perl behavior, not PerlOnJava-specific behavior. For any new or changed unit test, run it with `perl` or `prove` first, capture the output, and only then use it to drive PerlOnJava fixes: ```bash prove -r src/test/resources/unit > /tmp/prove_unit_perl.txt 2>&1; echo "EXIT: $?" >> /tmp/prove_unit_perl.txt diff --git a/Makefile b/Makefile index 2c5ea71907..819f35f984 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,6 @@ -.PHONY: all clean test test-unit test-interpreter check-thread-test-sources check-thread-core-test-sources check-thread-ecosystem-test-sources check-thread-regex-test-sources test-thread-tooling test-threads test-threads-core test-threads-core-platform test-threads-core-mode test-threads-windows test-threads-regex test-threads-release test-threads-ecosystem test-bundled-modules test-cpan-distroprefs test-exiftool test-all test-gradle test-gradle-unit test-gradle-all test-gradle-parallel test-maven-parallel build run wrapper check-java-gradle dev ci sbom sbom-java sbom-perl sbom-clean check-links +.PHONY: all clean test test-unit test-interpreter check-thread-test-sources check-thread-core-test-sources check-thread-ecosystem-test-sources check-thread-regex-test-sources test-thread-tooling test-threads test-threads-core test-threads-core-platform test-threads-core-mode test-threads-windows test-threads-regex test-threads-release test-threads-ecosystem test-bundled-modules test-cpan-distroprefs test-exiftool test-all test-gradle test-gradle-unit test-gradle-all test-gradle-parallel test-maven-parallel build run wrapper check-java-gradle dev ci sbom sbom-java sbom-perl sbom-clean check-links perl5-update perl5-sync + +PERL ?= perl THREAD_DIST_DIRS := perl5/dist/threads/t perl5/dist/threads-shared/t perl5/dist/Thread-Queue/t perl5/dist/Thread-Semaphore/t THREAD_PLATFORM_TESTS := \ @@ -82,6 +84,12 @@ THREAD_ECOSYSTEM_UPSTREAM_TESTS := \ all: build +perl5-update: + $(PERL) dev/import-perl5/update_perl5.pl + +perl5-sync: + $(PERL) dev/import-perl5/update_perl5.pl --sync $(if $(FILTER),--filter "$(FILTER)",) + # CI build - optimized for CI/CD environments ci: check-java-gradle ifeq ($(OS),Windows_NT) @@ -127,6 +135,15 @@ else ./gradlew classes testUnitParallel --parallel shadowJar endif +# Focused vendored-Joni unit gate for parser/matcher iteration. A full `make` +# remains required before pushing or updating a PR. +test-joni: check-java-gradle +ifeq ($(OS),Windows_NT) + gradlew.bat testJoni +else + ./gradlew testJoni +endif + # `make dev` is disabled on purpose. # # It used to be a "build without running tests" shortcut, but that is diff --git a/dev/design/cpan-compiler-tooling-batch-20260813.md b/dev/design/cpan-compiler-tooling-batch-20260813.md index 0321517c66..3fbbc30a51 100644 --- a/dev/design/cpan-compiler-tooling-batch-20260813.md +++ b/dev/design/cpan-compiler-tooling-batch-20260813.md @@ -143,5 +143,5 @@ was kept in the PerlOnJava validation set. ## References - [Module porting guide](../../docs/guides/module-porting.md) -- [Executable regex callbacks](executable-regex-callbacks.md) +- [Regex callout contract](../../docs/design/joni-callout-fork.md) - Skills: `debug-perlonjava`, `port-cpan-module` diff --git a/dev/design/cpan-runtime-parity-experiment.md b/dev/design/cpan-runtime-parity-experiment.md index 884b430e9c..adbb01f51b 100644 --- a/dev/design/cpan-runtime-parity-experiment.md +++ b/dev/design/cpan-runtime-parity-experiment.md @@ -220,5 +220,5 @@ Runtime outcome: - `dev/design/caller_line_number_fix.md` - `dev/design/utf8_flag_parity.md` -- `dev/design/regex_jruby_joni.md` +- `dev/implementation/regex.md` - `.agents/skills/debug-perlonjava/SKILL.md` diff --git a/dev/design/cpan-workaround-elimination.md b/dev/design/cpan-workaround-elimination.md index 346007a2ef..6765d8216e 100644 --- a/dev/design/cpan-workaround-elimination.md +++ b/dev/design/cpan-workaround-elimination.md @@ -1120,7 +1120,7 @@ Ubuntu and Windows CI jobs passed. - `dev/design/patch-and-cpan-prefs-layout.md` - `dev/design/cpan-runtime-parity-experiment.md` - `dev/design/catalyst-support.md` -- `dev/design/regex_alternatives.md` +- `dev/design/phase36-regex-parity.md` - `dev/design/shared_ast_transformer.md` - `.agents/skills/port-cpan-module/SKILL.md` - `.agents/skills/debug-perlonjava/SKILL.md` diff --git a/dev/design/executable-regex-callbacks.md b/dev/design/executable-regex-callbacks.md deleted file mode 100644 index c2f93bd898..0000000000 --- a/dev/design/executable-regex-callbacks.md +++ /dev/null @@ -1,656 +0,0 @@ -# Executable Regex Callbacks - -## Status - -- **Current phase:** Phase 3 — backtracking and dynamic scope -- **Started:** 2026-08-09 -- **Implementation status:** Callout engine and plain callback bridge integrated -- **Prerequisite:** Satisfied by the namespaced callout-enabled Joni integration -- **Primary targets:** `(?{ ... })`, `(?(?{ ... })yes|no)`, and `(??{ ... })` - -## Decision Summary - -Executable regex callbacks are implementable, but not by adding more textual -rewrites to `RegexPreprocessor` and not by wrapping `java.util.regex.Matcher`. -The matcher must invoke Perl while it owns the current backtracking state. - -The preferred implementation is: - -1. Preserve source-level regex code blocks as compiled `RuntimeCode` closures. -2. Represent an executable regex as a pattern skeleton plus a callback table. -3. Route executable patterns to a minimally extended Joni backend. -4. Add generic callout instructions and backtracking notifications to a maintained - Joni fork; keep that fork independent of PerlOnJava runtime classes. -5. Keep ordinary patterns on the existing Java backend and declarative recursive - patterns on the unmodified Joni path introduced by PR #895. - -Joni 2.2.7 has an explicit bytecode matcher and backtracking stack, which makes it -a useful base, but it has no in-match callout API. `WarnCallback` only reports -compile warnings, `Matcher.interrupt()` only cancels matching, and -`Regex.setUserObject()` stores opaque data without invoking it. The opaque user -object is still a suitable place for a generic callout table after extending the -engine. - -## Motivation - -PR #895 leaves explicit capability policies for executable regex paths. These -are high-value shared blockers rather than isolated test failures: - -- Type::Tiny constructs regex closures such as `qr/x(?{$z})/` and side-effecting - callbacks such as `qr/f(?{ ++$count })oo/`. -- Regexp::Common uses callback conditions for validation and `(??{ ... })` for - dynamically selected patterns. -- Object::InsideOut uses a self-referential `(??{ ... })` balanced-parentheses - pattern. -- Perl core regex suites exercise callback timing, provisional captures, - backtracking, lexical scope, dynamic scope, and runtime pattern compilation. - -A correct shared implementation can remove capability policies and improve -multiple core regex files. A partial preprocessor substitution would make these -modules appear to work while silently skipping user code, so unsupported cases -must remain fatal until their semantics are implemented. - -## Goals - -- Execute literal `(?{ BLOCK })` callbacks at the correct match position. -- Preserve lexical closures created by `qr//`, `m//`, and `s///` on both the JVM - and interpreter backends. -- Make provisional captures and match variables visible inside callbacks. -- Restore dynamically localized state when backtracking crosses a callback. -- Support callback conditions `(?(?{ BLOCK })yes|no)`. -- Support `(??{ EXPR })` as a nested dynamic regex program, including recursion. -- Preserve Perl's distinction between source-literal executable blocks and - executable source introduced by runtime interpolation under `use re 'eval'`. -- Retain the fast existing engine paths for regexes without executable code. -- Provide standard-Perl differential tests before enabling each semantic tier. - -## Non-goals - -- Replacing every regex with Joni. -- Rewriting Perl callbacks into Java expressions. -- Treating callbacks as post-match hooks. -- Making all callback side effects transactional. -- Silently treating unsupported callbacks as zero-width no-ops. -- Completing every unrelated Perl regex feature in the same project. -- JIT-compiling the callback-aware matcher in the first implementation. - -## Current Architecture and Gaps - -### Parser - -`StringSegmentParser.parseRegexCodeBlock()` already parses literal callback bodies -as Perl AST nodes. It currently chooses among: - -- constant folding and a synthetic empty named capture for `$^R`; -- construction-time execution of a very narrow increment/decrement form; -- `RegexMarkers.CODE_BLOCK` or `RegexMarkers.RECURSIVE_PATTERN` for unsupported - blocks. - -All three representations flatten or discard information needed by a real -matcher. In particular, a pattern string cannot retain a lexical closure. - -### Runtime - -`RuntimeRegex` currently compiles a string plus modifiers and caches by those -values. Match variables are populated from a completed match. Executable code -needs a per-regex callback table, provisional match state during execution, and a -cache identity that does not conflate distinct closures with identical source. - -### Regex engines - -`java.util.regex` does not expose its backtracking transitions. Splitting a -pattern around callbacks and matching each fragment atomically is incorrect when -a later fragment fails and an earlier quantifier or alternative must retry. - -PR #895 introduces a backend-neutral `RegexMatcher` and a Joni backend for -declarative subpattern recursion. That is the required routing seam, but the Joni -2.2.7 parser, compiler, opcode set, and bytecode matcher still have no callout -node or instruction. - -## Required Perl Semantics - -The implementation must be driven by observed standard-Perl behavior. The -following statements are design requirements to verify in Phase 0, not a -substitute for differential tests. - -### Callback timing - -- `(?{ BLOCK })` is a zero-width assertion executed when the matcher reaches it. -- It can execute more than once because of quantifiers, alternatives, lookarounds, - and backtracking. -- Its scalar result becomes `$^R`; its truth value does not decide whether a - plain `(?{ ... })` succeeds. -- Exceptions and non-local control flow must follow Perl behavior rather than be - converted into a match failure without evidence. - -### Provisional match state - -While a callback is running, these values must describe the current partial -match: - -- `$_` and `pos($_)`; -- numbered and named captures; -- `$^N`; -- `$^R`; -- `@-`, `@+`, `%+`, and `%-` where applicable; -- the pre-match variable, `$&`, and `$'` where Perl makes them observable at - that point. - -The runtime therefore needs a stack of active match views. Updating only the -global "last successful match" after `find()` returns is insufficient and breaks -nested regexes invoked from callbacks. - -### Backtracking and side effects - -Do not roll back every side effect. Perl can leave ordinary assignments, I/O, -warnings, and invoked subroutine effects visible even when the regex later -backtracks over the callback. - -State created through `local`, together with automatically localized regex state -such as `$^R`, must unwind at the corresponding backtracking boundary. The -matcher must therefore record a `DynamicVariableManager` local-level checkpoint -on entry and restore to it when the callout frame is discarded. This is a -dynamic-scope checkpoint, not a general mutation journal. - -The exact treatment of tied variables, magic, `pos()`, and callbacks inside -lookarounds must be established with differential tests. - -### Callback conditions - -`(?(?{ BLOCK })yes|no)` executes the block in scalar context and selects a branch -from its truth value. It is distinct from plain `(?{ BLOCK })` and requires a -branching matcher instruction rather than a precomputed condition. - -### Dynamic patterns - -`(??{ EXPR })` executes `EXPR` at the current match position and treats its -result as a regex program. The nested program must participate in outer -backtracking. Running one nested match atomically is insufficient: if a later -outer suffix fails, the nested program may need to yield another alternative. - -The implementation must distinguish returned regex objects from returned strings, -preserve applicable modifiers and capture behavior, support recursive results, -and prevent unbounded Java recursion. Cache behavior, `/o`, and empty or undefined -results require differential coverage. - -### Compile-time safety - -Literal code in a source regex is compiled as part of the surrounding Perl unit. -Code introduced through runtime interpolation is subject to Perl's `use re -'eval'` safety rule. Embedding an already compiled `qr//` containing callbacks -must not be confused with injecting new source text. - -## Proposed Architecture - -```text -Perl source - | - v -String/regex parser - |-- literal/interpolation AST - `-- callback BlockNode ASTs - | - v -JVM compiler or bytecode compiler - |-- evaluates pattern interpolation at construction time - `-- compiles each callback as a lexical RuntimeCode closure - | - v -RuntimeRegexTemplate - |-- engine pattern skeleton - |-- callback descriptors and RuntimeCode table - |-- source-origin and lexical re-eval policy - `-- modifiers / callsite identity - | - v -RuntimeRegex - |-- Java engine: ordinary supported patterns - |-- Joni engine: declarative recursion - `-- callout-Joni engine: executable callbacks - | - v -RegexCalloutBridge - |-- installs provisional match view - |-- invokes RuntimeCode in scalar context - |-- tracks dynamic-local checkpoints - `-- restores nested match state on exit/backtrack -``` - -### Frontend representation - -Add an explicit AST representation rather than inserting callback marker strings -into ordinary interpolation: - -```java -final class RegexTemplateNode extends AbstractNode { - List parts; -} - -sealed interface RegexTemplatePart { - record Pattern(Node scalarExpression) implements RegexTemplatePart {} - record Callback(BlockNode block, CallbackKind kind) implements RegexTemplatePart {} -} - -enum CallbackKind { - CODE, CONDITION, DYNAMIC_PATTERN -} -``` - -The final class names may differ, but the representation must keep Perl AST and -pattern text separate. Callback bodies must use the existing anonymous-code -closure analysis and emission paths rather than inventing another evaluator. -Their invocation semantics are block-like, however, not an ordinary named -subroutine call: they must not introduce a spurious caller frame or fresh `@_`, -and regex-controlled `local` frames may need to outlive the Java method call that -evaluates the block. - -Both compiler backends must construct the same runtime abstraction: - -```java -final class RuntimeRegexTemplate { - RuntimeScalar patternSkeleton; - List callbacks; - RegexSourceOrigin sourceOrigin; -} - -final class RuntimeRegexCallback { - int id; - CallbackKind kind; - RuntimeCode code; -} -``` - -The callback table belongs to each runtime regex value. Two closures produced -from the same source string must not share captured lexical cells accidentally. - -### Internal pattern encoding - -The engine-facing pattern may contain private callout tokens that refer to table -indices, but these tokens are an internal serialization of structured data, not -user-visible preprocessing fallbacks. The encoding must be collision-proof and -must never be accepted from untrusted interpolated pattern text as an already -compiled callback. - -The extended Joni parser should create dedicated callout AST nodes from these -tokens. It must not attempt to parse Perl source code. - -### Generic Joni extension - -Maintain a small Joni fork with a runtime-neutral interface similar to: - -```java -interface CalloutHandler { - CalloutResult execute(int calloutId, MatchView view); - void unwind(Object backtrackToken); -} - -record CalloutResult( - CalloutAction action, - Object value, - Object backtrackToken) {} - -enum CalloutAction { - CONTINUE, FAIL, SELECT_TRUE, SELECT_FALSE, ENTER_DYNAMIC_PATTERN -} -``` - -The concrete contract should use minimal allocation, but it needs to communicate: - -- callback identity; -- current byte position and provisional capture boundaries; -- result/action; -- a token to unwind dynamic state when the matcher backtracks past the callout. - -Add matcher instructions conceptually equivalent to: - -- `CALLOUT id` for `(?{ ... })`; -- `CALLOUT_CONDITION id, false_target` for callback conditions; -- `CALLOUT_PATTERN id` for `(??{ ... })`; -- a callout stack-frame type whose pop/unwind path notifies the handler. - -Keep all Perl-specific operations in `RegexCalloutBridge`. The Joni fork must not -depend on `RuntimeCode`, `RuntimeScalar`, or other PerlOnJava types. This keeps the -fork reviewable and makes an upstream generic callout proposal possible. - -### Dynamic pattern execution - -`CALLOUT_PATTERN` cannot delegate to a separate matcher that returns only its -first result. The preferred implementation compiles the returned pattern into a -Joni program and enters it as a nested regex call frame sharing the outer input, -current position, and required capture context. - -Phase 5 must first determine which Joni structures can safely be shared and -which capture-number translations Perl requires. If nested programs cannot be -entered without invasive Joni changes, stop and revise the design rather than -shipping atomic nested matching. - -### Runtime match-state bridge - -Introduce an active match-state stack rather than mutating one static completed -matcher in place: - -```java -final class ActiveRegexMatch { - RuntimeRegex regex; - RuntimeScalar target; - RegexMatcher matcher; - MatchView provisionalView; - RuntimeScalar previousCodeResult; -} -``` - -`RegexCalloutBridge` pushes or updates this state before invoking Perl and restores -the previous active view afterward. Nested matches from callback code then get a -new stack entry and cannot destroy the outer provisional captures. - -The existing `RegexState` and `DynamicVariableManager` are starting points, but -`RegexState` currently models completed global state. It will need either a -provisional-view extension or a separate callback match state. - -### Dynamic-local unwind - -Before executing a callback: - -1. Record `DynamicVariableManager.getLocalLevel()`. -2. Install the callback's provisional match view and automatic regex locals. -3. Invoke its `RuntimeCode` body in scalar context through a regex-block entry - point that preserves the surrounding `@_` and caller identity. -4. Transfer ownership of callback-created dynamic-local frames to the matcher - instead of applying the ordinary subroutine-exit unwind. -5. Retain the resulting local-level token in the Joni callout stack frame. - -On normal forward continuation, localized values remain active for the part of -the match governed by Perl semantics. When Joni backtracks across that frame, -the bridge calls `popToLocalLevel(savedLevel)` and restores the prior `$^R` and -provisional match view. At final match completion or failure, all remaining -callout frames must be unwound exactly once. - -This interaction needs explicit handling for exceptions, regex timeouts, matcher -interruption, and nested callbacks. If the existing `RuntimeCode.apply()` cleanup -cannot transfer dynamic-scope ownership, add a narrow `applyRegexCallback()` (or -equivalent execution mode); do not bypass cleanup by mutating the dynamic stack -after it has already been restored. - -### Caching - -Split cacheable engine structure from closure-bearing runtime values: - -- Declarative patterns may continue using the existing pattern/modifier cache. -- An executable regex wrapper is always per construction unless proven safe. -- A compiled callout skeleton may be cached by normalized skeleton, modifiers, - encoding mode, and engine version, while its callback table remains per value. -- `/o` uses callsite identity and retains the first constructed callback closure - according to standard-Perl behavior. -- Dynamic `(??{ ... })` subprogram caching must be specified by differential tests; - do not infer it from ordinary pattern caching. - -### Serialization and stringification - -`qr//` stringification must expose Perl-compatible source text, never internal -callout tokens or callback IDs. Storable support must be investigated separately: -serializing a closure-bearing regex may require the same restrictions as -serializing `RuntimeCode` closures. - -## Rejected Approaches - -### More `RegexPreprocessor` substitutions - -Textual substitutions cannot invoke code at the correct backtracking point and -cannot retain lexical closures. This includes replacing callbacks with empty -groups, synthetic captures, lookarounds, or post-match callbacks. - -### Splitting around Java matchers - -A wrapper cannot ask `java.util.regex.Matcher` for the next internal alternative -of an earlier fragment after a later fragment fails. Making delegated fragments -atomic changes Perl semantics. - -### Executing callbacks while constructing the regex - -This gets timing, repetition, captures, and backtracking wrong. The existing -narrow increment/decrement construction-time path should be removed once the -real callback path is available. - -### Blanket transactional rollback - -Rolling back arbitrary assignments and external side effects would not match -Perl. Only dynamically scoped and automatically localized match state should be -restored at backtracking boundaries. - -### JNI to the system Perl regex engine - -The system engine cannot directly execute PerlOnJava `RuntimeCode` closures or -share PerlOnJava lexical cells. A native bridge would also add platform and -deployment costs without removing the callback-runtime integration problem. - -### Full custom regex VM as the first step - -A custom VM remains a fallback if the Joni spike fails, but it duplicates a large -working matcher before the callback semantics have been validated. Extend the -explicit-stack backend already entering PerlOnJava through PR #895 first. - -## Differential Test Plan - -Create `src/test/resources/unit/regex_executable_callbacks.t`. As required for -unit tests, validate every addition with standard Perl before relying on it for -PerlOnJava behavior. - -### Phase 0 semantic matrix - -Cover at least: - -1. Plain callback execution and scalar `$^R` results. -2. False callback results that do not fail plain `(?{ ... })`. -3. Package-variable and lexical-closure reads/writes. -4. Multiple execution under alternation, greedy/lazy quantifiers, and failure. -5. Ordinary side effects after backtracking. -6. `local` restoration after forward progress, backtracking, success, and failure. -7. `$1`, named captures, `$^N`, `$^R`, `@-`, `@+`, `$_`, and `pos()`. -8. Positive and negative lookarounds. -9. Nested regex matches invoked by callback code. -10. Callback exceptions and surrounding `eval`. -11. Callback conditions with true, false, and backtracked branches. -12. `(??{ ... })` returning strings, `qr//` values, empty values, and recursive - patterns. -13. Literal callbacks versus interpolated executable source with and without - `use re 'eval'`. -14. `qr//` closure lifetime after the creating lexical scope exits. -15. `/g`, `/c`, `/o`, substitution, and byte/Unicode target behavior. - -Suggested baseline command: - -```bash -prove src/test/resources/unit/regex_executable_callbacks.t \ - > /tmp/prove_regex_executable_callbacks_perl.txt 2>&1 -printf 'EXIT: %s\n' "$?" \ - >> /tmp/prove_regex_executable_callbacks_perl.txt -``` - -After each implementation phase, run both PerlOnJava backends with `timeout` and -capture complete output in files. - -### Perl core gates - -Use `perl dev/tools/perl_test_runner.pl` for broad counts and focused `jperl` -runs only under `timeout`: - -- `perl5_t/t/re/rxcode.t` -- `perl5_t/t/re/reg_eval.t` -- `perl5_t/t/re/reg_eval_scope.t` -- `perl5_t/t/re/pat_re_eval.t` -- callback-related sections of `pat.t`, `pat_advanced.t`, and `subst.t` - -Passing the focused unit file is not sufficient to claim full callback support. -Record reached assertions and remaining categories for each core file. - -### CPAN policy-removal gates - -- Run the original Type::Tiny callback tests without - `SkipRegexCallbackTests.patch` on both backends. -- Run the unchanged Regexp::Common suite and classify remaining non-callback - failures separately. -- Run Object::InsideOut's unchanged self-recursive pattern and its relevant suite. -- Remove a distropref or patch only after its unchanged source suite passes or the - remaining policy has a separately documented capability reason. - -### Regression and performance gates - -- Run full `make` after every implementation phase. -- Preserve Java-regex behavior and performance for non-executable patterns. -- Compare Joni recursive-pattern tests introduced by PR #895 before and after the - fork. -- Add timeout/step-limit tests for callbacks that recursively start matches. -- Measure allocation and throughput for ordinary patterns to ensure callback - state is not allocated on their fast path. - -## Implementation Phases - -### Phase 0: Differential semantics and Joni spike - -- Add the standard-Perl semantic matrix. -- Prototype a generic no-op callout node, opcode, handler, and unwind notification - in a temporary Joni fork. -- Prove that a callback can observe provisional captures and runs again after - backtracking. -- Decide fork publication/versioning and upstreaming strategy. - -**Exit criteria:** The differential output is captured; the Joni prototype can -enter and unwind a generic callback without PerlOnJava dependencies; no working -tree-only fork changes remain. - -### Phase 1: Structured frontend and runtime template - -- Add callback-aware regex AST/template nodes. -- Compile callback blocks as lexical `RuntimeCode` closures in both backends. -- Construct per-value callback tables and collision-proof engine skeletons. -- Preserve existing fatal behavior until the matcher execution path exists. - -**Exit criteria:** JVM and interpreter construct equivalent templates; closure -identity and lifetime tests pass without executing callbacks during construction. - -### Phase 2: Plain `(?{ ... })` - -- Integrate the callout-enabled Joni dependency. -- Add `CALLOUT`, provisional match views, `$^R`, and nested match-state stacking. -- Support package and lexical variable access. -- Keep unsupported semantic combinations fatal rather than silently approximated. - -**Exit criteria:** The Phase 0 plain-callback matrix passes on standard Perl, JVM, -and interpreter; relevant Type::Tiny callback tests pass unchanged. - -### Phase 3: Backtracking and dynamic scope - -- Add callout backtracking frames and exact-once unwind. -- Restore `local` and automatic regex state without reverting ordinary side - effects. -- Cover lookarounds, quantifiers, failure, exceptions, interruption, and timeout. - -**Exit criteria:** Backtracking/localization sections of `rxcode.t` and -`reg_eval_scope.t` match standard Perl on both backends. - -### Phase 4: Callback conditions - -- Parse and represent `(?(?{ ... })yes|no)`. -- Add conditional callout branching. -- Validate provisional `$^N` and captures used by Regexp::Common validators. - -**Exit criteria:** Target Regexp::Common callback-condition cases and focused core -tests pass unchanged. - -### Phase 5: `(??{ ... })` dynamic programs - -- Add nested program compilation/execution inside the Joni matcher. -- Integrate nested alternatives with outer backtracking. -- Specify capture numbering, modifier inheritance, recursion limits, and caching. -- Support self-referential runtime regex values without Java stack recursion. - -**Exit criteria:** Differential dynamic-pattern matrix, Object::InsideOut's -self-recursive pattern, and applicable `reg_eval.t`/`rxcode.t` sections pass. - -### Phase 6: Runtime source, hardening, and policy removal - -- Implement `use re 'eval'` checks for runtime-injected executable source. -- Finish `/g`, `/c`, `/o`, substitution, byte/Unicode, stringification, warning, - timeout, and serialization behavior. -- Run complete core and CPAN gates. -- Remove obsolete markers, construction-time callback hacks, CPAN patches, and - capability policies only when their gates pass. -- Update feature matrix and user documentation. - -**Exit criteria:** Full `make` passes; unchanged target suites have recorded results; -removed policies are justified by passing source-first gates. - -## Risks and Mitigations - -| Risk | Mitigation | -|---|---| -| Joni fork becomes large or hard to rebase | Keep the callout SPI generic and opcode patch minimal; stop after Phase 0 if nested integration requires broad unrelated changes. | -| Callback match state corrupts nested regexes | Use an explicit active-match stack and differential nested-match tests. | -| Dynamic locals leak after failure or timeout | Store local-level tokens in matcher frames and exercise every exit path. | -| Cache reuses the wrong lexical closure | Separate cached skeletons from per-value callback tables; include callsite identity for `/o`. | -| Internal callback IDs can be injected by user strings | Use structured source-origin metadata and collision-proof private tokens rejected from runtime text. | -| `(??{ ... })` is treated atomically | Require nested alternatives to participate in outer backtracking before enabling the feature. | -| Core suite gains apparent passes from no-op fallback | Keep unsupported callbacks fatal and remove no-op behavior only through explicit test gates. | -| Ordinary regexes regress | Preserve engine dispatch fast paths and run PR #895 plus full `make` regression gates. | - -## Open Questions - -1. Can the Joni callout extension be accepted upstream, or should PerlOnJava - publish a namespaced fork from the start? -2. What is the minimal provisional-capture API that avoids allocating `Region` - snapshots for every callback? -3. Should active regex state become thread-local immediately, or can it be layered - over current static fields without compromising concurrent use? -4. How exactly does standard Perl scope callback-created `local` values during - successful forward continuation and quantifier repetition? -5. Which captures created by a returned `(??{ ... })` pattern are visible to the - outer pattern, and how should Joni group numbers be translated? -6. What are Perl's cache rules when `(??{ ... })` repeatedly returns equal strings - or the same `qr//` object? -7. How should closure-bearing regex values interact with Storable? -8. Which non-local control-flow operations are legal from a regex callback, and - how should both compiler backends propagate them? - -Do not resolve these by intuition. Add standard-Perl differential cases and -record the observed output in this document as phases proceed. - -## Progress Tracking - -### Current Status: Phase 6 delivered; mixed source composition complete - -### Completed Phases - -- [x] Phase 0: Differential semantics and Joni spike -- [x] Phase 1: Structured frontend and runtime template -- [x] Phase 2: Plain `(?{ ... })` -- [x] Phase 3: Backtracking and dynamic scope -- [x] Phase 4: Callback conditions -- [x] Phase 5: `(??{ ... })` dynamic programs (2026-08-16) -- [x] Phase 6: Runtime source and hardening (2026-08-16) - -### Next Steps - -1. Resolve exact runtime-eval source names, warning locations, and diagnostic - differences. -2. Remove only capability policies justified by unchanged-source suite results. -3. Extend focused differential coverage for tied and magical callback paths - that throw or recurse. - -### Blockers - -- `pat_re_eval.t` executes all 555 planned assertions on both backends, with - 420 passing and 135 remaining semantic or diagnostic failures. The focused - mixed-source gate is 16/16, `reg_eval_scope.t` is 49/49, and Object::InsideOut - is 6/6 on both backends. - -## Related Documents and Skills - -- `dev/design/regex_jruby_joni.md` — older broad Joni migration notes -- `dev/design/regex_parser_integration.md` — regex AST/parser strategy -- `dev/design/regex_preprocessing_fixes.md` — known preprocessing gaps and counts -- `dev/design/regex_alternatives.md` — engine alternatives -- `dev/implementation/regex.md` — earlier full-VM and hybrid architecture notes -- `dev/design/cpan-workaround-elimination.md` — compatibility-policy design - introduced by PR #895 (not present on `master` until that PR is merged) -- `.agents/skills/debug-perlonjava/SKILL.md` — required debugging and differential - workflow diff --git a/dev/design/jcpan-packed-crypto-tooling.md b/dev/design/jcpan-packed-crypto-tooling.md index b29f8e3217..274f5e524a 100644 --- a/dev/design/jcpan-packed-crypto-tooling.md +++ b/dev/design/jcpan-packed-crypto-tooling.md @@ -59,8 +59,8 @@ Ignore a target only when its unchanged suite also fails under system Perl. ### Open Questions - `ExtUtils::ParseXS` 3.64 uses executable `(??{ ... })` regex callbacks. - That capability is deliberately tracked by - `dev/design/executable-regex-callbacks.md`; it surfaced only through + The current callback contract is tracked by + `docs/design/joni-callout-fork.md`; it surfaced only through HTTP::Message's optional Brotli recommendation during the Catalyst run and must not be papered over with a source patch. - `Proc::ProcessTable`'s native upstream suite still fails under system Perl in @@ -70,7 +70,7 @@ Ignore a target only when its unchanged suite also fails under system Perl. ## Related documentation and skills -- `dev/design/executable-regex-callbacks.md` +- `docs/design/joni-callout-fork.md` - `docs/guides/module-porting.md` - `.agents/skills/debug-perlonjava/SKILL.md` - `.agents/skills/port-cpan-module/SKILL.md` diff --git a/dev/design/perl-regex-library-rfc.md b/dev/design/perl-regex-library-rfc.md index da9973b573..37b194165b 100644 --- a/dev/design/perl-regex-library-rfc.md +++ b/dev/design/perl-regex-library-rfc.md @@ -176,7 +176,5 @@ behavior or stabilize transitional routing decisions. Related documents: - `dev/design/phase36-regex-parity.md` -- `dev/design/executable-regex-callbacks.md` -- `dev/design/regex_engines.md` -- `dev/design/regex_jruby_joni.md` - `dev/implementation/regex.md` +- `docs/design/joni-callout-fork.md` diff --git a/dev/design/phase36-regex-differential-20260817.md b/dev/design/phase36-regex-differential-20260817.md deleted file mode 100644 index e4b47f09cc..0000000000 --- a/dev/design/phase36-regex-differential-20260817.md +++ /dev/null @@ -1,185 +0,0 @@ -# Phase 36 Forced-Backend Regex Differential — 2026-08-17 - -## Scope - -This report records the 80-file `perl5_t/t/re` corpus with the temporary Java -and Joni matcher selector on both PerlOnJava execution backends. The corpus -uses the clean pre-PR-1002 binary built from commit `ba85bdc05`; its SHA-256 is: - -```text -04be3d3d52348dbda4de1ff187df5cd9d788a274ab14bbb5170bafe879cd12cf -``` - -The historical comparison is PR 958's captured runner log: - -```text -../PerlOnJava/logs/test_20260815_080000_958.log -``` - -That log contains all 80 regex files and records 50,273/94,771 passing -assertions. Complete logs, runner JSON, and normalized comparison JSON remain -outside Git under `/tmp/phase36-regex-*`. - -PR 1002 merged and PR 1005's package-localization fix was prepared after this -binary was frozen. In particular, PR 1005 closes `pat_advanced.t` tests -922–933. Those changes are intentionally not mixed into this same-commit -matrix; a later verification rerun must use one rebuilt current-master binary -for all four legs. - -## Method - -Each matrix leg inherits one matcher selection and, for interpreter legs, -global interpreter selection. `perl_test_runner.pl` owns a hard timeout and -process group for every `jperl` child. Full output is captured to a log and the -runner writes per-file JSON. The displayed 300-second value is the base limit; -the runner's configured heavy-file overrides raise `pat_psycho*` and other -designated heavy fixtures to 600 seconds. - -```text -JPERL_REGEX_BACKEND=java perl dev/tools/perl_test_runner.pl \ - --timeout 300 --jobs 5 --output /tmp/phase36-regex-java-jvm.json perl5_t/t/re - -JPERL_REGEX_BACKEND=joni perl dev/tools/perl_test_runner.pl \ - --timeout 300 --jobs 5 --output /tmp/phase36-regex-joni-jvm.json perl5_t/t/re - -JPERL_REGEX_BACKEND=java JPERL_INTERPRETER=1 \ - perl dev/tools/perl_test_runner.pl --timeout 300 --jobs 6 \ - --output /tmp/phase36-regex-java-interpreter.json perl5_t/t/re - -JPERL_REGEX_BACKEND=joni JPERL_INTERPRETER=1 \ - perl dev/tools/perl_test_runner.pl --timeout 300 --jobs 6 \ - --output /tmp/phase36-regex-joni-interpreter.json perl5_t/t/re -``` - -The comparison gate now reports execution errors, incomplete files, and -zero-TAP results explicitly. `--expected-files 80 --fail-on-invalid` rejects an -incomplete corpus independently of the existing per-file pass-count regression -gate. - -## Matrix Summary - -| Matcher | Execution backend | Passing / planned | Delta vs PR 958 | Timeouts | Status | -|---|---|---:|---:|---:|---| -| Java | JVM | 49,923 / 94,823 | -350 / +52 | 0 | complete | -| Joni | JVM | 32,479 / 77,612 | -17,794 / -17,159 | 10 | complete | -| Java | interpreter | 50,021 / 94,823 | -252 / +52 | 0 | complete | -| Joni | interpreter | 32,483 / 77,612 | -17,790 / -17,159 | 10 | complete | - -## Complete Java/JVM Comparison - -The forced-Java/JVM leg covered all 80 files. It has four per-file pass-count -regressions against PR 958: - -| File | PR 958 | Candidate | Delta | Initial classification | -|---|---:|---:|---:|---| -| `pat.t` | 1099/1302 | 239/1302 | -860 | shared source-provenance abort | -| `pat_thr.t` | 1099/1302 | 239/1302 | -860 | same direct failure in thread wrapper | -| `reg_mesg.t` | 1692/2525 | 1664/2521 | -28 | diagnostics and plan change | -| `regexp_normal.t` | 2193/2210 | 2175/2210 | -18 | matcher semantics | - -`pat{,_thr}.t` stops immediately after test 239 with: - -```text -Eval-group not allowed at runtime, use re 'eval' -``` - -This is not an optimizer/debug transcript difference or a Java/Joni routing -difference. The forced-Joni leg stops at the same point. The failing literal -uses single-quote regex delimiters, `m'a(?{ ... })b'`; initial reduction shows -that this parse path produces a plain pattern string and loses trusted literal -callback provenance before matcher selection. - -The net aggregate loss masks substantial progress since PR 958. In particular, -`pat_re_eval{,_thr}.t` improves from 0/555 to 423/555 each, -`pat_advanced{,_thr}.t` improves from 1376/1687 to 1511/1687 each, -`reg_eval_scope.t` reaches 49/49, and `rxcode.t` reaches 40/42. - -## Complete Joni/JVM Comparison - -The forced-Joni leg covers all 80 files but falls to 32,479/77,612: 17,794 -fewer passing assertions and 17,159 fewer planned assertions than PR 958. It -contains 27 per-file pass-count regressions, 33 execution issues, and 29 -zero-TAP files. Ten files reach their runner-owned bounds with zero TAP: - -- 300 seconds: `regex_sets_compat.t`, `regexp.t`, `regexp_noamp.t`, - `regexp_notrie.t`, `regexp_qr.t`, `regexp_qr_embed.t`, and - `regexp_trielist.t`. -- 600 seconds: `pat_psycho.t`, `pat_psycho_thr.t`, and - `regexp_qr_embed_thr.t`. - -The cluster is matcher-specific: the same files complete in the forced-Java -leg. Reduction must determine whether each stall occurs during Joni compile or -search before any broad implementation change. - -Completed Joni/JVM files also expose semantic gaps independent of timeout: - -- `pat{,_thr}.t`: 239/1302 each, sharing the matcher-independent literal - callback provenance abort described above. -- `pat_advanced{,_thr}.t`: 1271/1687 each, versus forced Java 1511/1687. -- `reg_mesg.t`: 1364/2486, versus forced Java 1664/2521. -- `reg_posixcc.t`: 2052/2560, versus forced Java 2560/2560. -- `regexp_normal.t`: 2175/2210 on both matcher selections. -- `regexp_unicode_prop.t`: 1039/1110; its thread wrapper is 1040/1110. - -`speed.t` exits incomplete at 1/59 after 451 seconds and `speed_thr.t` exits -incomplete at 1/59 after 301 seconds. These are internal-watchdog/incomplete -results rather than runner timeouts, but still lose 25 passing assertions per -file against PR 958. - -## Complete Java JVM/Interpreter Comparison - -The forced-Java interpreter leg covers all 80 files at 50,021/94,823. It has -the same zero runner timeouts and planned count as forced-Java/JVM, while -gaining 98 passing assertions in aggregate. That aggregate gain is entirely -driven by `alpha_assertions.t` (2188/2320 on JVM and 2293/2320 on interpreter, -+105); four interpreter-specific losses remain: - -| File | JVM | Interpreter | Delta | -|---|---:|---:|---:| -| `reg_eval_scope.t` | 49/49 | 45/49 | -4 | -| `pat_advanced.t` | 1511/1687 | 1510/1687 | -1 | -| `pat_advanced_thr.t` | 1511/1687 | 1510/1687 | -1 | -| `qr.t` | 4/4 | 3/4 | -1 | - -Against PR 958, the interpreter leg has five pass-count regressions: the same -four Java/JVM corpus regressions plus `qr.t` at -1. These execution-backend -differences are shared runtime/compiler parity gaps, not Java-vs-Joni matcher -differences. - -## Complete Joni JVM/Interpreter Comparison - -The forced-Joni interpreter leg covers all 80 files at 32,483/77,612. Its ten -timeouts, 33 execution issues, 29 zero-TAP files, and planned count are -identical to Joni/JVM. It gains four passing assertions in aggregate, again -masking execution-backend differences: - -| File | JVM | Interpreter | Delta | -|---|---:|---:|---:| -| `reg_eval_scope.t` | 49/49 | 45/49 | -4 | -| `qr.t` | 4/4 | 3/4 | -1 | -| `alpha_assertions.t` | 2099/2320 | 2108/2320 | +9 | - -On the interpreter execution backend, selecting Joni instead of Java changes -50,021/94,823 to 32,483/77,612: 17,538 fewer passing and 17,211 fewer planned -assertions, with 29 regressing and three improving files. The loss categories -match the JVM engine differential, so the primary blocker is matcher selection -rather than execution-backend compilation. - -## Classification and Follow-up - -- Source policy: fix the matcher-independent single-quote literal callback - provenance abort after this report PR, with a focused standard-Perl oracle. -- Matcher semantics: separate the shared `regexp_normal.t` loss from - Joni-only `pat_advanced.t` and POSIX/property losses. -- Diagnostics: treat `reg_mesg.t` independently from matching behavior. -- Timeout behavior: reduce the Joni timeout cluster under individual hard - timeouts; do not hide it through Java fallback. -- Optimizer/debug transcript: none of the regressions above are currently - classified as transcript-only exclusions. - -The Phase 1 exit criterion is not met. Joni fails to retain every assertion -that passes under Java, introduces ten matcher-specific timeouts on both -execution backends, and exposes independent semantic and diagnostic losses. -The four relevant pairwise comparisons (Java/Joni within each execution -backend and JVM/interpreter within each matcher selection) are complete and -retained under `/tmp/phase36-compare-*`. diff --git a/dev/design/phase36-regex-parity.md b/dev/design/phase36-regex-parity.md index 0e93bf7851..e1a13b9c20 100644 --- a/dev/design/phase36-regex-parity.md +++ b/dev/design/phase36-regex-parity.md @@ -2,387 +2,317 @@ ## Goal -Implement Perl 5.44 regular-expression semantics on both PerlOnJava execution -backends and make the vendored Joni fork the sole production matcher. Java -`Pattern` and the backend selector are temporary differential tools and must be -removed before completion. +Implement the regex semantics of the latest imported upstream Perl on both +PerlOnJava execution backends, with the vendored Joni fork as the sole +production matcher. -The contract includes matching, captures, match state, callbacks, dynamic -patterns, diagnostics, warnings, source locations, byte/Unicode behavior, -direct/thread parity, unchanged Perl core tests, and unchanged CPAN consumers. -Optimizer programs and debug transcripts are reported separately from language -semantics. - -The immutable no-regression comparison point is: +The immutable no-regression baseline is: ```text ../PerlOnJava/logs/test_20260815_080000_958.log ``` -## Final Architecture +An implementation PR may merge incrementally when every valid baseline test row +retains at least its PR 958 passing count and at least one row improves. That is +a merge boundary, not project completion. Completion requires every phase and +final-acceptance item below. + +## Required Architecture -- The forked Joni engine is implemented and maintained in this repository. - Joni owns regex grammar and matcher semantics: captures, conditions, - recursion, lookarounds, case folding, control verbs, backtracking-visible - state, byte/Unicode matching, and property membership. + recursion, lookarounds, folding, control verbs, backtracking-visible state, + byte/Unicode matching, properties, and native compile diagnostics. - PerlOnJava owns source policy: interpolation provenance, lexical hints and - warnings, `use re 'eval'`, executable Perl closures, user-defined properties, - source locations, and final Perl diagnostic rendering. -- The fork remains runtime-neutral. Callouts use internal IDs and a matcher-local - handler API; Joni never receives Perl source or PerlOnJava runtime objects. -- Upstream Joni/JCodings package names and all copyright/authorship notices stay - intact under `third_party/`. Standalone packaging relocates them to - `org.perlonjava.internal`, avoiding public namespace collisions without - rewriting the maintained source namespace. -- Joni is the default for every closure-bearing pattern throughout migration. - No callback, condition, control verb, recursive program, or dynamic source may - fall back to Java. Ordinary constants move to Joni as their native gates pass. -- Final production code has one matcher. Ordinary patterns allocate no callout - state, and a match operation never runs two engines because regex side effects - are observable. + warning masks, `use re 'eval'`, executable Perl closures, user-defined + properties, source locations, and final Perl diagnostic rendering. +- No production regex may route to `java.util.regex`, including ordinary + constant patterns. Historical selector-policy tests use a test-scope-only + model that cannot enter production artifacts. +- The maintained Joni/JCodings source packages remain unchanged under + `third_party/`; standalone packaging relocates them to + `org.perlonjava.internal` to avoid public collisions. +- Every original Joni/JCodings copyright, authorship, and license notice is + preserved byte-for-byte. +- Joni remains runtime-neutral. Callouts expose internal IDs and matcher-local + handlers, never Perl source or PerlOnJava runtime objects. +- Ordinary patterns allocate no callout state. One match operation runs exactly + one engine because regex side effects are observable. +- Imported Perl and Unicode inputs track the latest upstream `perl5/` + checkout. Do not pin a fixed Perl SHA or release. ## Preprocessing Boundary -Classify every current regex preprocessing rule as one of: +Every transformation must fit one category: 1. Perl source policy retained in a small frontend scanner. 2. Backend-neutral spelling normalization retained outside the matcher. -3. Matcher semantics moved into Joni parser/compiler/matcher internals. -4. Java-only translation or stack workaround deleted with the Java backend. +3. Matcher semantics implemented in Joni parser/compiler/matcher internals. +4. Java-only translation or workaround deleted. Text rewriting must not emulate behavior dependent on capture close order, -backtracking, matcher regions, encoding, or callback execution. As native fixes -land, remove corresponding `RegexPreprocessor` code immediately and rerun the -affected corpus before taking another slice. - -## Current Validated Position - -- The reproducible differential baseline and conditions/control-verb phase are - complete. -- `(*MARK:NAME)`, named `(*SKIP:NAME)`, `$REGMARK`, `$REGERROR`, callback unwind, - and native `(*THEN)` branch boundaries are in the Joni path. -- Absolute, forward, backward, whole-pattern, and signed-relative numbered - subpattern calls parse natively in Joni; the adapter rewrite is gone. -- Recursive callouts observe captures from the just-completed recursive frame. -- Folded exact-search candidate bounds are safe for long ASCII-strict literals, - and native numbered-call diagnostics retain the Perl source location. -- The last complete forced-Joni `pat_advanced.t` gate executes 1,687/1,687 and - passes 1,646 on JVM and interpreter, with identical 41-row residuals. The - integrated signed-IV range fix removes row 1651 with zero introductions in - exact A/B evidence; a fresh combined serial gate remains required because a - later run stopped before the complete plan under concurrent CPAN load. -- The current imported `reg_mesg.t` passes 1,794/2,613 on each backend with an - identical status/test-number vector. -- Forced-Joni Unicode property comparison is 83,648/83,648 on both backends. - The Hyphen/IsHyphen warning correction removes the final exact 32 residuals - with zero introductions while preserving dynamic property interpolation. -- The shared deterministic pinned-Perl Unicode generator covers all current - property families plus compact Perl default simple/full/reverse case-fold - metadata. General_Category compatibility aliases, native named-call/parser - safety, the runtime-neutral Joni property-value matcher, signed-IV user- - property ranges, POSIX compatibility, and generated fold data are integrated. - The analyser fold-safety slice, final binary aliases, generated named-sequence - lookup, property-wildcard execution, Hyphen diagnostics, native extended - classes, property/class fold closure, and nested property-wildcard lexing are - integrated in local staging. -- Raw `\N{name}` source now survives frontend and matcher compilation without - the temporary `=POJSEQ=` transport. Generated and lexical multi-code-point - names and ordinary scalar names resolve through Joni; the temporary - generated-sequence-only routing distinction is deleted. -- `master` contains the validated named-character diagnostics plus native - `(?(DEFINE)...)`, ordinary lookbehind, branch reset, and plain `\N`; its exact - head passed warning-free local, Ubuntu, and Windows gates. -- Byte/Unicode provenance and fold policy, dotted-U+ diagnostics, the ordinary- - pattern Joni default, a dynamic-pattern edge contract, and the first obsolete - import retirement are integrated. Fold, property, resolver-cache, and the - classified runtime-diagnostic residuals are closed. -- Native DEFINE, ordinary lookbehind, and branch reset now route through Joni; - their feature-specific Java rewrites and branch-reset capture-map adapter are - deleted. Plain Perl `\N` is a native Joni non-line-feed atom, including - intervals, `/s` independence, and Perl's character-class diagnostic. -- Unknown, empty, malformed/dotted U+, and missing-brace named-character groups - have native frontend/runtime diagnostics. -- Forced-Joni `pat_re_eval.t` now executes and passes 555/555 on both JVM and - interpreter. Perl's release-build `-D` diagnostic is preserved without - enabling PerlOnJava's unrelated internal compiler trace. -- Each `pat.t` variant executes 1,301/1,302; JVM passes 1,225 and interpreter - passes 1,234. The remaining JVM-only dynamic code-array rows are active work. -- The four Java/Joni × JVM/interpreter legs now have one 80-file comparison - ledger on the pre-successor artifact. It identifies stable extended-class, - regexp, charset, fold-grind, and bounded-speed negative clusters plus several - zero-TAP/execution records. The complete matrix must be repeated on the exact - successor artifact before acceptance; older aggregate figures are not release - evidence. -- Exact `/aa` routing/folding gates pass on native Joni, and the Java `/aa` - workaround is removed. -- Perl grouped nested-quantifier semantics and extended-mode quantifier - modifiers are native Joni behavior; the exact `regexp.t` differential removes - seven failures with no introductions. -- Named `(*ACCEPT:NAME)`, `(*FAIL:NAME)`, and `(*F:NAME)` carry control state - through native Joni bytecode and publish Perl-compatible `$REGMARK` and - `$REGERROR`; the exact `regexp.t` differential removes three failures with no - introductions. -- Negative lookbehind accepts capture enclosures and uses ACCEPT-aware width - analysis in native Joni; named cut errors remain authoritative before an - unnamed FAIL. The combined exact `regexp.t` differential has no introductions. -- Perl `/xx` character-class whitespace and nested inline `x`/`xx` mode changes - are native Joni lexer/parser behavior. The corresponding `regexp.t` identities - pass without introductions on both execution backends. -- Reverse full-fold alternatives can repartition across adjacent source - literals without changing single-literal lookbehind width. The targeted - `regexp.t` identity and the existing literal/backreference fold contract pass - on default and forced Joni for JVM and interpreter. -- Perl's exact `L_` General_Category compatibility spelling resolves as `LC` - before loose alias normalization, so uncased letters no longer enter that - class. The focused system-Perl oracle, four runtime legs, and imported - `regexp.t` identity agree. +backtracking, matcher regions, encoding, or callback execution. When a native +Joni fix lands, remove its corresponding preprocessor/runtime scanner in the +same tranche. + +Remaining scanner-removal queue: + +- [ ] Make Joni's property resolver accept every raw built-in Perl spelling + currently expanded by `JoniRegexPattern.translateUserDefinedProperties`, + including Script, Script_Extensions, Block, Age/Present_In, and aliases. +- [ ] Keep raw user-defined property tokens through Joni parsing and resolve or + defer them through the mode-specific callback cache; remove never-match or + match-all text substitutions used to represent deferred properties. +- [ ] Preserve ordinary/extended-class context and source positions in Joni so + the adapter no longer scans bracket depth or generates replacement classes. +- [ ] Retain only runtime-neutral trusted-callout materialization and documented + Perl source-policy checks outside Joni; delete the scanner when these gates + pass. ## Execution Phases ### Phase 0 — Reproducible differential baseline -- Run the same 80 `perl5_t/t/re` files on JVM/interpreter and forced Java/Joni. -- Save complete logs and machine-readable results outside the tree. -- Reject zero-TAP, timeout, truncated, or incomplete records before comparing. -- Classify failures as matcher semantics, source policy, diagnostics, shared - runtime behavior, or optimizer/debug-only output. +- [x] Derive the complete regex-bearing test ledger mechanically. +- [x] Preserve direct and `_thr.t` identities separately. +- [x] Reject zero-TAP, timeout, truncated, incomplete, or malformed records. +- [x] Emit machine-readable file/test comparison evidence against PR 958. -Exit: the baseline is repeatable and every next slice has exact rows and an -oracle. +Exit: every implementation slice has exact rows, a standard-Perl oracle, and a +repeatable baseline. ### Phase 1 — Ordinary-pattern Joni parity -- Complete byte/Unicode variant selection from pattern and subject provenance. -- Close captures, duplicate names, branch reset, regions, bounds, zero-width - search progression, `\G`, `/g`, `/c`, `/o`, substitution, reuse, and nested - match-state restoration. -- Route each ordinary-pattern family to Joni only after focused and complete - differential gates show zero introductions. +- [ ] Close all remaining PR 958 ordinary-pattern regressions. +- [ ] Prove capture, duplicate-name, branch-reset, region/bounds, zero-width + progression, `\G`, `/g`, `/c`, `/o`, substitution, reuse, and nested + match-state behavior. +- [ ] Prove byte/Unicode pattern and subject variant selection. +- [x] Delete the disconnected production backend selector while preserving its + historical compatibility tests under test scope. -Exit: every semantic assertion passing on Java passes on forced Joni, with JVM -and interpreter agreement. +Exit: every ordinary regex executes in Joni with no baseline regression and +JVM/interpreter agreement. ### Phase 2 — Conditions and backtracking-visible state -- Numbered/named/assertion/recursion/callback conditions and `(DEFINE)`. -- `(*MARK:NAME)`, named `(*SKIP:NAME)`, `(*PRUNE)`, `(*COMMIT)`, `(*THEN)`, - `$REGMARK`, `$REGERROR`, cut boundaries, recursion limits, and unwind. -- Capture-close order, provisional match variables, dynamic locals, and callback - side effects on the selected path. +- [x] Numbered, named, assertion, recursion, callback, and `DEFINE` conditions. +- [x] `(*MARK:NAME)`, named `(*SKIP:NAME)`, `(*PRUNE)`, `(*COMMIT)`, + `(*THEN)`, `(*ACCEPT)`, `(*FAIL)`, `$REGMARK`, and `$REGERROR`. +- [x] Capture publication/clearing, recursion frames, callback unwind, and + destructive-cut boundaries. -Exit: focused Perl oracles and relevant `pat_advanced.t`, `rxcode.t`, and -`reg_eval_scope.t` sections agree. +Exit: focused standard-Perl oracles and affected imported rows agree. ### Phase 3 — Unicode and native pattern syntax -- Add a development generator that reads and analyzes the repository's pinned - Perl 5.44 Unicode tables, then emits checked-in Java source for Joni property - names, loose aliases, value families, ranges, and case-fold metadata. The same - script emits resolver oracle fixtures plus input/output checksums. Generated - Java is reproducible and its second consecutive generation must be diff-free; - hand-written Java is limited to reviewed precedence and behavior that cannot - be derived from the source tables. -- Finish Block, Script, Script_Extensions, General_Category, binary, - compatibility, wildcard, versioned `Age`, POSIX, `\h`/`\H`, and user-property - behavior from pinned Perl 5.44 Unicode data. -- Preserve property-family and user-callback precedence, signed-IV-wide scalar - domains, and byte/Unicode warnings; do not duplicate ICU behavior when the - pinned data or ICU/JCodings already provides it. -- Complete `\N{name}` single/multi/empty atoms, classes, lexical translators, - caching, and exact extended-class diagnostics. -- Complete `/d`, `/u`, `/a`, `/aa`, literal/backreference/class/property case - folding and optimizer search safety. -- Complete Perl escapes, subpattern calls, lookbehind width/255-character rules, - branch-reset lexical targets, `\K`, recursion safety, and invalid-pattern - diagnostics natively in Joni. - -Exit: semantic `regexp_unicode_prop.t`, `pat.t`, and `pat_advanced.t` assertions -complete without masking supported syntax through `JPERL_UNIMPLEMENTED=warn`. +- [x] Generate checked-in Java property, alias, range, named-character, and + case-fold data from the latest `perl5/` tables with provenance and a + diff-free second generation. +- [x] General Category, Script, Block, Script Extensions, POSIX, binary, + compatibility, wildcard, user-property, signed-wide, and fold foundations. +- [x] Native `\N{name}`, extended classes, DEFINE, lookbehind, branch reset, + plain `\N`, recursion, numeric references, false ranges, and subpattern + calls. +- [x] Finish lexical custom-charname cache identity, source byte/Unicode mode, + scoped user-property options, and nested class fold provenance. +- [x] Finish native POSIX grammar, recovery, warning order, and diagnostics. +- [ ] Finish remaining non-POSIX native range/parser diagnostics. +- [ ] Refresh complete Unicode, `pat.t`, and `pat_advanced.t` gates. + +Exit: Unicode and native syntax corpora execute without compatibility masking. ### Phase 4 — Runtime source and diagnostics -- Preserve package, lexical context, warning masks/categories, filename, line, - syntax position, and byte/Unicode identity through literal, runtime, and eval - compilation. -- Complete recursive/nested `(??{...})`, mixed literal/runtime executable - source, tied/localized interpolation, object stringification, and `/g`/`/c`/ - `/o` behavior across callbacks and exceptions. -- Finish native warning collection plus exact Perl wording, markers, - fatal-versus-warning behavior, and source suffixes. -- Close all 555 `pat_re_eval.t` assertions on both execution backends; classify - shared non-regex eval defects separately but fix any that block regex source. +- [x] Runtime callbacks, nested continuations, lexical warning policy, eval + capture lifetime, thread cloning, source spelling, and callback unwind. +- [x] Native numeric, named-character, quantifier, group-name, extended-class, + range, and selected POSIX diagnostics. +- [x] `pat_re_eval.t` semantic contract. +- [ ] Finish all remaining same-source `reg_mesg.t` diagnostic families. +- [x] Finish analyser warning-policy rows. +- [ ] Finish remaining debug-trace rows. +- [ ] Refresh complete `regexp.t`, `reg_mesg.t`, and runtime-source gates. -Exit: runtime-generated regexes and diagnostics agree with standard Perl. +Exit: generated regexes, warnings, fatality, categories, text, and locations +agree with standard Perl on JVM and interpreter. ### Phase 5 — Remove migration scaffolding -- Delete every Java matcher field, route, syntax rewrite, fallback, and the - backend selector. -- Delete matcher-semantic preprocessing after each replacement gate is green. -- Keep only the documented Perl source-policy/frontend layer. -- Remove regex patches introduced by `dev/import-perl5/sync.pl`, then restore - exact upstream files with targeted sync. +- [x] Remove Java matcher storage and production routing. +- [x] Remove native-replaced extended-class, branch-reset, lookbehind, DEFINE, + recursion, numeric-reference, and matcher-semantic adapter rewrites. +- [x] Remove obsolete imported regex patches and prove targeted sync idempotent. +- [ ] Delete remaining matcher-semantic preprocessing, source scanners, and + unreachable adapters after their native gates pass. +- [x] Prove no environment setting can select a production Java matcher. -Exit: Joni is the only production matcher and imported regex tests are -unchanged upstream files. +Exit: Joni is the sole matcher and only documented Perl source policy remains +outside it. ### Phase 6 — Release and documentation -- Run all direct and `_thr.t` regex files on JVM/interpreter and compare the - complete `dev/tools/perl_test_runner.pl` output file-by-file with PR 958. -- Run unchanged Type::Tiny, Regexp::Common, Object::InsideOut, and every CPAN - suite affected by removed regex capability policy. -- Run performance, packaging, notices/licenses, warning-free build, Ubuntu, - Windows, and full CI gates. -- Update `docs/reference/feature-matrix.md`, including the expected-Joni feature - set around lines 390–409 and every currently missing Perl regex feature. -- Rewrite `dev/implementation/regex.md` as the clear as-implemented architecture. -- Update `docs/design/joni-callout-fork.md` for the shipped fork API, packaging, - namespace, callback/unwind contract, and Unicode ownership. -- Delete wholly redundant documents; reduce rationale-bearing older documents - to concise summaries pointing to the canonical implementation documents. - -Exit: all semantic and release gates pass and documentation matches shipped -behavior. +- [ ] Pass immutable complete 622-file JVM acceptance against PR 958. +- [ ] Pass the complete regex-bearing ledger on the interpreter and reconcile + every JVM/interpreter semantic difference. +- [ ] Pass direct/thread parity, bounded `pat_psycho*` and `speed*`, + affected CPAN suites, packaging, notice/license, and warmed performance gates. +- [x] Pass the five-run warmed ordinary-regex comparison: candidate median + 12.23s versus exact-parent 12.68s under alternating contended runs. +- [ ] Pass warning-free `make`, Ubuntu, Windows, and complete CI. +- [ ] Reconcile `docs/reference/feature-matrix.md`, + `dev/implementation/regex.md`, and `docs/design/joni-callout-fork.md` + with shipped behavior. +- [ ] Delete redundant documents; retain only concise rationale summaries that + point to canonical implementation documents. + +Exit: release evidence and public/internal documentation match the code. + +## Current Release Gate + +The current integration source composition ends at `702bb2853`. Its +constituent source tranches are each +warning-free full-build green. Raw property, warning, escaped-class callback, +byte-NEL line break, and word-boundary whitespace coverage pass on JVM and +interpreter. The byte-NEL tranche makes unchanged `regexp.t` 2210/2210 on both +backends. The native word-boundary tranches make `uniprops10.t` +20,070/20,070 on both backends, recovering 1,190 assertions from their exact +parents with no introduced assertion IDs; direct Joni and focused boundary +oracles are green. One exact combined build of this composition is the current +checkpoint barrier. The integrated overload-copy increment correction +passes unchanged `lib/overload_fallback.t` 4/4 on JVM and interpreter, +adjacent overload gates, and a warning-free full build. The preceding exact +combined code barrier `18b9a0133` passes packaging, licensed Joni, all unit +shards, and the shadow JAR. PR 1087 remains the next +incremental release PR; update it only from an exact warning-free integration +head whose complete comparator has no pass-count decrease from PR 958 and no +new invalid, missing, timeout, truncated, incomplete, or zero-TAP row. + +The authoritative 622-file, jobs-5, timeout-300 gate at `d3a4bb074` completed +with 677871/695187 assertions passing and 95 improved rows. Fresh private-tree +isolation found no regex pass decrease: both `pat.t` variants improve by 147 +passing assertions. Plan/platform drift explains four raw decreases; missing +private-import inputs explain two new porting errors. The +`lib/overload_fallback.t` 3/4 decrease is fixed at `cbee747f1`. +`io/socket.t` is environmental rather than a product decrease: the exact +one-file runner outside the restricted sandbox passes 25/25 with zero +errors/timeouts, while the sandbox denies localhost bind and clamps +`SO_SNDBUF` to 816; focused JVM/interpreter option probes outside it both +return 32768. There is no remaining reproduced non-regex pass-count blocker. +The complete runner, comparator, isolation, dossier, 622-file list, reducers, +and verified checksum manifest are +durably retained under +`../PerlOnJava/logs/test_20260821_080900_d3a4bb074_a16_*`; do not repeat the +full corpus merely to rediscover this evidence. + +### Execution Tracker + +- [x] Reproducible PR 958 baseline and strict comparator. +- [x] Conditions, callbacks, control verbs, and backtracking-visible state. +- [x] Runtime regex source, lexical context, callback unwind, and diagnostics. +- [ ] Ordinary-pattern Joni parity: prove the full corpus with native byte and + Unicode matching and no Java matcher fallback. +- [ ] Unicode and pattern syntax: complete nested scoped extended-class + interpolation and remaining corpus-derived roots. +- [x] Production Java matcher/backend selector and legacy `RegexPreprocessor` + are absent; source audit finds only test-scope backend-policy assertions. +- [x] Obsolete imported regex patches are removed and targeted sync is + idempotent. +- [ ] Remove residual temporary source-policy scanners identified by the final + corpus. +- [ ] Complete integration, dual-backend/direct-thread/CPAN/performance gates, + platform CI, documentation reconciliation, and post-merge checks. + +Active ownership: + +- P3: close the ordinary native matcher checklist and implement the largest + remaining disjoint matcher-state root, if any. +- P4: implement the general frontend array-match/substitution compile warning + root that accounts for the missing planned `pat.t`/`pat_thr.t` assertion. +- P5: generate and wire current-Perl InSC/InPC data covering 2,120 residual + assertions; the warn-retirement dossier is complete. +- P6: classify and close the largest remaining native `reg_mesg.t` + Parser/Lexer diagnostic family. +- Coordinator: integration, conflict resolution, immutable acceptance, PR/CI, + plan state, combined build, and release evidence. ## Ordered Next Steps -1. Integrate the native `/xx`, adjacent full-fold partition, and `L_` alias - batch on the exact merged predecessor. Run one warning-free full build plus - zero-introduction `regexp.t` and fold/property gates, then publish a review - PR and require exact-head Ubuntu/Windows CI. -2. Complete recursive and runtime `(??{...})` as native nested Joni execution: - preserve captures, `$^R`, `pos`, modes, byte/Unicode provenance, callback - unwind, backtracking re-evaluation, and recursion safety. Route every embedded - closure to Joni and delete constant inlining, progressive errors, and the - dynamic Java adapter as their gates pass. -3. Complete byte/Unicode pattern provenance through runtime interpolation and - template composition, then finish `/d`/`u`/`a`/`aa` forward/reverse literal, - class, property, and backreference folding from generated data. Require - direct Joni plus ordinary/forced JVM/interpreter zero-introduction gates. -4. Finish the remaining lexical `use re 'strict'`, unescaped-brace, and non-hex - diagnostic families. Refresh complete - `reg_mesg.t`, `pat.t`, and `pat_advanced.t` maps after each combined batch. -5. Repeat the four-leg 80-file Java/Joni × JVM/interpreter matrix on the exact - successor artifact and compare every file with the PR 958 log. Resolve every - regression, zero-TAP record, timeout, truncation, or incomplete file before - user acceptance. -6. Remove each proven-obsolete regex transformation from `dev/import-perl5` - sync sources, regenerate a private unpatched corpus twice, prove byte-for-byte - idempotence, and run the affected upstream tests without editing them. -7. Use the refreshed impact report to move all remaining ordinary constants to - native Joni, deleting their Java routes and matcher-semantic preprocessing in - the same validated slices. Keep `pat_re_eval.t` at 555/555 throughout. -8. Delete Java matching, selector, fallback state, and unreachable preprocessors; - then run direct/thread regex, CPAN, performance, packaging, notice/license, - warning-free build, Ubuntu, Windows, and full CI gates. -9. Update the feature matrix and final as-implemented/fork documents, remove or - summarize redundant design documents, rebase the final stack on `master`, and - run the complete PR 958 parity audit before declaring Phase 36 complete. - -## Parallel Work - -- Coordinator/integration: canonical stack, PR 958 comparison, PR/CI readiness, - plan state, ownership, and conflict resolution. -- Native syntax/matcher: one non-overlapping Joni grammar or matcher feature per - branch with direct fork tests and Perl reducers. -- Unicode: one classified property family per branch from the exact residual - artifact. -- Differential/release: immutable row sets, normalized comparators, fallback - impact ranking, import sync, CPAN and platform gates. -- Documentation: feature inventory and final architecture documents after the - corresponding behavior is validated. - -Workers use isolated worktrees and append-only handoff mailboxes. Assignments -state exact base, owned/excluded files, oracle, complete gates, correction -budget, and delivery evidence. Workers self-monitor CPU and may admit at most -three concurrent expensive jobs globally; timing-sensitive final gates are -serial. Workers normally stop after focused and complete affected-corpus gates -and deliver local commits without pushing. The coordinator batches two to four -non-overlapping deliveries, runs one warning-free full `make` on the combined -head, and only then pushes or updates the PR. A worker-local full build is -reserved for build-system changes or focused evidence of broad cross-suite risk. -`pat_psycho*` and `speed*` may use two CPU-heavy workers, while `pat*`, -`pat_advanced*`, and memory-sensitive fixtures remain one-worker exclusive. -Every `jperl`, `jcpan`, and `prove` process has a hard timeout. +1. Run one exact combined warning-free `make` at the current clean integration + head, including P3 a18 and P6 a35. +2. Refresh focused Unicode, + `regexp.t`, `regex_sets.t`, `charset.t`, `pat.t`, + `pat_advanced.t`, `pat_re_eval.t`, and `reg_mesg.t` gates on that exact + immutable head. +3. Preserve the documented fixture-invalid and sandbox-environment dispositions. + Refresh the comparator evidence for the exact integration + head without repeating the already-retained discovery run. Push a head with no PR-958 + pass-count regression to PR 1087, run CI, and make the incremental PR + reviewable. +4. Continue P4 documentation, P5 generated Indic properties, P6 pat/diagnostic + work, and remaining native Unicode/runtime roots in a new WIP + PR. Repeat focused tests per semantic tranche and one combined build per + integration batch. +5. Delete remaining production migration scaffolding and prove all constants, + closures, conditions, verbs, recursion, dynamic source, byte strings, and + Unicode strings execute through Joni. +6. Run complete JVM/interpreter acceptance, direct/thread parity, affected CPAN + suites, five warmed performance samples, packaging, notices/licenses, + warning-free build, and platform CI. +7. Reconcile final documentation and remove redundant design material. +8. After the final implementation PR is merged to `master`, remove automatic + regex `JPERL_UNIMPLEMENTED=warn` injection from + `dev/tools/perl_test_runner.pl`; rerun the complete corpus; then delete the + RuntimeRegex warning-plus-never-match downgrade and obsolete tests/docs. +9. On final `master`, review shipped behavior against + `pod/perlreref.pod`, `pod/perlrecharclass.pod`, + `pod/perlrequick.pod`, `pod/perlrepository.pod`, `pod/perlre.pod`, + `pod/perlretut.pod`, and `pod/perlrebackslash.pod`. Record every + supported, partial, divergent, and missing capability in + `docs/reference/feature-matrix.md` with evidence. ## Test and Delivery Contract -- Never modify or delete existing tests. Validate every NEW Perl fixture with - system Perl before PerlOnJava. -- Capture complete output in files. Use `perl dev/tools/perl_test_runner.pl`, - never `jperl`, to drive the fork-based core runner. -- Compare JVM and interpreter results, direct and thread wrappers, and forced - backends where the temporary selector still exists. -- A semantic slice needs its focused oracle, direct Joni tests where applicable, - and complete affected corpus with zero introductions. Each combined - integration batch needs one warning-free `make` before push or PR update. -- Preserve original Joni/JCodings notices and verify relocated packaging. -- Never push master. Use focused branches, attributed commits, PRs, and current - master rebases after upstream merges. - -## Performance Gate - -Before deleting Java matching, run five warmed ordinary-pattern measurements on -each backend. Joni median runtime must be within 25% of the Java baseline, add -no timeout, and not materially increase steady-state allocation. Performance -failure blocks backend removal, not semantic fixes. - -## Execution Tracker - -- [x] Phase 0 — reproducible differential baseline -- [ ] Phase 1 — ordinary-pattern Joni parity -- [x] Phase 2 — conditions and backtracking-visible state -- [ ] Phase 3 — Unicode and native pattern syntax -- [ ] Phase 4 — runtime source and diagnostics -- [ ] Phase 5 — remove migration scaffolding -- [ ] Phase 6 — release and documentation - -A checked phase means its focused semantic implementation is complete. Release -gates may reopen it if a semantic regression appears. - -### Active phase detail - -- [x] Pinned Perl Unicode property-data generators and freshness gates -- [x] General Category, Script, Block, POSIX, binary-membership, and signed-wide - property ranges -- [x] Runtime-neutral Joni property-value matcher -- [x] Replace every Java property-wildcard execution site with the Joni matcher -- [x] Parse nested property-value regex syntax in Joni and remove adapter - materialization of the selected ranges -- [x] Complete Hyphen warning/category/source-position diagnostics -- [x] Pinned Perl simple/full/reverse case-fold data -- [x] Native fold adapter and unsafe optimizer-boundary suppression -- [x] Property/class fold closure -- [x] Fold-mode and byte/Unicode provenance context -- [ ] Forward/reverse literal expansion and backreference folding -- [x] Generated Perl named-sequence lookup and native sequence resolution -- [x] Remove temporary named-sequence encoding from native Joni pattern source -- [x] Restore canonical multi-code-point named-sequence extended-class diagnostics -- [x] Restore Perl diagnostics for unknown/empty/malformed named sequences -- [x] Native `(?[...])` with zero diagnostic regressions -- [x] Native `(?(DEFINE)...)` and removal of its adapter rewrite -- [x] Native ordinary lookbehind and removal of its Java translation -- [x] Native branch reset and removal of its capture-map adapter -- [x] Native plain `\N` non-newline atom and interval forms -- [ ] Native recursive/runtime `(??{...})` and removal of dynamic adapters -- [ ] Retire proven-obsolete `dev/import-perl5` regex patches -- [ ] Refresh the complete Unicode, `pat.t`, `pat_advanced.t`, `reg_mesg.t`, and - 80-file forced-Joni gates on one integrated artifact +- Never modify imported or existing tests to make them pass. Add focused + reducers and verify every new unit fixture with system Perl first. +- Every semantic slice needs system-Perl, JVM, interpreter, direct-Joni where + applicable, and complete affected-corpus zero-introduction evidence. +- Use `dev/tools/perl_test_runner.pl` with system `perl`, not `jperl`. +- Compare complete output with the PR 958 baseline; reject missing, invalid, + timeout, truncated, incomplete, or newly zero-TAP records. Preserve and + classify the baseline's platform/skip-only zero-TAP rows separately. +- Give concurrent corpus runs private writable test state. Match the baseline's + concurrency and cleanup for release evidence; label faster variants as + reconnaissance only. +- Run at most three expensive jobs concurrently. Workers self-monitor load; + final timing-sensitive gates are serial. +- Wrap every `jperl`, `jcpan`, and `prove` invocation in `timeout` and + save complete output outside the repository. +- Build only with `make`. Batch two to four deliveries per full build where + risk permits; a worker-local full build is reserved for broad-risk changes. +- Do not push an integration head until its exact `make` is warning-free. +- Keep `perl5/` development-only. A development make rule may clone it when + absent or pull latest upstream when present, then run + `dev/import-perl5/sync.pl`. Sync must include required generated inputs such + as `unicore/Name.pl`, preserve needed non-regex patches, and be idempotent. ## Final Acceptance -- [ ] Every semantic regex test passing in PR 958 still passes. -- [ ] Complete runner output is compared file-by-file with the PR 958 log. -- [ ] JVM/interpreter and direct/thread results agree. -- [ ] Forced Joni covers constants, closures, conditions, control verbs, - recursion, dynamic source, byte strings, and Unicode strings. -- [ ] `pat_psycho*` and `speed*` pass under bounded parallelism. +- [ ] Every semantic row passing in PR 958 still passes. +- [ ] Complete 622-file JVM output is compared file-by-file with PR 958. +- [ ] Complete regex-bearing JVM/interpreter and direct/thread results agree. +- [ ] Joni covers constants, closures, conditions, control verbs, recursion, + dynamic source, byte strings, and Unicode strings. +- [x] `(*MARK:NAME)` and named control-verb state execute in Joni. +- [x] Bounded `pat_psycho*` and `speed*` semantic/performance closure. - [ ] No supported regex test needs `JPERL_UNIMPLEMENTED=warn`. -- [ ] Joni is the sole production matcher; Java routing/selector code is gone. -- [ ] Matcher-semantic preprocessing is gone. -- [ ] Obsolete import patches are removed and targeted sync is idempotent. -- [ ] Feature matrix and final architecture documents match implementation. -- [ ] Original copyright/authorship notices are preserved. -- [ ] Performance, warning-free `make`, packaging, license, Ubuntu, Windows, - and CI gates pass. +- [x] Joni is the sole production matcher; selector compatibility code is + test-scope-only and absent from production packaging. +- [x] Matcher-semantic `RegexPreprocessor` and production Java matcher are gone. +- [x] Obsolete regex import patches are gone. +- [ ] Temporary source-policy scaffolding is gone. +- [x] Targeted latest-upstream sync is reproducible and idempotent. +- [ ] Feature matrix and architecture/fork documents match implementation. +- [ ] Original copyright/authorship/license notices are preserved. +- [ ] Warmed performance, CPAN, packaging, warning-free build, Ubuntu, Windows, + and CI pass. +- [ ] Post-merge warn-mode removal and POD capability review are complete. diff --git a/dev/design/regex_alternatives.md b/dev/design/regex_alternatives.md deleted file mode 100644 index a8fc3c7957..0000000000 --- a/dev/design/regex_alternatives.md +++ /dev/null @@ -1,60 +0,0 @@ -# Open-source regex engines to look at - ---- - -### 1. **PCRE2 (C)** - -* **Closest match to Perl semantics.** - Supports subroutine calls, recursion, verbs, backtracking control, `\K`, `\G`, named captures, etc. -* **Mature and very fast.** - Highly optimized, tested in production everywhere. -* **Drawback:** written in C. You’d either need a JNI bridge (performance overhead + complexity) or port its VM design to Java/bytecode. -* **Good fit if:** you want an authoritative reference for how the opcodes and backtracking model can look. Even just studying PCRE2’s IR and backtracking stack gives you a roadmap. - ---- - -### 2. **Oniguruma / Onigmo (C, Ruby’s regex)** - -* **Used by Ruby.** - Similar richness: subroutines, conditionals, callouts, verb-like constructs. -* **Unicode-aware.** - Strong support for multibyte encodings. -* **Same issue:** C codebase → would require port or JNI. -* **Good fit if:** you want a more modular codebase than PCRE2 and are interested in multi-encoding support. - ---- - -### 3. **RE2 (C++, Google)** - -* **Non-backtracking engine.** - Designed for safety and guaranteed linear time. -* **Not a fit** if your goal is Perl fidelity, since RE2 *intentionally omits* Perl features like backreferences, recursion, or verbs. -* **Good fit if:** you wanted a “safe mode” for sandboxing untrusted regex, but not for Perl emulation. - ---- - -### 4. **Joni (Java, JRuby project)** - -* **Oniguruma port to Java.** - Used by JRuby to give Ruby-like regex semantics on the JVM. -* **Already integrates with JVM.** - No JNI bridge needed; you can inspect and possibly adapt its VM design. -* **Not Perl-complete.** But it’s the closest JVM-side codebase with backtracking and features beyond `java.util.regex`. -* **Good fit if:** you want something you can drop into PerlOnJava as a starting point and then extend toward Perl’s semantics. - ---- - -### 5. **PCRE-J (various Java ports)** - -* Some partial PCRE ports exist in Java, though many are outdated and incomplete. -* **Good fit if:** you find a maintained one, but otherwise riskier than Joni. - ---- - -### Strategy for PerlOnJava - -* **Short term:** leverage Joni. It’s Java, battle-tested (JRuby depends on it), and already has a backtracking model + subroutines. You can embed it, then progressively extend its instruction set to cover Perl-only constructs (`(?{ })`, `(??{ })`, cut verbs). -* **Mid term:** study PCRE2 as the “gold standard” and port the missing instructions (the C VM maps very directly to Java bytecode). -* **Long term:** you’ll probably end up with your own forked/extended VM specialized for PerlOnJava, but you save months of design by standing on Joni/PCRE2 first. - - diff --git a/dev/design/regex_engines.md b/dev/design/regex_engines.md deleted file mode 100644 index 9fef1285a9..0000000000 --- a/dev/design/regex_engines.md +++ /dev/null @@ -1,79 +0,0 @@ -# Strategy for Supporting Multiple Regex Engines in PerlOnJava - -## Overview - -The goal of this document is to outline a strategy for integrating multiple regex engines into the PerlOnJava project. This will allow the system to support different regex engines such as Java's built-in regex, RE2J, and ICU4J, providing flexibility and performance benefits depending on the use case. This document will guide the implementation team through the necessary steps to achieve this integration. - -## Objectives - -1. **Abstract Regex Operations**: Define interfaces that abstract the operations common to all regex engines. -2. **Implement Adapters**: Create adapter classes for each regex engine that implement these interfaces. -3. **Modify Existing Classes**: Update existing classes, such as `RuntimeRegex`, to utilize these interfaces. -4. **Ensure Compatibility**: Maintain compatibility with existing functionality and ensure that the new system is extensible for future regex engines. - -## Architecture - -### 1. Define Interfaces - -We will define two primary interfaces to abstract the regex operations: - -- **RegexPattern Interface**: Represents a compiled regex pattern. - - `RegexMatcher matcher(String input)`: Returns a matcher for the given input string. - -- **RegexMatcher Interface**: Represents the operations that can be performed with a regex pattern. - - `boolean matches()`: Checks if the entire input sequence matches the pattern. - - `String replaceAll(String replacement)`: Replaces every subsequence of the input sequence that matches the pattern with the given replacement string. - -### 2. Implement Adapters - -For each regex engine, implement the `RegexPattern` and `RegexMatcher` interfaces. - -#### Java Regex Adapter - -- **JavaRegexPattern**: Implements `RegexPattern` using Java's `Pattern`. -- **JavaRegexMatcher**: Implements `RegexMatcher` using Java's `Matcher`. - -#### RE2J Adapter - -- **Re2jRegexPattern**: Implements `RegexPattern` using RE2J's `Pattern`. -- **Re2jRegexMatcher**: Implements `RegexMatcher` using RE2J's `Matcher`. - -#### ICU4J Adapter - -- **Icu4jRegexPattern**: Implements `RegexPattern` using ICU4J's regex capabilities. -- **Icu4jRegexMatcher**: Implements `RegexMatcher` using ICU4J's regex capabilities. - -### 3. Modify Existing Classes - -Update the `RuntimeRegex` class to use the new interfaces. This involves: - -- Replacing direct usage of Java's `Pattern` and `Matcher` with `RegexPattern` and `RegexMatcher`. -- Allowing the selection of the regex engine at runtime, possibly through configuration or a factory pattern. - -### 4. Factory Pattern for Engine Selection - -Implement a factory class to manage the creation of `RegexPattern` instances based on the desired regex engine. This factory will: - -- Read configuration settings to determine which regex engine to use. -- Instantiate the appropriate `RegexPattern` adapter. - -### 5. Caching Strategy - -Maintain the existing caching strategy in `RuntimeRegex` to ensure compiled patterns are reused efficiently. Ensure that the cache can handle patterns from different engines without conflict. - -### 6. Testing and Validation - -- **Unit Tests**: Develop comprehensive unit tests for each adapter to ensure they conform to the expected behavior. -- **Integration Tests**: Test the integration of multiple regex engines within the PerlOnJava environment. -- **Performance Testing**: Evaluate the performance of each regex engine to guide users in selecting the appropriate engine for their needs. - -## Implementation Plan - -1. **Define Interfaces**: Create `RegexPattern` and `RegexMatcher` interfaces. -2. **Develop Adapters**: Implement adapters for Java, RE2J, and ICU4J regex engines. -3. **Update RuntimeRegex**: Modify `RuntimeRegex` to use the new interfaces and integrate the factory pattern. -4. **Implement Factory**: Develop a factory class for regex engine selection. -5. **Testing**: Conduct unit, integration, and performance testing. -6. **Documentation**: Update documentation to reflect changes and provide guidance on using different regex engines. - - diff --git a/dev/design/regex_jruby_joni.md b/dev/design/regex_jruby_joni.md deleted file mode 100644 index 5a454292ba..0000000000 --- a/dev/design/regex_jruby_joni.md +++ /dev/null @@ -1,102 +0,0 @@ - -## Migration Plan to Joni Regex - -> **Scope note (2026-08-09):** This is an older broad migration sketch. PR #895 -> implements a narrower backend-neutral matcher and Joni path for declarative -> recursive subpatterns. Executable `(?{ ... })`, callback conditions, and -> `(??{ ... })` require in-match callouts that stock Joni 2.2.7 does not expose. -> See [`executable-regex-callbacks.md`](executable-regex-callbacks.md) for the -> current callback design, semantics, phases, and progress tracking. - -### 1. **Dependencies and Imports** -- Add Joni dependency to the project -- Replace `java.util.regex.Pattern` and `java.util.regex.Matcher` imports with Joni equivalents -- Import Joni's `Regex`, `Matcher`, `Option`, and `Region` classes - -### 2. **Pattern Compilation Changes** -- Replace `Pattern.compile()` with Joni's `new Regex()` constructor -- Convert Java regex flags to Joni Options (e.g., `CASE_INSENSITIVE` → `Option.IGNORECASE`) -- Update the pattern caching mechanism to store Joni Regex objects instead of Pattern objects - -### 3. **Matcher Creation and Usage** -- Replace `pattern.matcher(input)` with Joni's matcher creation approach -- Update matcher method calls: - - `find()` → Joni's `search()` or `match()` methods - - `group()` → Joni's region-based group extraction - - `start()/end()` → Joni's region-based position methods - - `groupCount()` → Joni's capture group handling - -### 4. **Region Handling** -- Implement Joni's Region object for managing match positions -- Adjust the position tracking logic for `\G` assertions and global matches -- Update the `matcher.region()` calls to use Joni's search region specification - -### 5. **Capture Group Management** -- Modify capture group extraction to use Joni's byte-based approach -- Handle the conversion between byte positions and character positions for Unicode strings -- Update the globalMatcher storage to accommodate Joni's matcher structure - -### 6. **Flag Conversion** -- Create a mapping between Perl/Java regex flags and Joni Options -- Update `RegexFlags.toPatternFlags()` to return Joni Option values -- Handle any Joni-specific options that might benefit Perl compatibility - -### 7. **String Encoding Considerations** -- Ensure proper encoding handling (UTF-8/UTF-16) when converting strings to byte arrays for Joni -- Update position calculations to account for multi-byte characters -- Adjust substring operations for capture groups and match positions - -### 8. **Error Handling** -- Update exception handling for Joni-specific exceptions -- Adapt error messages for regex compilation failures - -### 9. **Performance Optimizations** -- Consider reusing byte array conversions where possible -- Optimize the caching mechanism for Joni Regex objects -- Profile and adjust buffer sizes for Joni operations - -### 10. **Testing and Compatibility** -- Ensure all existing regex features work with Joni -- Test Unicode handling improvements -- Verify performance characteristics -- Check for any regex syntax differences between Java and Joni that might affect existing patterns - - -## Using JRuby Strings with Joni - -### 1. **Native Integration** -- Joni was specifically designed for JRuby, so JRuby strings (RubyString) have built-in support for Joni operations -- Direct byte array access without conversion overhead -- Encoding information is already embedded in RubyString - -### 2. **Simplified Position Handling** -- JRuby strings maintain both byte positions and character positions -- Automatic handling of multi-byte character boundaries -- Built-in methods for converting between byte and character indices - -### 3. **Encoding Management** -- RubyString carries encoding information with the string data -- Automatic encoding negotiation for regex operations -- Better support for Perl's encoding semantics - -### 4. **Performance Improvements** -- Eliminate repeated String ↔ byte[] conversions -- Reuse existing byte arrays from RubyString -- Reduce memory allocations during regex operations - -### 5. **Better Perl Compatibility** -- JRuby strings support mutable operations similar to Perl -- Copy-on-write semantics that match Perl's behavior -- Support for binary strings and mixed encodings - -## Additional Considerations - -### Migration Impact -- Would need to update RuntimeScalar to use RubyString internally -- String operations throughout PerlOnJava would benefit from JRuby's string handling -- Could leverage JRuby's existing regex variable implementations ($1, $2, $&, etc.) - -### API Compatibility -- JRuby provides string methods that closely match Perl's string operations -- Could potentially reuse JRuby's regex match data structures -- Simplified implementation of Perl's pos() functionality diff --git a/dev/design/regex_parser_integration.md b/dev/design/regex_parser_integration.md deleted file mode 100644 index 97d81ef2f5..0000000000 --- a/dev/design/regex_parser_integration.md +++ /dev/null @@ -1,303 +0,0 @@ -# Regex Parser Integration Strategy for PerlOnJava - -## Overview - -This document outlines a strategy for integrating an existing, mature regex parser into PerlOnJava to replace the current string-manipulation-based regex preprocessing approach with proper semantic parsing and validation. - -## Current State Analysis - -### Problems with Current Approach - -1. **"Cheating" with hardcoded string matching**: Current validation uses `s.equals()` and `s.contains()` for pattern detection -2. **Fragile preprocessing**: String manipulation approach is error-prone and hard to maintain -3. **Limited semantic understanding**: No proper AST representation of regex structure -4. **Incomplete validation**: Edge cases in backreferences, character classes, and complex constructs -5. **Architectural inconsistency**: Mix of pre-validation and post-processing creates conflicts - -### Current Architecture - -``` -Perl Regex String → RegexPreprocessor → Java-compatible String → Java Pattern - ↓ - String manipulation + hardcoded validation -``` - -## Proposed Integration Strategy - -### Phase 1: ANTLR-based PCRE Parser Integration - -#### Recommended Parser: bkiers/pcre-parser - -- **Repository**: https://github.com/bkiers/pcre-parser -- **Technology**: ANTLR 4 grammar for PCRE (Perl Compatible Regular Expressions) -- **License**: MIT (compatible with PerlOnJava) -- **Maturity**: Active project with comprehensive PCRE support - -#### Integration Architecture - -``` -Perl Regex String → PCRE Parser → AST → Semantic Validator → AST Transformer → Java Pattern - ↓ ↓ ↓ ↓ - ANTLR 4 Tree Proper validation Java-compatible AST -``` - -### Phase 2: Implementation Plan - -#### Step 1: Dependency Integration - -Add ANTLR PCRE parser dependency to `build.gradle`: - -```gradle -dependencies { - implementation 'nl.bigo:pcre-parser:1.0.0' // Version TBD - implementation 'org.antlr:antlr4-runtime:4.9.3' -} -``` - -#### Step 2: Core Integration Classes - -1. **EnhancedRegexPreprocessor**: Main entry point -2. **RegexASTValidator**: Semantic validation using AST -3. **RegexASTTransformer**: Transform Perl AST to Java-compatible form -4. **RegexErrorReporter**: Convert ANTLR errors to PerlCompilerException - -#### Step 3: Fallback Strategy - -Maintain current preprocessing as fallback for: -- Parser failures -- Unsupported constructs -- Performance-critical paths (if needed) - -### Phase 3: Detailed Implementation - -#### Core Classes Structure - -```java -public class EnhancedRegexPreprocessor { - public static String preProcessRegex(String regex, RegexFlags flags) { - try { - // Parse regex into AST - ParseTree ast = parseRegex(regex); - - // Semantic validation - validateRegexAST(ast, flags); - - // Transform for Java compatibility - return transformAST(ast, flags); - - } catch (RegexParseException e) { - // Fallback to current approach - return RegexPreprocessor.preProcessRegex(regex, flags); - } - } - - private static ParseTree parseRegex(String regex) throws RegexParseException { - PCRELexer lexer = new PCRELexer(CharStreams.fromString(regex)); - PCREParser parser = new PCREParser(new CommonTokenStream(lexer)); - - // Configure error handling - parser.removeErrorListeners(); - parser.addErrorListener(new RegexErrorListener()); - - return parser.pcre(); - } -} -``` - -#### Semantic Validation - -```java -public class RegexASTValidator extends PCREBaseVisitor { - private int captureGroupCount = 0; - private Set namedGroups = new HashSet<>(); - private RegexFlags flags; - - public void validate(ParseTree tree, RegexFlags flags) { - this.flags = flags; - visit(tree); - } - - @Override - public Void visitBackreference(BackreferenceContext ctx) { - int groupNum = Integer.parseInt(ctx.NUMBER().getText()); - if (groupNum > captureGroupCount) { - throw new PerlCompilerException("Reference to nonexistent group"); - } - return super.visitBackreference(ctx); - } - - @Override - public Void visitNamedBackreference(NamedBackreferenceContext ctx) { - String groupName = ctx.NAME().getText(); - if (!namedGroups.contains(groupName)) { - throw new PerlCompilerException("Reference to nonexistent named group"); - } - return super.visitNamedBackreference(ctx); - } -} -``` - -#### AST Transformation - -```java -public class RegexASTTransformer extends PCREBaseVisitor { - private StringBuilder result = new StringBuilder(); - private RegexFlags flags; - - public String transform(ParseTree tree, RegexFlags flags) { - this.flags = flags; - visit(tree); - return result.toString(); - } - - @Override - public String visitCharacterClass(CharacterClassContext ctx) { - // Transform Perl character class to Java equivalent - // Handle POSIX classes, Unicode properties, etc. - return super.visitCharacterClass(ctx); - } - - @Override - public String visitQuantifier(QuantifierContext ctx) { - // Handle possessive quantifiers, etc. - return super.visitQuantifier(ctx); - } -} -``` - -## Benefits of Integration - -### 1. Architectural Improvements - -- **Clean separation**: Parsing, validation, and transformation as distinct phases -- **Semantic understanding**: True AST-based processing instead of string manipulation -- **Extensibility**: Easy to add new Perl regex features -- **Maintainability**: Grammar-based approach is self-documenting - -### 2. Validation Improvements - -- **Proper backreference validation**: Check against actual capture group structure -- **Character class validation**: Parse and validate character classes semantically -- **Quantifier validation**: Understand quantifier context and nesting -- **Named group validation**: Track and validate named capture groups - -### 3. Error Reporting - -- **Precise error locations**: ANTLR provides exact position information -- **Semantic error messages**: Context-aware error reporting -- **Perl-compatible messages**: Transform ANTLR errors to Perl-style messages - -## Migration Strategy - -### Phase A: Parallel Implementation (Low Risk) - -1. Implement enhanced preprocessor alongside current one -2. Add feature flag to enable/disable new parser -3. Run both parsers in test suite, compare results -4. Gradually enable for specific regex patterns - -### Phase B: Gradual Replacement (Medium Risk) - -1. Replace preprocessing for simple patterns first -2. Use fallback for complex patterns initially -3. Expand coverage as confidence grows -4. Monitor performance and correctness - -### Phase C: Full Migration (High Confidence) - -1. Make enhanced preprocessor the default -2. Keep current preprocessor as emergency fallback -3. Remove fallback after extensive testing -4. Clean up deprecated code - -## Performance Considerations - -### Potential Concerns - -1. **Parsing overhead**: ANTLR parsing may be slower than string manipulation -2. **Memory usage**: AST creation requires additional memory -3. **Startup time**: ANTLR parser initialization cost - -### Mitigation Strategies - -1. **Caching**: Cache parsed ASTs for frequently used patterns -2. **Lazy initialization**: Initialize parser only when needed -3. **Pattern analysis**: Use fast path for simple patterns -4. **Benchmarking**: Measure and optimize critical paths - -## Testing Strategy - -### Unit Tests - -1. **Parser integration tests**: Verify ANTLR parser works correctly -2. **Validation tests**: Test semantic validation logic -3. **Transformation tests**: Verify AST transformation correctness -4. **Error handling tests**: Test error reporting and fallback - -### Integration Tests - -1. **Regex test suite**: Run existing `t/re/regexp.t` with new parser -2. **Performance tests**: Compare performance with current approach -3. **Compatibility tests**: Ensure Perl compatibility maintained - -### Regression Tests - -1. **Fallback tests**: Verify fallback mechanism works -2. **Edge case tests**: Test complex regex patterns -3. **Error message tests**: Verify error message compatibility - -## Implementation Timeline - -### Week 1-2: Research and Setup -- Evaluate ANTLR PCRE parser options -- Set up build integration -- Create basic integration framework - -### Week 3-4: Core Implementation -- Implement EnhancedRegexPreprocessor -- Basic AST validation and transformation -- Fallback mechanism - -### Week 5-6: Testing and Refinement -- Comprehensive test suite -- Performance optimization -- Error handling improvements - -### Week 7-8: Integration and Deployment -- Gradual rollout with feature flags -- Monitor test results and performance -- Documentation and cleanup - -## Alternative Approaches Considered - -### 1. Custom Regex Parser - -**Pros**: Full control, optimized for PerlOnJava needs -**Cons**: Significant development effort, maintenance burden - -### 2. Perl Regex Engine Integration (JNI) - -**Pros**: Perfect Perl compatibility -**Cons**: JNI complexity, deployment challenges, performance overhead - -### 3. Regex Engine Libraries (RE2, etc.) - -**Pros**: High performance, proven reliability -**Cons**: Limited Perl compatibility, different semantics - -## Conclusion - -Integrating an ANTLR-based PCRE parser represents the best balance of: -- **Architectural cleanliness**: Proper separation of concerns -- **Implementation effort**: Leverage existing, mature parser -- **Perl compatibility**: PCRE provides good Perl regex coverage -- **Maintainability**: Grammar-based approach is sustainable - -This approach eliminates the "cheating" problem by providing true semantic understanding of regex patterns while maintaining compatibility and performance. - -## References - -- [bkiers/pcre-parser](https://github.com/bkiers/pcre-parser) - ANTLR 4 PCRE Parser -- [ANTLR 4 Documentation](https://github.com/antlr/antlr4/blob/master/doc/index.md) -- [PCRE Specification](https://www.pcre.org/current/doc/html/pcre2syntax.html) -- [Perl Regular Expressions](https://perldoc.perl.org/perlre) diff --git a/dev/design/regex_preprocessing_fixes.md b/dev/design/regex_preprocessing_fixes.md deleted file mode 100644 index a93c7f0a7b..0000000000 --- a/dev/design/regex_preprocessing_fixes.md +++ /dev/null @@ -1,282 +0,0 @@ -# Regex Preprocessing Fixes - -## Overview - -This document tracks regex preprocessing issues discovered while running `re/pat.t`, `re/pat_advanced.t`, and related tests with `JPERL_UNIMPLEMENTED=warn`. - -## Completed Fixes - -### 1. Invalid quantifier brace handling consuming regex metacharacters - -**Root cause:** `handleQuantifier()` in `RegexPreprocessor.java` used `s.indexOf('}', start)` to find the closing brace of a potential quantifier, but this search crossed character class boundaries and regex groups. For example, in `{ (?> [^{}]+ | (??{...}) )* }`, the `{` at the start was treated as a potential quantifier, and `indexOf('}')` found the `}` inside the character class `[^{}]`, consuming everything in between (including `(?>` and `[^{`) as literal text. - -**Fix:** When `handleQuantifier` determines that braces don't form a valid quantifier (content contains non-numeric characters), it now only escapes the opening `{` as `\{` and returns immediately, letting the main regex loop process subsequent characters normally. Previously it consumed and escaped the entire `{...}` range. - -**Files changed:** `RegexPreprocessor.java` — `handleQuantifier()` method - -### 2. `\x{...}` hex escape with non-hex characters - -**Root cause:** The hex escape handler used `Integer.parseInt(hexStr, 16)` which throws `NumberFormatException` for strings containing non-hex characters (e.g., `\x{9bq}`). Inside character classes, this was caught and re-thrown as a fatal `PerlCompilerException`, killing the test run. Outside character classes, the escape was passed through to Java's regex engine which also rejected it. - -**Perl behavior:** `\x{9bq}` extracts the valid hex prefix `9b` (value 0x9B) and ignores the remaining characters. `\x{x9b}` has no valid prefix, so the value is 0. Underscores are allowed (removed by preprocessing) but other non-hex chars terminate the hex number. - -**Fix:** All three `\x{...}` handlers now extract the valid hex prefix instead of requiring the entire content to be valid hex: -- `handleRegexCharacterClassEscape()` — inside `[...]` (was the fatal crash) -- `handleEscapeSequences()` — outside `[...]` -- Range endpoint parser — for character class ranges - -**Files changed:** `RegexPreprocessorHelper.java` - -### 3. Bare `\xNN` with non-hex characters - -**Root cause:** Bare `\x` (without braces) was passed through to Java's regex engine, which expects exactly 2 hex digits after `\x`. Patterns like `\xk` or `\x4j` caused `PatternSyntaxException`. - -**Perl behavior:** `\x` takes up to 2 hex digits. `\xk` = `\x00` followed by literal `k`. `\x4j` = `\x04` followed by literal `j`. - -**Fix:** Added explicit bare `\x` handling that parses up to 2 hex digits and emits `\x{HH}` format when fewer than 2 valid hex digits are found. - -**Files changed:** `RegexPreprocessorHelper.java` — `handleEscapeSequences()` method - -### 4. NullPointerException when regex fails with JPERL_UNIMPLEMENTED=warn - -**Root cause:** When regex compilation fails and gets downgraded to a warning, the catch block in `RuntimeRegex.compile()` set the error pattern but didn't set `regex.patternString`. Downstream code (e.g., `replaceRegex()`) checked `regex.patternString == null` and triggered recompilation with a null pattern, causing NPE in `convertPythonStyleGroups(null).replaceAll(...)`. - -**Fix:** -1. Set `regex.patternString` in the catch block when downgrading to warning -2. Added null guard in `preProcessRegex()` to treat null input as empty string - -**Files changed:** `RuntimeRegex.java`, `RegexPreprocessor.java` - -## Known Remaining Issues - -### Test Pass Rates (after all fixes) - -| Test | Before fixes | After fixes | Remaining failures | -|------|-------------|-------------|-------------------| -| `re/pat.t` | 428/1298 | **1077**/1298 (all run) | 221 fail | -| `re/pat_advanced.t` | 63/1298 | **1308**/1625 | 317 fail + 53 not reached | -| `re/pat_rt_report.t` | 2397/2515 | **2431**/2515 (ran 2508) | 77 fail + 7 not reached | -| `re/regexp_unicode_prop.t` | — | **1017**/1096 | 79 fail + 14 not reached | -| `re/reg_eval_scope.t` | 6/49 | 7/49 | 42 fail | -| `uni/variables.t` | 66880/66880 | 66880/66880 | 0 | - -### Early Termination (crashes blocking remaining tests) - -| Test | Crash point | Cause | Tests blocked | -|------|------------|-------|---------------| -| pat.t | **No crash** — all 1298 tests now run | N/A | 0 | -| pat_advanced.t | Line 2308 (test 1625) | `\p{Is_q}` — package-scoped user property (`Some::Is_q`) | 53 tests | -| pat_rt_report.t | Line 1158 (test 2508) | `(?1)` — numbered group recursion not supported | 7 tests | -| regexp_unicode_prop.t | Line 543 (test 1096) | `\pf`/`\Pf` invalid property generates warnings instead of errors | 14 tests | - -### Failure Categories - -#### A. `\G` anchor (26 failures in pat.t) - -The `\G` assertion (match at pos()) has significant issues: -- **Floating `\G`** patterns like `/a+\G/` fail — Java doesn't support `\G` except at pattern start -- **`\G` in loops** (`/\G.../gc` iteration) doesn't maintain position correctly -- Tests: pat.t 455-518 - -**Difficulty: Medium-High.** Requires custom `\G` tracking in the match engine; Java's `\G` only works at the start of a match attempt. - -#### B. `(?{...})` code blocks (36 failures in pat.t, 5 in pat_advanced.t, 5 in pat_rt_report.t) - -Regex embedded code blocks are replaced with no-op groups. This breaks: -- **`$^R`** — result of last `(?{...})` (tests 308-310) -- **`pos()` inside `(?{...})`** (tests 470-494) -- **Package/lexical variable access** inside `(?{...})` (tests 522-525) -- **Eval-group runtime checks** — "Eval-group not allowed at runtime" (tests 300-304) - -**Difficulty: Very High.** Would require integrating the Perl compiler into the regex engine to execute code at match time. - -#### C. `$^N` — last successful capture (20 failures in pat_advanced.t) - -`$^N` is not updated after successful group captures. Tests 69-88 all fail. -- Both outside regex and inside `(?{...})` usage fails -- `$^N` is automatically localized — not implemented - -**Difficulty: Medium.** Requires tracking the last successfully matched group in the match result. - -#### D. `(??{...})` recursive patterns (5 failures in pat.t) - -Non-constant recursive patterns are replaced with empty groups. Tests 293-297 (complicated backtracking, recursion with `(??{})`) all fail. - -**Difficulty: Very High.** Same as `(?{...})` — requires runtime code execution. - -#### E. `(*ACCEPT)`, `(*FAIL)` control verbs (5 failures in pat.t) - -Regex control verbs are not supported by Java's regex engine. Tests 357-373 (ACCEPT and CLOSE buffer tests). - -**Difficulty: High.** Would require a custom regex engine or post-processing layer. - -#### F. `@-` / `@+` / `@{^CAPTURE}` arrays (12 failures in pat.t, 5 in pat_rt_report.t) - -The match position arrays have bugs: -- **Wrong values** for capture group positions (tests 381-438) -- **Stale values** not cleared after new match (tests 439-441) -- **Read-only protection** throws wrong exception type: `UnsupportedOperationException` instead of `Modification of a read-only value attempted` (test 449) -- **Interpolation in patterns** — `@-` and `@+` should not be interpolated (pat_rt_report.t 151-154) -- **Undefined values** in `@-`/`@+` after match (pat_rt_report.t 213) - -**Difficulty: Medium.** The data is available from Java's `Matcher`; needs more careful mapping to Perl semantics. - -#### G. `qr//` stringification and modifiers (4 failures in pat.t) - -- `qr/\b\v$/xism` stringifies as `(?^imsx:\b\v$)` but should be `(?^msix:\\b\\v$)` — backslashes not escaped in stringification (test 315) -- **`/u` modifier** not tracked: `use feature 'unicode_strings'` should add `/u` flag (tests 323-327) - -**Difficulty: Low-Medium.** Stringification fix is straightforward; `/u` modifier tracking needs scope awareness. - -#### H. `\N{name}` charnames (25 failures in pat_advanced.t) - -Named character escapes have extensive issues: -- **Empty `\N{}`** not handled correctly (tests 794-809) -- **`\N{PLUS SIGN}`** — named characters not expanded in regex (tests 831-833) -- **`\N{U+0041}`** in character class — `[\N{SPACE}\N{U+0041}]` fails (test 836) -- **Charname validation** — leading digit, comma, latin1 symbol errors not produced (tests 821-828) -- **Charname caching** with `$1` — not implemented (tests 798-801) -- **Cedilla/NO-BREAK SPACE** in names — error handling missing (tests 816-819) - -**Difficulty: Medium-High.** `\N{U+XXXX}` is partially implemented; full charnames support needs the `charnames` module. - -#### I. Useless `(?c)` / `(?g)` / `(?o)` warnings (13 failures in pat_advanced.t) - -Perl warns about useless regex modifiers (`/c`, `/g`, `/o` are match-operator flags, not regex flags). PerlOnJava silently ignores them without producing warnings. - -**Difficulty: Low.** Add warning emission in the regex flag parser. - -#### J. Bare `\x` hex escape edge cases (5 failures in pat_advanced.t) - -Our fix handles the crash but the test strings don't match correctly: -- `\x4j` produces `\004j` but regex `[\x4j]{2}` doesn't match it (test 101) -- `\xk` produces `\000k` but regex `[\xk]{2}` doesn't match it (test 102) -- `\xx`, `\xxa`, `\x9_b` — regex character class expansion doesn't match the test string (tests 103-105) - -The issue is that the test string and the regex pattern both use `\x` escapes, but the regex preprocessor and the string processor handle them differently. The test expects both to produce the same character. - -**Difficulty: Low-Medium.** The regex-side `\x` handling needs to produce character classes that match what the string-side produces. - -#### K. Conditional `(?(1)...)` with `$` anchor — Bug 41010 (48 failures in pat_rt_report.t) - -The largest single failure category. Patterns like `/([ ]*$)(?(1))/` don't match correctly. This is a systematic issue with conditionals referencing a group that ends with `$` anchor. - -**Difficulty: Medium.** Likely a subtle difference in how Java handles the interaction between `$` anchor in a group and conditional backreference. - -#### L. `$REGMARK` / `${^PREMATCH}` etc. (6 failures in pat_rt_report.t) - -`$REGMARK` (set by `(*MARK:name)`) is not implemented. Tests 2458-2463. - -**Difficulty: High.** Requires `(*MARK)` verb support. - -#### M. `(?1)` numbered group recursion / `(?&name)` named recursion (pat_advanced.t, pat_rt_report.t) - -`(?1)` and `(?&name)` syntax for recursing into capture groups is not recognized. Now downgradable with `JPERL_UNIMPLEMENTED=warn` (no longer crashes tests), but the patterns silently fail to match. - -**Difficulty: Very High.** Java's regex engine has no recursion support. Would need a custom engine or PCRE/JNI bridge. - -#### N. `\p{isAlpha}` POSIX-style Unicode property (crash in pat.t) - -The POSIX-style Unicode property syntax `\p{isAlpha}`, `\p{isSpace}` is not recognized. This causes the fatal error that stops pat.t at line 1247, blocking 666 remaining tests. - -**Difficulty: Low-Medium.** Map POSIX-style aliases (`isAlpha` → `Alpha`, `isSpace` → `Space`, etc.) in the Unicode property handler. - -#### O. Empty clause in alternation (3 failures in pat.t) - -Empty alternatives in patterns like `/(|a)/` or the "0 match in alternation" test don't work correctly. - -**Difficulty: Low-Medium.** Likely a regex preprocessing issue. - -#### P. Miscellaneous (small counts) - -| Issue | Tests | Difficulty | -|-------|-------|-----------| -| Look around edge cases | pat.t 332-333 | Medium | -| REG_INFTY (quantifier limit) | pat.t 250 | Low | -| POSIX class error message format | pat.t 348 | Low | -| Lookbehind limit (Java) | pat.t 252 | Hard (engine limit) | -| Empty pattern pmop flags | pat_rt_report.t 44 | Medium | -| Nested split | pat_rt_report.t 85 | Medium | -| Ill-formed UTF-8 in class | pat_rt_report.t 140 | Medium | -| Pattern in loop (prev success) | pat_rt_report.t 2469-2470 | Medium | -| Long string patterns | pat_advanced.t 805-813 | Medium | -| `/d` to `/u` modifier change | pat_advanced.t 807-808 | Low-Medium | - -#### Q. Package-scoped user-defined Unicode properties (crash in pat_advanced.t) - -`\p{Is_q}` defined in package `Some` as `Some::Is_q` is not found because user-defined property lookup only checks `main::` package. Perl uses the current package when resolving `\p{...}` names. This crashes pat_advanced.t at line 2308 (test 1625), blocking 53 tests. - -**Difficulty: Medium.** Need to pass the current package context to the regex preprocessor and try the current package before falling back to `main::`. - -#### R. Invalid single-char `\pX`/`\PX` properties (crash in regexp_unicode_prop.t) - -Invalid single-character properties like `\pf`, `\Pq` are passed through to Java's regex engine which throws `PatternSyntaxException`. This is caught and wrapped as `PerlJavaUnimplementedException`, which under `JPERL_UNIMPLEMENTED=warn` generates warnings instead of proper errors. Test 1096 in regexp_unicode_prop.t expects 0 warnings but gets 8 (from `\pf`, `\Pf`, `\pq`, `\Pq`), then crashes. - -**Fix approach:** Validate single-char properties in the preprocessor (only `\pL`, `\pM`, `\pN`, etc. are valid — single Unicode general category letters). Invalid ones should throw `PerlCompilerException` (not `PerlJavaUnimplementedException`). - -**Difficulty: Low.** Add validation for single-char `\p`/`\P` properties in `RegexPreprocessorHelper`. - -#### S. `/i` flag not passed to user-defined property subs (regexp_unicode_prop.t) - -Perl calls user-defined property subs with `$caseless=1` when the `/i` flag is active, allowing subs to return a wider character set for case-insensitive matching. PerlOnJava always calls the sub with an empty argument list. This causes 2 test failures in regexp_unicode_prop.t (tests 1061, 1077) and several in pat_advanced.t. - -**Fix approach:** Pass the `/i` flag through the regex preprocessor to `tryUserDefinedProperty`, which then passes `1` as the first argument to the property sub. - -**Difficulty: Medium.** Requires threading the case-insensitive flag through several method calls in the regex preprocessing pipeline. - -### Priority Recommendations - -**Quick wins (Low difficulty, high impact):** -1. ~~**`\p{isAlpha}` aliases** — unblocks 666 pat.t tests (category N)~~ **DONE** — pat.t now runs all 1298 tests -2. **Invalid `\pX` single-char properties** — unblocks 14 regexp_unicode_prop.t tests (category R) -3. **Useless `(?c)`/`(?g)`/`(?o)` warnings** — fixes 13 pat_advanced.t tests (category I) -4. **POSIX class error message** — fix message format (category P) -5. **REG_INFTY error** — add quantifier limit check (category P) - -**Medium effort, significant impact:** -6. **Package-scoped user properties** — unblocks 53 pat_advanced.t tests (category Q) -7. **`/i` caseless flag for user properties** — fixes ~4 tests (category S) -8. **`(?(1)...)` with `$` anchor** — fixes 48 pat_rt_report.t tests (category K) -9. **`@-`/`@+` position arrays** — fixes 17 tests across files (category F) -10. **`$^N` last capture** — fixes 20 pat_advanced.t tests (category C) -11. **Bare `\x` edge cases** — fixes 5 pat_advanced.t tests (category J) -12. **`\N{name}` charnames** — fixes 25 pat_advanced.t tests (category H) - -**Hard / architectural (major work):** -13. **`\G` anchor** — 26 pat.t tests (category A) -14. **`(?{...})` code blocks** — 46 tests total (category B) -15. **`(?1)` recursion / `(?&name)` / `(*ACCEPT)` / `(*MARK)`** — engine limitations (categories E, L, M) - -## Progress Tracking - -### Current Status: Major user-defined property and regex cache fixes (2026-04-10) - -### Completed -- [x] Fix 1: handleQuantifier brace consumption (2026-04-10) -- [x] Fix 2: \x{...} hex escape with non-hex chars (2026-04-10) -- [x] Fix 3: Bare \xNN with non-hex chars (2026-04-10) -- [x] Fix 4: NPE on failed regex with JPERL_UNIMPLEMENTED=warn (2026-04-10) -- [x] Failure analysis and categorization (2026-04-10) -- [x] Fix 5: \p{isAlpha} case-insensitive Is prefix, add Space/Alnum/Punct aliases (2026-04-10) -- [x] Fix 6: \p{Property=Value} syntax (2026-04-10) -- [x] Fix 7: Named capture groups with underscores — U95 encoding (2026-04-10) -- [x] Fix 8: User-defined property resolution — refactor resolvePropertyReference to return UnicodeSet (2026-04-10) - - Properties using +utf8:: references (e.g., +utf8::Uppercase, &utf8::ASCII) were failing because - the old code returned Java regex patterns that ICU4J's UnicodeSet couldn't parse - - Created resolvePropertyReferenceAsSet() and resolveStandardPropertyAsSet() methods -- [x] Fix 9: Regex cache preventing deferred recompilation (2026-04-10) - - ensureCompiledForRuntime() now evicts stale cache entries before recompiling -- [x] Fix 10: Cache user-defined property sub results (2026-04-10) - - Matches Perl behavior of calling each property sub only once - - Fixes "Called twice" errors from subs with `state` variables -- [x] Fix 11: Titlecase/TitlecaseLetter/Lt property aliases (2026-04-10) -- [x] Fix 12: (?&name) named group recursion downgraded to regexUnimplemented (2026-04-10) -- [x] Fix 13: (?digit) numbered recursion downgraded to regexUnimplemented (2026-04-10) - -### Files Modified -- `src/main/java/org/perlonjava/runtime/regex/RegexPreprocessor.java` -- `src/main/java/org/perlonjava/runtime/regex/RegexPreprocessorHelper.java` -- `src/main/java/org/perlonjava/runtime/regex/RuntimeRegex.java` -- `src/main/java/org/perlonjava/runtime/regex/UnicodeResolver.java` -- `src/main/java/org/perlonjava/runtime/regex/CaptureNameEncoder.java` -- `src/main/java/org/perlonjava/runtime/runtimetypes/HashSpecialVariable.java` diff --git a/dev/design/test_pass_rate_improvement_plan.md b/dev/design/test_pass_rate_improvement_plan.md index 8290a5f734..70d8d84510 100644 --- a/dev/design/test_pass_rate_improvement_plan.md +++ b/dev/design/test_pass_rate_improvement_plan.md @@ -2,7 +2,11 @@ > **Historical document (superseded).** Counts and priorities below are a > point-in-time planning snapshot. Use the current test reports, roadmap, and -> feature matrix when choosing new compatibility work. +> feature matrix when choosing new compatibility work. This plan predates the +> Phase 36 Joni cutover: references below to Java `Pattern`, Java-first matching, +> or `RegexPreprocessor` describe the retired implementation. See +> `dev/design/phase36-regex-parity.md` and `docs/reference/feature-matrix.md` for +> the current architecture. **Date:** 2025-03-31 **Branch:** fix/sregex-args-propagation diff --git a/dev/implementation/regex.md b/dev/implementation/regex.md index 9f0317c910..7ad23fffad 100644 --- a/dev/implementation/regex.md +++ b/dev/implementation/regex.md @@ -1,147 +1,232 @@ # Regex implementation -## Scope and target - -PerlOnJava maintains a source fork of Joni as its Perl-compatible regex engine. -The target architecture has one production matcher: Joni owns parsing, -backtracking, captures, conditions, recursion, control verbs, Unicode matching, -case folding, and matcher-visible callbacks. PerlOnJava owns Perl source policy, -runtime integration, lexical warnings, diagnostics, and callback closures. - -Migration is not complete. Automatic routing uses Joni for ordinary patterns. -Setting `JPERL_REGEX_BACKEND=java` or the `jperl.regex.backend=java` system -property retains the legacy matcher solely as a differential baseline; explicit -`joni` selects the production route. The Java matcher, selector, and Java-only -rewrites are temporary migration scaffolding. - -## Compilation and routing - -`RuntimeRegex` compiles Perl regex values and keeps byte-string and Unicode -variants where subject provenance can affect semantics. `RegexBackendPolicy` -selects the temporary Java route or Joni. `JoniRegexPattern` converts only the -remaining frontend-owned representations, builds the PerlOnJava Joni syntax, -and compiles the vendored engine. - -Patterns requiring matcher semantics unavailable in Java select Joni. These -include subpattern calls, recursion, Perl conditions, structured executable or -dynamic callbacks, control verbs, ASCII-strict folding, and native named -character sequences. Embedded closures select Joni even when their result is -constant because execution and unwind remain observable at match time. - -The matcher exposes the same `RegexMatcher` interface to JVM-compiled and -interpreter execution. Match, substitution, `/g`, `/c`, `pos`, captures, and -match variables are coordinated by `RuntimeRegex`; backend-specific offsets are -converted to Perl character positions at that boundary. - -## Vendored Joni fork - -Production Joni sources live in `third_party/joni` under their original -`org.joni` namespace. The root build compiles the fork and its upstream tests as -dedicated source sets. Packaging relocates Joni to +## Runtime boundary + +PerlOnJava has one production regex engine: the maintained Joni fork in +`third_party/joni`. `RuntimeRegex` is the Perl runtime boundary and +`JoniRegexPattern` is the only adapter that constructs a matcher. The JVM and +bytecode-interpreter execution backends call this same runtime code; neither has +its own regex implementation. + +`JPERL_REGEX_BACKEND` and `jperl.regex.backend` do not select a production +matcher. The production `RegexBackendPolicy` class has been removed; a +test-scope-only model preserves the immutable migration assertions and cannot +enter the standalone artifact. Likewise, +`JoniRegexPattern.compatibilityPatternDescription` is a display-only +normalization for legacy assertions and debug descriptions. The raw +`sourcePattern` is what Joni compiles and what source diagnostics describe. + +This separation is the central maintenance rule: + +- PerlOnJava owns source provenance, lexical policy, runtime state, and Perl + callbacks. +- Joni owns matcher-visible grammar and behavior. +- Compatibility descriptions must never become matcher input. + +## Responsibility map + +| Responsibility | Production classes | +| --- | --- | +| Parse literal/interpolated regex source and capture executable closures | `StringSegmentParser`, `RegexLiteralAnalyzer` | +| Preserve trusted callback provenance while assembling interpolated patterns | `RuntimeRegexTemplate`, `RuntimeRegexCallback` | +| Compile runtime source admitted by `use re 'eval'` in its Perl lexical context | `RuntimeRegexSourceCompiler` | +| Cache compiled variants and implement Perl-visible match/substitution state | `RuntimeRegex`, `RegexFlags` | +| Adapt encoding, diagnostics, resolver hooks, callbacks, and Joni match results | `JoniRegexPattern` and its `JoniRegexMatcher` / `PerlCalloutHandler` nested classes | +| Resolve Perl Unicode properties and names with pinned-data precedence | `UnicodeResolver`, `NamedCharacterExpansion`, `PerlUnicode*Data` | +| Parse and execute matcher semantics without Perl runtime dependencies | `org.joni.Regex`, `Parser`, `Analyser`, `ArrayCompiler`, `ByteCodeMachine` | +| Expose runtime-neutral host hooks | `CalloutHandler`, `MatchView`, `DynamicPatternResult`, `CharacterPropertyResolver`, `NamedCharacterResolver`, `PerlPropertyValueMatcher`, `WideScalarCodec` | + +## From Perl source to a compiled pattern + +`StringSegmentParser` distinguishes literal source, interpolation, and +parser-created executable blocks. It emits `regexCallback` nodes inside a +`regexTemplate`; JVM lowering and interpreter lowering preserve the same node +contract. + +`RuntimeRegexTemplate` assembles the runtime value. Only parser-created callback +wrappers allocate entries in the callback table. They are represented by +private slot sentinels, not by matcher syntax; sentinel starts in interpolated +text are doubled, so untrusted text cannot acquire callback provenance. +Embedding a callback-bearing `qr//` validates and renumbers its slots. +`maskCallouts()` hides trusted slots while runtime Perl source is parsed, and +`materializeTrustedCallouts()` turns only validated, in-range slots into Joni +tokens immediately before compilation. `trustedCalloutCount` supplies the +second bounds check. A lone interpolated `qr//` retains its compiled identity, +preserving its flags, callbacks, and overload behavior. + +`RuntimeRegexSourceCompiler` handles executable regex source admitted by +`use re 'eval'`. It compiles with the construction site's package, lexical +cells, hints, warning bits, byte provenance, and operation flags, using a fresh +synthetic `(eval N)` filename at line 1. Dynamic source is therefore checked as +Perl source before it becomes a Joni program; it is not evaluated by the regex +engine. + +`RuntimeRegex.compileSynchronized()` performs the remaining Perl-side checks, +constructs `RegexFlags`, and creates `JoniRegexPattern` variants. Its cache key +includes source and modifiers, lexical debug and `re 'strict'` state, trusted +callout count, effective byte provenance, and custom-`charnames` translator +discriminator. The discriminator is the translator scalar's string +representation; the translator and its `NamedCharacterCache` are separately +retained for deferred recompilation. User-defined Unicode properties are +preloaded outside the compiler lock when Perl code may run. Deferred +source-compile placeholders retain their exact compilation context and are +replaced before matching. + +`JoniRegexPattern` supplies Joni `Syntax`, options, resolver hooks, warning +mapping, and trusted-token materialization. Production matcher input otherwise +retains the admitted source spelling. Native Joni parses and executes groups, +captures, calls and recursion, conditions, lookarounds, control verbs, +quantifiers, ordinary and extended character classes, named characters, +properties, case folding, callbacks, and dynamic subprograms. + +## Matching and Perl state + +A compiled `RuntimeRegex` can hold an ordinary Joni variant, a Unicode variant, +and a byte-pattern variant for byte-backed `/d` case-fold behavior. +`selectRecursivePattern()` chooses among them from the pattern and subject +provenance. Every match operation creates a matcher and, when needed, a +matcher-local callback handler; compiled patterns do not share provisional +callback state. + +`RuntimeRegex` owns Perl-visible behavior around the matcher: scalar and list +context, `pos`, `/g`, `/c`, `\G`, substitutions, match variables, named and +numbered captures, preserve-match state, and last-successful-pattern reuse. +Joni reports byte offsets. The adapter maps them to Perl character offsets +before publishing `$&`, `$1`, `@-`, `@+`, and `pos`. + +Global matching implements Perl's empty-match rule explicitly: after returning +one zero-width match at an offset, the next attempt first asks for a consuming +match at that same offset with all further empty results suppressed. Only then +may it advance by one Perl character. Substitution uses the same semantic rule. + +## Executable callbacks and dynamic patterns + +The engine-facing skeleton uses `(?{=CALL:})` and +`(?{=DYNAMIC:})`. The fork parses these as dedicated nodes and opcodes; it +does not parse or execute Perl source. + +`JoniRegexPattern.PerlCalloutHandler` publishes provisional capture state and +runs the captured Perl closure in scalar context. Each callback token +checkpoints Perl regex/capture state, the prior `$^R`, dynamic-local level, +result metadata, and, for dynamic evaluation, the prior capture view. Callback +position is published and restored around invocation rather than stored in the +token. Joni's matcher stack calls `unwind` when backtracking abandons the token +and `complete` when the selected path keeps it. The adapter finishes the +top-level invocation; nested Joni continuations finish their own handlers. The +bridge restores dynamic scope on both normal and exceptional paths. + +A dynamic `(??{...})` expression is evaluated only when its opcode is reached. +The returned string or `qr//` becomes a nested Joni continuation. Its +alternatives remain resumable by the outer matcher, while its capture numbering +stays private. Control verbs operate at the current matcher-program boundary; +they are not post-match rewrites. + +The runtime-neutral fork API and exact unwind contract are documented in +[`joni-callout-fork.md`](../../docs/design/joni-callout-fork.md). + +## Encoding and Unicode ownership + +Unicode patterns and subjects use UTF-8 plus explicit character-to-byte and +byte-to-character maps. Byte programs use ISO-8859-1 and identity maps. +`PerlUtfString` together with Joni's `WideScalarCodec` provides a reversible +internal representation for surrogate and above-Unicode Perl scalar values. + +Unicode behavior has three data owners: + +- Checked-in `PerlUnicode*Data` classes and + `third_party/joni/.../PerlUnicodeCaseFoldData` encode current-Perl property, + alias, name, and fold semantics that must not drift with libraries. Joni's + `WordBreakData`, `SentenceBreakData`, and `LineBreakData` separately encode + boundary data. +- ICU supplies `UnicodeSet` operations and fallback Unicode APIs where Perl does + not require a pinned override. +- JCodings supplies encodings and baseline code-point/fold primitives used by + Joni. `RuntimeRegex`, `RegexFlags`, and `UnicodeResolver` choose Perl-specific + `/d`, `/u`, `/a`, `/aa`, byte provenance, and property-fold policy; the + maintained fork enforces those choices and adds pinned multi-code-point fold + behavior. + +`UnicodeResolver` implements Perl alias grammar and precedence: cached +user-defined properties are consulted before colliding built-ins, then pinned +Perl aliases and generated tables, followed by explicitly accepted ICU +property/value fallbacks. It also implements property-value wildcards, +script-run policy, inclusive and wide ranges, and per-property case-fold +eligibility through Joni's +`CharacterPropertyResolver`. `NamedCharacterResolver` uses the compiled +`NamedCharacterCache`; `PerlPropertyValueMatcher` evaluates wildcard value +expressions without depending on PerlOnJava runtime classes. + +The generator registry is +`dev/tools/perl_unicode_data_generators.json`. It records the consumed Perl +checkout, Unicode version, input hashes, generated outputs, and output hashes. +`dev/tools/generate_perl_unicode_data.pl --check` is the deterministic +regeneration gate for the registered property and fold tables. Scalar-name and +named-sequence tables currently have standalone generators, +`generate_perl_unicode_scalar_name_data.pl` and +`generate_perl_unicode_named_sequence_data.pl`; they are not registered in that +manifest and therefore require explicit regeneration and byte comparison. The +Joni word, sentence, and line boundary tables are produced by +`generate_joni_word_break_data.pl`, `generate_joni_boundary_data.pl`, and +`generate_joni_line_break_data.pl`. They are not entries in this manifest, so +refreshing them requires an explicit regeneration and byte comparison. The +policy is current-checkout provenance: a recorded commit and hashes identify one +generation, while deliberate `make perl5-update` and `make perl5-sync` +operations may advance the next one. + +## Fork and distribution + +The fork retains upstream `org.joni` packages in source. Gradle adds its +production sources to `main`; imported fork tests use the separate `joniTest` +source set. The standalone JAR relocates Joni to `org.perlonjava.internal.joni` and JCodings to -`org.perlonjava.internal.jcodings`, avoiding classpath collisions without -rewriting the maintained source namespace. - -The fork includes native support required by PerlOnJava for: - -- absolute, relative, named, recursive, and whole-pattern subpattern calls; -- numbered, named, assertion, recursion, and callback conditions; -- `(*ACCEPT)`, `(*MARK:NAME)`, named `(*SKIP:NAME)`, `(*PRUNE)`, `(*COMMIT)`, - and `(*THEN)` with matcher-owned unwind boundaries; -- runtime-neutral callouts and dynamic nested matchers; -- wide scalar ranges beyond Unicode and Perl property resolution; -- Perl-specific parser, diagnostic, and case-fold hooks. - -Original Joni, JCodings, Unicode, and Perl copyright and authorship notices are -retained. The packaged JAR includes license texts and a modification notice; -the SBOM identifies the vendored components. - -## Executable and dynamic callbacks - -The Perl parser creates structured callback parts rather than embedding raw Perl -source in a regex string. Runtime assembly assigns callback IDs and emits -trusted engine tokens such as `(?{=CALL:})` and -`(?{=DYNAMIC:})`. Interpolated runtime text cannot create trusted tokens. - -Joni invokes a matcher-local `CalloutHandler` with provisional captures and the -current byte position. Callback tokens checkpoint regex state, `$^R`, and -dynamic locals. Backtracking unwinds each token exactly once; successful -completion closes active scopes while retaining the successful callback result. -Dynamic `(??{ ... })` programs retain their alternatives as resumable nested -matcher continuations rather than atomic post-processing. - -`$^N` follows capture-close order. `$+` remains the highest-numbered defined -capture. Nested matches save and restore outer match state, and callback control -flow cannot target loops or labels outside its pseudo block. - -## Unicode properties and named characters - -`UnicodeResolver` implements Perl property aliases and defaults from generated, -pinned Unicode 17 data. Generators and checked-in sources live under `dev/tools` -and `dev/unicode/17.0.0`; freshness tests require byte-for-byte regeneration. -ICU4J supplies general Unicode operations, while generated Perl tables define -the compatibility surface where Perl aliases, defaults, or versions differ. - -Property-value wildcard expressions are compiled and executed by -`org.joni.PerlPropertyValueMatcher`; Java `Pattern` no longer evaluates them. -The resolver currently materializes the selected ranges through the adapter -because Joni's character-property lexer does not yet own nested regex syntax -inside `\p{...}`. Removing that materialization is an active migration step. - -Generated named-sequence data resolves Perl's multi-code-point `\N{name}` values -before ordinary scalar Unicode names. Custom `charnames` translators and source -provenance remain frontend/runtime responsibilities. Temporary encoded sequence -tokens and their diagnostic restoration are still being removed. - -## Case folding - -Generated Perl tables contain default full mappings, simple-fold classes, -reverse multi-character sequences, and Turkic exclusions. The fork has a -runtime-neutral fold adapter and suppresses exact-search optimisation where a -full fold makes its literal bound unsafe. - -Property/class closure, explicit `/d`, `/u`, `/a`, and `/aa` context, reverse -literal expansion, and backreference folding are not yet complete. Until those -paths carry Perl provenance natively, the adapter retains the corresponding -semantic protections. - -## Preprocessing boundary - -Preprocessing may preserve source policy or bridge a feature not yet represented -by Joni, but it must not emulate backtracking semantics. Current temporary work -includes Java syntax adaptation, range materialisation for property wildcards, -named-sequence encoding, extended-character-class lowering, and the -`(?(DEFINE)...)` rewrite. Each is deleted with the same change that proves its -native replacement against Perl. - -The frontend continues to own trusted callback construction, `use re 'eval'` -security, lexical warning policy, user-defined Unicode properties, original -source locations, and Perl-facing diagnostics. Those are source/runtime policy, -not matcher behavior. - -## Validation contract - -New semantic fixtures are validated with system Perl before either PerlOnJava -backend. Focused changes run direct Joni tests plus forced-Joni JVM and -interpreter fixtures. Combined batches run warning-free `make`, packaging, and -generated-data freshness checks. - -The release gate compares `dev/tools/perl_test_runner.pl` output file-by-file -with `../PerlOnJava/logs/test_20260815_080000_958.log`. Complete Unicode, -`reg_mesg.t`, `pat.t`, `pat_advanced.t`, four 80-file forced-Joni legs, -`pat_psycho*`, and `speed*` must finish without unexplained regressions, -timeouts, incomplete TAP, or backend disagreement. - -## Remaining migration gates - -- finish native extended character classes and `(?(DEFINE)...)`; -- complete property/class, literal, backreference, and provenance-aware folding; -- move nested property-value regex parsing into Joni; -- close runtime-source and exact diagnostic differences; -- remove Java matching, backend selection, and matcher-semantic preprocessing; -- remove obsolete imported-test patches and verify sync idempotence; -- pass performance, packaging, Linux, Windows, and complete CI gates. - -The ordered execution plan and acceptance tracker are in -`dev/design/phase36-regex-parity.md`. The fork API and ownership contract are in -`docs/design/joni-callout-fork.md`. +`org.perlonjava.internal.jcodings`, preventing conflicts with embedding +applications. + +The JAR carries the upstream Joni license, the JCodings license, and the +PerlOnJava fork notice under `META-INF/licenses`. Its SBOM records vendored Joni +and the Joni-to-JCodings dependency. `verifyJoniPackaging` and +`dev/tools/verify-joni-packaging.pl` enforce relocation, notice bytes, component +metadata, and dependency edges. + +## Remaining source-policy boundaries + +The Java code in the regex package may use small Java regular expressions as +text scanners; those utilities are not match engines for Perl patterns. The +remaining production boundaries are explicit: + +- `RuntimeRegex` handles lexical/source policy such as `\Q` interpolation, + unescaped-left-brace warnings, literal diagnostic markers, and recognition of + runtime executable source before invoking `RuntimeRegexSourceCompiler`. +- `JoniRegexPattern.analyzePerlSyntax()` records adapter policy needed before or + around compilation, including the Perl prohibition on `\K` in lookaround and + optimization/control-state flags. It does not rewrite matcher semantics. +- `JoniRegexPattern.validateExtendedPropertyPolicy()` still scans extended + classes to reject Unicode string properties and unresolved user properties + whose composition cannot yet be represented through the runtime-neutral + property hook. Removing this bounded scan requires Joni to carry enough class + context for those two policies. +- `RegexDiagnosticFormatter` and the Joni `WarnCallback` mapping retain Perl's + message text, source spelling, marker position, warning category, lexical + warning mask, and fatal-versus-warning decision. Unsupported syntax is fatal + unless the development-only `JPERL_UNIMPLEMENTED=warn` downgrade is selected. + +## Verification + +For a regex change, validate new or changed Perl fixtures with system Perl +first. Run focused PerlOnJava tests under both execution backends with a timeout +and captured output. Direct fork changes also require `make test-joni`. + +The repository gates are: + +- `make` for the maintained fork, packaging checks, and unit shards; +- `make check-links` when documentation links change and `lychee` is installed; +- `perl dev/tools/generate_perl_unicode_data.pl --check` for generated Unicode + inputs and outputs; +- `perl dev/tools/perl_test_runner.pl perl5_t/t/re/` for the imported regex + corpus, compared file by file rather than by aggregate totals alone. + +`JPERL_UNIMPLEMENTED=warn` may deliberately turn unsupported compilation into a +warning and a never-match pattern. It is a diagnostic aid, never evidence that +supported syntax works. The active acceptance checklist remains +[`phase36-regex-parity.md`](../design/phase36-regex-parity.md); this document +describes architecture rather than project status. diff --git a/dev/implementation/signal-handling.md b/dev/implementation/signal-handling.md index 439fe76a4e..54e069433f 100644 --- a/dev/implementation/signal-handling.md +++ b/dev/implementation/signal-handling.md @@ -183,7 +183,7 @@ factorial(1000000); # Not interruptible **Solution:** Don't check every subroutine call (too expensive) **Impact:** Rare edge case - 99% of code has loops -### 2. Regex Engine (Java Pattern/Matcher) +### 2. Regex Engine (Joni) **Problem:** ```perl @@ -191,7 +191,8 @@ alarm(1); "aaa...aaa" =~ /(a+)+b/; # Catastrophic backtracking - NOT interruptible ``` -**Why:** `matcher.find()` is Java library call, not interruptible +**Why:** A native Joni search runs inside one JVM call and does not currently +poll PerlOnJava's signal state while backtracking. **Workaround:** Wrap regex in timeout thread when alarm active **Status:** Not yet implemented (future enhancement) @@ -394,4 +395,3 @@ sleep 10; This implementation provides a **lightweight, efficient, and practical** solution for alarm()-based signal handling in PerlOnJava. While not 100% compatible with Perl (particularly regarding regex interruption), it covers 85-90% of real-world use cases with negligible performance overhead. The key insight is to check signals at **strategic points** (loop entries, I/O) rather than everywhere, achieving both correctness and performance. - diff --git a/dev/import-perl5/README.md b/dev/import-perl5/README.md index b9309fee68..b3c05f2e42 100644 --- a/dev/import-perl5/README.md +++ b/dev/import-perl5/README.md @@ -21,6 +21,34 @@ The import system helps maintain modules that are (nearly) identical to their pe ## Quick Start +### Update the development Perl checkout + +```bash +make perl5-update +make perl5-sync +make perl5-sync FILTER=Name.pl +# If the platform Perl is older than current blead requires: +make PERL=/path/to/system/perl perl5-sync FILTER=Name.pl +``` + +`perl5-update` clones the official Perl repository into the gitignored +`perl5/` directory when absent. For an existing checkout (including a +`perl5/` symlink to an adjacent checkout), it refuses tracked edits, detached +HEAD, missing or mismatched upstream configuration, and non-fast-forward +updates before changing files. The checked-out branch must be the branch the +remote currently advertises as its default; the helper refuses any other +branch instead of silently switching it. It fetches the configured upstream +and advances the checked-out branch with `--ff-only`, then prints the exact +consumed commit. +Ignored and untracked generated files do not make the checkout falsely dirty. + +`perl5-sync` performs that safe update and then replays the complete import +manifest. `FILTER` passes exactly one `--only` value. These explicit developer +targets may access the network; ordinary `make`, tests, packaging, and CI do +not depend on them. `PERL` may select a compatible system Perl when the +platform default is too old for current blead's Unicode generators; never use +`jperl` for the importer. + ### Synchronize All Configured Imports ```bash @@ -37,10 +65,10 @@ perl dev/import-perl5/sync.pl --only File-DosGlob Substring match against each row’s `source:` and `target:` fields. Prefer this after adding a single module so unrelated trees under `src/main/perl/lib/` are not overwritten. Run `perl dev/import-perl5/sync.pl --help` for details. -### Refresh the pinned Unicode generator snapshot +### Refresh the current upstream Unicode generator snapshot The six tracked payloads under `dev/unicode/17.0.0/` are ordinary manifest -imports from the pinned `perl5/lib/unicore` checkout. Refresh only that complete +imports from the current upstream `perl5/lib/unicore` checkout. Refresh only that complete group with its unique target prefix: ```bash @@ -50,7 +78,7 @@ perl dev/import-perl5/sync.pl --only dev/unicode/17.0.0 The command updates `version`, the three alias/block files, and the two `extracted/` property files. Their repository-authored `README.md` is not an import target and remains untouched. Review source/target hashes and regenerate -the affected checked-in Java data after intentionally advancing the pinned Perl +the affected checked-in Java data after intentionally advancing the upstream Perl or Unicode baseline. ### Add a New Module @@ -83,7 +111,8 @@ Main synchronization script that imports files from perl5/ based on config.yaml. **Features:** - Copies individual files or entire directories - Refreshes the minimal tracked Unicode generator snapshot through explicit manifest rows -- Generates pinned-source test artifacts such as `unicore/TestProp.pl` +- Generates current-upstream test artifacts such as `unicore/TestProp.pl` +- Generates the core `unicore/Name.pl` source artifact before copying it - Applies patches automatically - Creates necessary directories - Validates sources exist @@ -102,7 +131,7 @@ Protected targets (`protected: true` in YAML) are always excluded from bulk dire The upstream `uniprops01.t` through `uniprops10.t` wrappers load `perl5_t/lib/unicore/TestProp.pl`. Perl does not commit that file: its build -generates it from `perl5/lib/unicore/mktables` and the pinned Unicode database. +generates it from `perl5/lib/unicore/mktables` and the current upstream Unicode database. PerlOnJava therefore generates a losslessly split fixture explicitly: ```bash @@ -110,7 +139,7 @@ perl dev/import-perl5/sync.pl --only TestProp.pl ``` Generation runs in a temporary copy of `perl5/lib/unicore`, so it does not -modify the pinned source tree. The importer retains every canonical assertion, +modify the current upstream source tree. The importer retains every canonical assertion, splits the ten existing `TESTCHUNK` sections into ignored `TestProp-01.pl` through `TestProp-10.pl` files, and installs a small `TestProp.pl` dispatcher. Each unchanged upstream wrapper consequently parses only its selected section @@ -126,6 +155,23 @@ filtered syncs neither generate nor remove them. Missing Unicode inputs or an incompatible host Perl make the sync fail with an actionable diagnostic rather than silently leaving the ten wrappers unavailable. +#### Generated Unicode name table + +`_charnames.pm` loads `unicore/Name.pl` as a normal bundled core resource. +Upstream creates this file with `perl5/lib/unicore/mktables`, but does not keep +it in its source checkout. The manifest therefore first generates +`perl5/lib/unicore/Name.pl` from the current checkout, reports its SHA-256, +and then copies it through the ordinary source/target import row: + +```bash +perl dev/import-perl5/sync.pl --only Name.pl +``` + +The invoking host Perl must be 5.36 or newer, because the current `mktables` +uses `builtin`. The generator writes only the current checkout's missing source +artifact and publishes it atomically; the normal sync copy remains responsible +for the bundled `src/main/perl/lib/unicore/Name.pl` resource. + ### add_module.pl Interactive tool to add new modules to the sync configuration. diff --git a/dev/import-perl5/config.yaml b/dev/import-perl5/config.yaml index f45961dd22..4880b9bda6 100644 --- a/dev/import-perl5/config.yaml +++ b/dev/import-perl5/config.yaml @@ -95,7 +95,7 @@ imports: target: perl5_t/Porting type: directory - # Minimal pinned Unicode 17.0 generator inputs. Keep these as explicit file + # Minimal current-upstream Unicode 17.0 generator inputs. Keep these as explicit file # imports so clean checkouts can reproduce the checked-in Java data without # importing the complete perl5/lib/unicore tree. - source: perl5/lib/unicore/version @@ -127,12 +127,21 @@ imports: type: file # perl5_t/lib otherwise remains empty to avoid module loading conflicts. - # TestProp.pl is generated from the pinned Unicode inputs because upstream + # TestProp.pl is generated from the current upstream Unicode inputs because upstream # does not store this build artifact in the perl5 source tree. - source: perl5/lib/unicore/mktables target: perl5_t/lib/unicore/TestProp.pl type: generated_unicode_testprop + # Name.pl is a normal core resource, generated by mktables but omitted from + # the current source checkout. Generate it there before the ordinary copy. + - source: perl5/lib/unicore/mktables + target: perl5/lib/unicore/Name.pl + type: generated_unicode_name_source + + - source: perl5/lib/unicore/Name.pl + target: src/main/perl/lib/unicore/Name.pl + # Bulk import all core test files from perl5/t/ to perl5_t/t/ # This creates a complete Perl 5 test environment under perl5_t/ - source: perl5/t @@ -288,7 +297,6 @@ imports: # From core library - source: perl5/lib/_charnames.pm target: src/main/perl/lib/_charnames.pm - patch: _charnames.pm.patch # From core library - source: perl5/lib/charnames.pm diff --git a/dev/import-perl5/patches/App-Cpan.pm.patch b/dev/import-perl5/patches/App-Cpan.pm.patch index cd789092d3..06e8291780 100644 --- a/dev/import-perl5/patches/App-Cpan.pm.patch +++ b/dev/import-perl5/patches/App-Cpan.pm.patch @@ -1,14 +1,20 @@ ---- perl5/cpan/CPAN/lib/App/Cpan.pm 2026-04-10 11:04:21 -+++ src/main/perl/lib/App/Cpan.pm 2026-08-10 10:12:19 -@@ -652,6 +652,7 @@ +--- perl5/cpan/CPAN/lib/App/Cpan.pm ++++ src/main/perl/lib/App/Cpan.pm +@@ -647,11 +647,13 @@ + $logger->error( "Skipping $arg because I couldn't find a matching namespace." ); + next; + }; ++ my $requested_distribution_id = eval { $module->distribution->id }; + + _clear_cpanpm_output(); $action->( $arg ); my $error = _cpanpm_output_indicates_failure(); -+ $error ||= _cpanpm_status_indicates_failure(); ++ $error ||= _cpanpm_status_indicates_failure($requested_distribution_id); push @errors, $error if $error; } -@@ -752,7 +753,7 @@ +@@ -752,7 +754,7 @@ BEGIN { my $epic_fail_words = join '|', @@ -17,21 +23,29 @@ fail(?:ed)? Cannot\s+install ); sub _cpanpm_output_indicates_failure -@@ -763,6 +764,17 @@ - return A_MODULE_FAILED_TO_INSTALL if $last_line =~ /\b(?:Cannot\s+install)\b/i; +@@ -764,6 +766,25 @@ $result || (); -+ } + } + +sub _cpanpm_status_indicates_failure + { ++ my $requested_distribution_id = shift; ++ $requested_distribution_id =~ s{^./../}{} ++ if defined $requested_distribution_id; ++ + # CPAN already records structured phase status for every distribution in + # the current command, including recursively installed prerequisites. + # Prefer that state when App::Cpan's legacy last-output-line heuristic is + # fooled by trailing hints or report suggestions. + my @failed = CPAN::Shell->find_failed($CPAN::CurrentCommandId); -+ return A_MODULE_FAILED_TO_INSTALL if grep { $_->[5] } @failed; ++ return A_MODULE_FAILED_TO_INSTALL if grep { ++ $_->[5] ++ || (defined $requested_distribution_id ++ && $_->[1] eq $requested_distribution_id) ++ } @failed; + return; - } ++ } } + sub _cpanpm_output_indicates_success diff --git a/dev/import-perl5/patches/IPC-Cmd.pm.patch b/dev/import-perl5/patches/IPC-Cmd.pm.patch index 9c8115568b..1ae5fbdd1a 100644 --- a/dev/import-perl5/patches/IPC-Cmd.pm.patch +++ b/dev/import-perl5/patches/IPC-Cmd.pm.patch @@ -1,8 +1,14 @@ --- perl5/cpan/IPC-Cmd/lib/IPC/Cmd.pm +++ src/main/perl/lib/IPC/Cmd.pm -@@ -8,5 +8,9 @@ +@@ -7,7 +7,14 @@ + use constant IS_VMS => $^O eq 'VMS' ? 1 : 0; + use constant IS_WIN32 => $^O eq 'MSWin32' ? 1 : 0; use constant IS_HPUX => $^O eq 'hpux' ? 1 : 0; - use constant IS_WIN98 => (IS_WIN32 and !Win32::IsWinNT()) ? 1 : 0; +- use constant IS_WIN98 => (IS_WIN32 and !Win32::IsWinNT()) ? 1 : 0; ++ use constant IS_WIN98 => (IS_WIN32 and do { ++ require Win32; ++ !Win32::IsWinNT(); ++ }) ? 1 : 0; + use constant IS_PERLONJAVA => do { + require Config; + $Config::Config{perlonjava} ? 1 : 0; @@ -10,7 +16,7 @@ use constant ALARM_CLASS => __PACKAGE__ . '::TimeOut'; use constant SPECIAL_CHARS => qw[< > | &]; use constant QUOTE => do { IS_WIN32 ? q["] : q['] }; -@@ -38,7 +42,7 @@ +@@ -38,7 +45,7 @@ require Time::HiRes; Time::HiRes->import(); require Win32 if IS_WIN32; }; @@ -19,3 +25,73 @@ eval { my $wait_start_time = Time::HiRes::clock_gettime(&Time::HiRes::CLOCK_MONOTONIC); +@@ -190,6 +197,7 @@ + sub can_capture_buffer { + my $self = shift; + ++ return 1 if IS_PERLONJAVA; + return 1 if $USE_IPC_RUN && $self->can_use_ipc_run; + return 1 if $USE_IPC_OPEN3 && $self->can_use_ipc_open3; + return; +@@ -1345,9 +1353,18 @@ + qq[: Command '$pp_cmd' aborted by alarm after $timeout seconds] + }, ALARM_CLASS } if $timeout; + alarm $timeout || 0; ++ ++ ### PerlOnJava has no fork(), so forced IPC::Run/Open3 selection must ++ ### still use the JVM ProcessBuilder backend. ++ if (IS_PERLONJAVA) { ++ $self->_debug("# Using PerlOnJava::Process. Have buffer: $have_buffer") ++ if $DEBUG; ++ $ok = $self->_perlonjava_run( ++ $cmd, $_out_handler, $_err_handler, $timeout, $verbose ++ ); + + ### IPC::Run is first choice if $USE_IPC_RUN is set. +- if( !IS_WIN32 and $USE_IPC_RUN and $self->can_use_ipc_run( 1 ) ) { ++ } elsif( !IS_WIN32 and $USE_IPC_RUN and $self->can_use_ipc_run( 1 ) ) { + ### ipc::run handlers needs the command as a string or an array ref + + $self->_debug( "# Using IPC::Run. Have buffer: $have_buffer" ) +@@ -1407,8 +1424,41 @@ + ? ($ok, $err, \@buffer, \@buff_out, \@buff_err) + : ($ok, $err ) + : $ok ++ ++ ++} ++ ++sub _perlonjava_run { ++ my ($self, $cmd, $outhand, $errhand, $timeout, $verbose) = @_; + ++ require Config; ++ require PerlOnJava::Process; ++ my $argv = ref($cmd) eq 'ARRAY' ? [@$cmd] : IS_WIN32 ++ ? [($ENV{COMSPEC} || 'cmd.exe'), '/d', '/s', '/c', $cmd] ++ : [($Config::Config{sh} || '/bin/sh'), '-c', $cmd]; + ++ my $result = PerlOnJava::Process::run_process( ++ argv => $argv, ++ timeout => $timeout, ++ tee => 0, ++ ); ++ $outhand->($result->{stdout}) if length($result->{stdout} // ''); ++ $errhand->($result->{stderr}) if length($result->{stderr} // ''); ++ ++ if ($result->{timed_out}) { ++ $self->error(loc("Command '%1' timed out", ref($cmd) ? "@$cmd" : $cmd)); ++ return $self->ok(0); ++ } ++ if (length($result->{error} // '')) { ++ $self->error($result->{error}); ++ return $self->ok(0); ++ } ++ if (($result->{exit_code} // -1) != 0) { ++ $self->error(loc("Command '%1' exited with value %2", ++ ref($cmd) ? "@$cmd" : $cmd, $result->{exit_code})); ++ return $self->ok(0); ++ } ++ return $self->ok(1); + } + + sub _open3_run_win32 { diff --git a/dev/import-perl5/patches/_charnames.pm.patch b/dev/import-perl5/patches/_charnames.pm.patch deleted file mode 100644 index a7e682e0f8..0000000000 --- a/dev/import-perl5/patches/_charnames.pm.patch +++ /dev/null @@ -1,32 +0,0 @@ ---- perl5/lib/_charnames.pm 2025-12-11 14:13:49 -+++ src/main/perl/lib/_charnames.pm 2026-04-08 09:40:13 -@@ -137,6 +137,12 @@ - return if $txt; - - $txt = do "unicore/Name.pl"; -+ if (!defined $txt || $txt eq '') { -+ # unicore/Name.pl not available (e.g. on PerlOnJava); -+ # set $txt to a truthy placeholder so we don't retry and crash. -+ # viacode() will fall back to _java_viacode() for name lookups. -+ $txt = "# unavailable\n"; -+ } - Internals::SvREADONLY($txt, 1); - } - -@@ -805,6 +811,16 @@ - if (defined $algorithmic) { - $viacode{$hex} = $algorithmic; - return $algorithmic; -+ } -+ -+ # Try Java-backed ICU4J name lookup if available (PerlOnJava). -+ # This provides complete Unicode name data without needing unicore/Name.pl. -+ if (defined &_java_viacode) { -+ my $java_name = _java_viacode(CORE::hex $hex); -+ if (defined $java_name && $java_name ne '') { -+ $viacode{$hex} = $java_name; -+ return $java_name; -+ } - } - - # Return the official name, if exists. It's unclear to me (khw) at diff --git a/dev/import-perl5/sync.pl b/dev/import-perl5/sync.pl index 7e459af9dc..e9780e70cc 100755 --- a/dev/import-perl5/sync.pl +++ b/dev/import-perl5/sync.pl @@ -84,11 +84,12 @@ sub apply_patch { my ($target, $patch_file) = @_; # --no-backup-if-mismatch prevents creating .orig files - my $cmd = "patch --no-backup-if-mismatch -p0 '$target' < '$patch_file'"; + my $cmd = "patch --no-backup-if-mismatch -r - -p0 '$target' < '$patch_file'"; print " Applying patch: $patch_file\n"; my $result = system($cmd); if ($result != 0) { + unlink "$target.rej", "$target.orig"; warn " Warning: patch failed with exit code $result\n"; return 0; } @@ -200,6 +201,7 @@ sub split_unicode_testprop { my @manifest = ( "\n# PerlOnJava lossless TESTCHUNK dispatcher\n", "# Canonical pinned mktables SHA-256: $canonical_sha\n", + "# Canonical current-upstream mktables SHA-256: $canonical_sha\n", ); for my $section (@sections) { my @counts = map { "$_=$section->{counts}{$_}" } @@ -236,7 +238,7 @@ sub split_unicode_testprop { } # Generate the Unicode property test fixture from a pristine copy of the -# pinned source data. Upstream deliberately does not commit TestProp.pl; its +# current upstream source data. Upstream deliberately does not commit TestProp.pl; its # normal build creates it with lib/unicore/mktables -maketest. sub generate_unicode_testprop { my ($generator_relative, $target, $project_root) = @_; @@ -249,9 +251,9 @@ sub generate_unicode_testprop { ); for my $required (@required) { unless (-f $required) { - warn " ERROR: Cannot generate Unicode TestProp.pl; missing pinned " - . "generation prerequisite: $required\n" - . " Restore perl5/lib/unicore from the pinned perl5 source " + warn " ERROR: Cannot generate Unicode TestProp.pl; missing pinned generation prerequisite " + . "(compatibility alias; selected source is the current checkout, not a historical SHA): $required\n" + . " Restore perl5/lib/unicore from the current upstream source " . "before running this sync.\n\n"; return 0; } @@ -265,7 +267,7 @@ sub generate_unicode_testprop { }; unless (copy_directory($unicode_source, $temporary_unicode, $project_root, [], [])) { - warn " ERROR: Cannot copy pinned Unicode data for TestProp.pl generation.\n\n"; + warn " ERROR: Cannot copy current upstream Unicode data for TestProp.pl generation.\n\n"; return 0; } @@ -275,7 +277,7 @@ sub generate_unicode_testprop { warn " ERROR: Cannot enter project root for TestProp.pl generation: $!\n\n"; return 0; } - print " Generating with pinned Unicode data: $generator_relative\n"; + print " Generating with current upstream Unicode data: $generator_relative\n"; my $result = system($^X, $generator_relative, '-C', $temporary_unicode, '-T', $generated, @@ -291,7 +293,7 @@ sub generate_unicode_testprop { ? "terminated by signal " . ($result & 127) : "exit code " . ($result >> 8); warn " ERROR: Unicode TestProp.pl generation failed ($exit).\n" - . " Ensure the pinned perl5/lib/unicore data is complete and the " + . " Ensure the current upstream perl5/lib/unicore data is complete and the " . "host Perl can run mktables.\n\n"; return 0; } @@ -385,6 +387,104 @@ sub generate_unicode_testprop { return 1; } +# Generate the core Name.pl table in the checked-out perl5 source before its +# ordinary manifest row copies it into the bundled library. Upstream does not +# commit this build product, but _charnames.pm loads it as a normal core file. +sub generate_unicode_name_source { + my ($generator_relative, $target, $project_root) = @_; + if ($^V lt v5.36.0) { + warn " ERROR: Cannot generate Unicode Name.pl with $^X ($^V).\n" + . " Current perl5/lib/unicore/mktables uses builtin, which requires " + . "Perl 5.36 or newer. Re-run sync.pl with a compatible host Perl.\n\n"; + return 0; + } + + my $generator = File::Spec->catfile($project_root, $generator_relative); + my $unicode_source = dirname($generator); + for my $required ($generator, + File::Spec->catfile($unicode_source, 'version'), + File::Spec->catfile($unicode_source, 'UnicodeData.txt')) { + unless (-f $required) { + warn " ERROR: Cannot generate Unicode Name.pl; missing checkout " + . "generation prerequisite: $required\n\n"; + return 0; + } + } + + my $temporary = tempdir('perlonjava-namepl-XXXXXX', TMPDIR => 1, CLEANUP => 1); + my $temporary_unicode = File::Spec->catdir($temporary, 'unicore'); + make_path($temporary_unicode) or do { + warn " ERROR: Cannot create temporary Unicode generation directory: $!\n\n"; + return 0; + }; + unless (copy_directory($unicode_source, $temporary_unicode, + $project_root, [], [])) { + warn " ERROR: Cannot copy checked-out Unicode data for Name.pl generation.\n\n"; + return 0; + } + + my $original_dir = getcwd(); + unless (chdir $project_root) { + warn " ERROR: Cannot enter project root for Name.pl generation: $!\n\n"; + return 0; + } + print " Generating Unicode Name.pl with $^X: $generator_relative\n"; + my $result = system($^X, $generator_relative, '-C', $temporary_unicode, '-q'); + my $generation_error = $!; + unless (chdir $original_dir) { + die "sync.pl: cannot restore working directory '$original_dir': $!\n"; + } + if ($result != 0) { + my $exit = $result == -1 + ? "could not start: $generation_error" + : ($result & 127) + ? "terminated by signal " . ($result & 127) + : "exit code " . ($result >> 8); + warn " ERROR: Unicode Name.pl generation failed ($exit).\n" + . " Re-run sync.pl with a host Perl that can run the current " + . "perl5/lib/unicore/mktables.\n\n"; + return 0; + } + + my $generated = File::Spec->catfile($temporary_unicode, 'Name.pl'); + unless (-s $generated) { + warn " ERROR: Unicode generator completed without producing Name.pl.\n\n"; + return 0; + } + open my $generated_fh, '<', $generated or do { + warn " ERROR: Cannot inspect generated Name.pl: $!\n\n"; + return 0; + }; + binmode $generated_fh; + local $/; + my $contents = <$generated_fh>; + close $generated_fh; + my $actual_sha = sha256_hex($contents); + my $target_dir = dirname($target); + make_path($target_dir) unless -d $target_dir; + my ($target_fh, $staged) = tempfile('.Name-sync-XXXXXX', DIR => $target_dir, + UNLINK => 0); + binmode $target_fh; + print {$target_fh} $contents or do { + warn " ERROR: Cannot stage generated Name.pl: $!\n\n"; + close $target_fh; + unlink $staged; + return 0; + }; + close $target_fh or do { + warn " ERROR: Cannot close staged Name.pl: $!\n\n"; + unlink $staged; + return 0; + }; + rename $staged, $target or do { + warn " ERROR: Cannot publish generated Name.pl: $!\n\n"; + unlink $staged; + return 0; + }; + print " Generated Name.pl (SHA-256 $actual_sha)\n"; + return 1; +} + sub usage { print <<'USAGE'; PerlOnJava perl5 import sync — see dev/import-perl5/config.yaml @@ -515,6 +615,13 @@ sub main { next; } } + elsif ($type eq 'generated_unicode_name_source') { + unless (generate_unicode_name_source($import->{source}, $target, + $project_root)) { + $error_count++; + next; + } + } elsif ($type eq 'directory') { unless (-d $source) { warn " ERROR: Source directory not found: $source\n\n"; @@ -565,17 +672,36 @@ sub main { }; } - # Copy file + my $patch_applied = 0; + # Stage file and its patch before replacing the target. print " Copying to: $import->{target}\n"; - unless (copy($source, $target)) { + my ($temporary, $temporary_path) = tempfile('.import-XXXXXX', DIR => $target_dir, UNLINK => 0); + close $temporary; + unless (copy($source, $temporary_path)) { warn " ERROR: Copy failed: $!\n\n"; $error_count++; next; } + if ($import->{patch}) { + my $patch_file = File::Spec->catfile($patches_dir, $import->{patch}); + unless (-f $patch_file && apply_patch($temporary_path, $patch_file)) { + unlink $temporary_path; + $error_count++; + next; + } + $patch_applied = 1; + } + rename $temporary_path, $target or do { + warn " ERROR: Cannot publish staged import: $!\n\n"; + unlink $temporary_path; + $error_count++; + next; + }; + $import->{_patch_applied} = $patch_applied; } # Apply patch if specified - if ($import->{patch}) { + if ($import->{patch} && !$import->{_patch_applied}) { my $patch_file = File::Spec->catfile($patches_dir, $import->{patch}); unless (-f $patch_file) { warn " ERROR: Patch file not found: $patch_file\n\n"; diff --git a/dev/import-perl5/t/transactional_patch_apply.t b/dev/import-perl5/t/transactional_patch_apply.t new file mode 100644 index 0000000000..ea521a1436 --- /dev/null +++ b/dev/import-perl5/t/transactional_patch_apply.t @@ -0,0 +1,33 @@ +use strict; +use warnings; +use Test::More; +use File::Temp qw(tempdir); +use File::Spec; + +my $root = File::Spec->rel2abs(File::Spec->catdir(File::Spec->curdir)); +require File::Spec->catfile($root, 'dev', 'import-perl5', 'sync.pl'); +my $dir = tempdir('import patch space XXXX', TMPDIR => 1, CLEANUP => 1); +my $target = File::Spec->catfile($dir, 'target file.txt'); +my $patch = File::Spec->catfile($dir, 'bad.patch'); +open my $fh, '>', $target or die $!; print {$fh} "old\n"; close $fh; +open $fh, '>', $patch or die $!; print {$fh} "--- target\n+++ target\n@@ -1 +1 @@\n-missing\n+new\n"; close $fh; +ok(!apply_patch($target, $patch), 'bad patch fails'); +open $fh, '<', $target or die $!; is(<$fh>, "old\n", 'failed patch leaves target unchanged'); close $fh; +opendir my $directory, $dir or die $!; +my @artifacts = grep { /\.(?:rej|orig)\z/ } readdir $directory; +closedir $directory; +is_deeply(\@artifacts, [], 'failed patch leaves no artifacts'); + +my $good_patch = File::Spec->catfile($dir, 'good patch.diff'); +open $fh, '>', $good_patch or die $!; +print {$fh} "--- target\n+++ target\n@@ -1 +1 @@\n-old\n+new\n"; +close $fh; +ok(apply_patch($target, $good_patch), 'valid patch succeeds for a target path containing spaces'); +open $fh, '<', $target or die $!; +is(<$fh>, "new\n", 'successful patch publishes the new bytes'); +close $fh; +opendir $directory, $dir or die $!; +@artifacts = grep { /(?:\.(?:rej|orig)\z|^\.import-)/ } readdir $directory; +closedir $directory; +is_deeply(\@artifacts, [], 'successful patch leaves no reject, backup, or temporary sibling'); +done_testing; diff --git a/dev/import-perl5/t/update_perl5.t b/dev/import-perl5/t/update_perl5.t new file mode 100644 index 0000000000..e96a3991c4 --- /dev/null +++ b/dev/import-perl5/t/update_perl5.t @@ -0,0 +1,172 @@ +#!/usr/bin/env perl +use strict; +use warnings; +use Cwd qw(abs_path); +use File::Spec; +use File::Temp qw(tempdir); +use FindBin; +use IPC::Open3; +use Symbol qw(gensym); +use Test::More; + +my $helper = abs_path(File::Spec->catfile($FindBin::Bin, '..', 'update_perl5.pl')); +my $tmp = tempdir('perlonjava-perl5-update-XXXXXX', TMPDIR => 1, CLEANUP => 1); +my $seed = File::Spec->catdir($tmp, 'seed'); +my $upstream = File::Spec->catdir($tmp, 'upstream.git'); +my $checkout = File::Spec->catdir($tmp, 'perl checkout'); + +git($tmp, 'init', '-q', $seed); +git($seed, 'config', 'user.name', 'Import Test'); +git($seed, 'config', 'user.email', 'import-test@example.invalid'); +write_file(File::Spec->catfile($seed, 'tracked.txt'), "one\n"); +git($seed, 'add', 'tracked.txt'); +git($seed, 'commit', '-q', '-m', 'initial'); +git($seed, 'branch', '-M', 'blead'); +git($tmp, 'init', '-q', '--bare', $upstream); +git($seed, 'remote', 'add', 'origin', $upstream); +git($seed, 'push', '-q', '-u', 'origin', 'blead'); +git_dir($upstream, 'symbolic-ref', 'HEAD', 'refs/heads/blead'); +my $initial = git_output($seed, 'rev-parse', 'HEAD'); + +my ($status, $out, $err) = run_helper( + '--perl-root', $checkout, + '--repository', $upstream, +); +is($status, 0, 'absent checkout is cloned from configured upstream') or diag $err; +is(git_output($checkout, 'rev-parse', 'HEAD'), $initial, 'clone consumes latest upstream commit'); +like($out, qr/Perl upstream commit: \Q$initial\E/, 'clone prints exact consumed commit'); + +write_file(File::Spec->catfile($seed, 'tracked.txt'), "two\n"); +git($seed, 'add', 'tracked.txt'); +git($seed, 'commit', '-q', '-m', 'upstream fast forward'); +git($seed, 'push', '-q'); +my $second = git_output($seed, 'rev-parse', 'HEAD'); +($status, $out, $err) = run_helper('--perl-root', $checkout, '--repository', $upstream); +is($status, 0, 'clean checkout fast-forwards') or diag $err; +is(git_output($checkout, 'rev-parse', 'HEAD'), $second, 'fast-forward reaches latest upstream tip'); +like($out, qr/Perl upstream commit: \Q$second\E/, 'fast-forward prints exact consumed commit'); + +write_file(File::Spec->catfile($checkout, 'generated-untracked.txt'), "generated\n"); +($status, $out, $err) = run_helper('--perl-root', $checkout, '--repository', $upstream); +is($status, 0, 'untracked generated files do not make checkout dirty') or diag $err; + +my $tracking_before_dirty = git_output($checkout, 'rev-parse', 'origin/blead'); +write_file(File::Spec->catfile($checkout, 'tracked.txt'), "local edit\n"); +write_file(File::Spec->catfile($seed, 'tracked.txt'), "three\n"); +git($seed, 'add', 'tracked.txt'); +git($seed, 'commit', '-q', '-m', 'upstream while dirty'); +git($seed, 'push', '-q'); +($status, $out, $err) = run_helper('--perl-root', $checkout, '--repository', $upstream); +isnt($status, 0, 'tracked local edit is refused'); +like($err, qr/tracked local changes exist/, 'dirty refusal explains the safety condition'); +is(git_output($checkout, 'rev-parse', 'origin/blead'), $tracking_before_dirty, + 'dirty checkout is refused before fetch'); +is(git_output($checkout, 'rev-parse', 'HEAD'), $second, 'dirty refusal leaves HEAD unchanged'); + +write_file(File::Spec->catfile($checkout, 'tracked.txt'), "two\n"); +($status, $out, $err) = run_helper('--perl-root', $checkout, '--repository', $upstream); +is($status, 0, 'checkout updates after tracked edit is removed') or diag $err; +my $third = git_output($checkout, 'rev-parse', 'HEAD'); + +git($checkout, 'config', 'user.name', 'Import Test'); +git($checkout, 'config', 'user.email', 'import-test@example.invalid'); +write_file(File::Spec->catfile($checkout, 'local.txt'), "local commit\n"); +git($checkout, 'add', 'local.txt'); +git($checkout, 'commit', '-q', '-m', 'local commit'); +my $local_head = git_output($checkout, 'rev-parse', 'HEAD'); +write_file(File::Spec->catfile($seed, 'upstream.txt'), "remote commit\n"); +git($seed, 'add', 'upstream.txt'); +git($seed, 'commit', '-q', '-m', 'divergent upstream commit'); +git($seed, 'push', '-q'); +($status, $out, $err) = run_helper('--perl-root', $checkout, '--repository', $upstream); +isnt($status, 0, 'non-fast-forward checkout is refused'); +like($err, qr/not a fast-forward/, 'non-fast-forward refusal is actionable'); +is(git_output($checkout, 'rev-parse', 'HEAD'), $local_head, 'non-fast-forward refusal leaves HEAD unchanged'); + +my $real_checkout = File::Spec->catdir($tmp, 'adjacent-perl5'); +($status, $out, $err) = run_helper('--perl-root', $real_checkout, '--repository', $upstream); +is($status, 0, 'second clean checkout is cloned') or diag $err; +my $linked_checkout = File::Spec->catfile($tmp, 'perl5-link'); +symlink $real_checkout, $linked_checkout or die "Cannot create symlink: $!"; +($status, $out, $err) = run_helper('--perl-root', $linked_checkout, '--repository', $upstream); +is($status, 0, 'symlink to adjacent checkout is supported') or diag $err; +my $latest = git_output($seed, 'rev-parse', 'HEAD'); +like($out, qr/Perl upstream commit: \Q$latest\E/, 'symlink update reports exact provenance'); + +my $wrong_repo = File::Spec->catdir($tmp, 'wrong.git'); +git($tmp, 'init', '-q', '--bare', $wrong_repo); +($status, $out, $err) = run_helper('--perl-root', $real_checkout, '--repository', $wrong_repo); +isnt($status, 0, 'unexpected configured repository is refused'); +like($err, qr/does not match/, 'repository refusal identifies unsafe relationship'); + +my $fake_sync = File::Spec->catfile($tmp, 'fake-sync.pl'); +my $sync_log = File::Spec->catfile($tmp, 'sync-args'); +write_file($fake_sync, <<'FAKE_SYNC'); +use strict; +use warnings; +open my $fh, '>', $ENV{SYNC_LOG} or die $!; +print {$fh} join "\0", @ARGV; +close $fh or die $!; +FAKE_SYNC +($status, $out, $err) = run_helper( + { SYNC_LOG => $sync_log }, '--perl-root', $real_checkout, + '--repository', $upstream, '--sync', '--sync-script', $fake_sync, +); +is($status, 0, 'full sync invocation succeeds against local fixture') or diag $err; +is(read_file($sync_log), '', 'full sync passes no filter arguments'); + +($status, $out, $err) = run_helper( + { SYNC_LOG => $sync_log }, '--perl-root', $real_checkout, + '--repository', $upstream, '--sync', '--filter', 'Name.pl', + '--sync-script', $fake_sync, +); +is($status, 0, 'filtered sync invocation succeeds against local fixture') or diag $err; +is(read_file($sync_log), "--only\0Name.pl", 'filtered sync passes exactly one --only argument pair'); + +done_testing(); + +sub run_helper { + my $environment = ref $_[0] eq 'HASH' ? shift : {}; + local %ENV = (%ENV, %$environment); + my $stderr = gensym; + my $pid = open3(undef, my $stdout, $stderr, $^X, $helper, @_); + my $out = do { local $/; <$stdout> // '' }; + my $err = do { local $/; <$stderr> // '' }; + waitpid $pid, 0; + return ($? >> 8, $out, $err); +} + +sub git { + my ($directory, @arguments) = @_; + system 'git', '-C', $directory, @arguments; + die "git @arguments failed\n" if $? != 0; +} + +sub git_dir { + my ($directory, @arguments) = @_; + system 'git', '--git-dir', $directory, @arguments; + die "git --git-dir @arguments failed\n" if $? != 0; +} + +sub git_output { + my ($directory, @arguments) = @_; + open my $pipe, '-|', 'git', '-C', $directory, @arguments or die $!; + my $output = do { local $/; <$pipe> // '' }; + close $pipe or die "git @arguments failed\n"; + $output =~ s/\s+\z//; + return $output; +} + +sub write_file { + my ($path, $contents) = @_; + open my $fh, '>', $path or die "Cannot write $path: $!"; + print {$fh} $contents; + close $fh or die "Cannot close $path: $!"; +} + +sub read_file { + my ($path) = @_; + open my $fh, '<', $path or die "Cannot read $path: $!"; + local $/; + return <$fh> // ''; +} diff --git a/dev/import-perl5/t/update_perl5_latest_branch.t b/dev/import-perl5/t/update_perl5_latest_branch.t new file mode 100644 index 0000000000..080f3fcfb9 --- /dev/null +++ b/dev/import-perl5/t/update_perl5_latest_branch.t @@ -0,0 +1,103 @@ +#!/usr/bin/env perl +use strict; +use warnings; +use Cwd qw(abs_path); +use File::Spec; +use File::Temp qw(tempdir); +use FindBin; +use IPC::Open3; +use Symbol qw(gensym); +use Test::More; + +my $helper = abs_path(File::Spec->catfile($FindBin::Bin, '..', 'update_perl5.pl')); +my $tmp = tempdir('perlonjava-perl5-latest-XXXXXX', TMPDIR => 1, CLEANUP => 1); +my $seed = File::Spec->catdir($tmp, 'seed'); +my $upstream = File::Spec->catdir($tmp, 'upstream.git'); +my $checkout = File::Spec->catdir($tmp, 'checkout'); + +git($tmp, 'init', '-q', $seed); +git($seed, 'config', 'user.name', 'Import Test'); +git($seed, 'config', 'user.email', 'import-test@example.invalid'); +write_file(File::Spec->catfile($seed, 'tracked.txt'), "blead one\n"); +git($seed, 'add', 'tracked.txt'); +git($seed, 'commit', '-q', '-m', 'blead initial'); +git($seed, 'branch', '-M', 'blead'); +git($tmp, 'init', '-q', '--bare', $upstream); +git($seed, 'remote', 'add', 'origin', $upstream); +git($seed, 'push', '-q', '-u', 'origin', 'blead'); +git_dir($upstream, 'symbolic-ref', 'HEAD', 'refs/heads/blead'); + +my ($status, $out, $err) = run_helper( + '--perl-root', $checkout, + '--repository', $upstream, +); +is($status, 0, 'default upstream branch is accepted') or diag $err; + +git($seed, 'checkout', '-q', '-b', 'maint'); +write_file(File::Spec->catfile($seed, 'tracked.txt'), "maint one\n"); +git($seed, 'add', 'tracked.txt'); +git($seed, 'commit', '-q', '-m', 'maint initial'); +git($seed, 'push', '-q', '-u', 'origin', 'maint'); +git($checkout, 'fetch', '-q', 'origin', 'maint:refs/remotes/origin/maint'); +git($checkout, 'checkout', '-q', '-b', 'maint', '--track', 'origin/maint'); + +git($seed, 'checkout', '-q', 'blead'); +write_file(File::Spec->catfile($seed, 'latest.txt'), "latest\n"); +git($seed, 'add', 'latest.txt'); +git($seed, 'commit', '-q', '-m', 'latest blead'); +git($seed, 'push', '-q'); + +my $head_before = git_output($checkout, 'rev-parse', 'HEAD'); +my $tracking_before = git_output($checkout, 'rev-parse', 'origin/blead'); +($status, $out, $err) = run_helper( + '--perl-root', $checkout, + '--repository', $upstream, +); +isnt($status, 0, 'clean maintenance branch is refused'); +like($err, qr/branch maint is not the latest upstream branch blead/, + 'refusal identifies the remote default branch'); +is(git_output($checkout, 'symbolic-ref', '--short', 'HEAD'), 'maint', + 'helper does not switch branches'); +is(git_output($checkout, 'rev-parse', 'HEAD'), $head_before, + 'helper does not move the maintenance checkout'); +is(git_output($checkout, 'rev-parse', 'origin/blead'), $tracking_before, + 'non-default branch is refused before fetch'); + +done_testing; + +sub run_helper { + my $stderr = gensym; + my $pid = open3(undef, my $stdout, $stderr, $^X, $helper, @_); + my $out = do { local $/; <$stdout> // '' }; + my $err = do { local $/; <$stderr> // '' }; + waitpid $pid, 0; + return ($? >> 8, $out, $err); +} + +sub git { + my ($directory, @arguments) = @_; + system 'git', '-C', $directory, @arguments; + die "git @arguments failed\n" if $? != 0; +} + +sub git_dir { + my ($directory, @arguments) = @_; + system 'git', '--git-dir', $directory, @arguments; + die "git --git-dir @arguments failed\n" if $? != 0; +} + +sub git_output { + my ($directory, @arguments) = @_; + open my $pipe, '-|', 'git', '-C', $directory, @arguments or die $!; + my $output = do { local $/; <$pipe> // '' }; + close $pipe or die "git @arguments failed\n"; + $output =~ s/\s+\z//; + return $output; +} + +sub write_file { + my ($path, $contents) = @_; + open my $fh, '>', $path or die "Cannot write $path: $!"; + print {$fh} $contents; + close $fh or die "Cannot close $path: $!"; +} diff --git a/dev/import-perl5/update_perl5.pl b/dev/import-perl5/update_perl5.pl new file mode 100644 index 0000000000..984ca8b127 --- /dev/null +++ b/dev/import-perl5/update_perl5.pl @@ -0,0 +1,139 @@ +#!/usr/bin/env perl +use strict; +use warnings; +use Cwd qw(abs_path getcwd); +use File::Spec; +use FindBin; +use Getopt::Long qw(GetOptions); + +my $project_root = abs_path(File::Spec->catdir($FindBin::Bin, '..', '..')); +my $perl_root = File::Spec->catdir($project_root, 'perl5'); +my $repository = $ENV{PERL5_REPOSITORY} // 'https://github.com/Perl/perl5.git'; +my $sync_script = File::Spec->catfile($project_root, 'dev', 'import-perl5', 'sync.pl'); +my $sync = 0; +my $filter; +my $help = 0; +GetOptions( + 'perl-root=s' => \$perl_root, + 'repository=s' => \$repository, + 'sync-script=s' => \$sync_script, + 'sync' => \$sync, + 'filter=s' => \$filter, + 'help' => \$help, +) or usage(2); +usage(0) if $help; +die "--filter requires --sync\n" if defined $filter && !$sync; +die "--filter must be non-empty\n" if defined $filter && !length $filter; +$perl_root = File::Spec->rel2abs($perl_root); + +if (!-e $perl_root && !-l $perl_root) { + run('git', 'clone', '--origin', 'origin', $repository, $perl_root); +} else { + die "$perl_root is not a Git checkout\n" + unless -d $perl_root && -d File::Spec->catdir($perl_root, '.git'); +} + +my $dirty = capture('git', '-C', $perl_root, 'status', '--porcelain', '--untracked-files=no'); +die "Refusing to update $perl_root: tracked local changes exist\n" if length $dirty; +my $branch = capture_line('git', '-C', $perl_root, 'symbolic-ref', '--quiet', '--short', 'HEAD'); +die "Refusing to update $perl_root: detached HEAD\n" unless length $branch; +my $upstream = capture_line('git', '-C', $perl_root, 'rev-parse', '--abbrev-ref', '--symbolic-full-name', '@{upstream}'); +die "Refusing to update $perl_root: branch $branch has no upstream\n" unless length $upstream; +my ($remote) = split m{/}, $upstream, 2; +die "Refusing to update $perl_root: invalid upstream $upstream\n" unless defined $remote && length $remote; +my $remote_url = capture_line('git', '-C', $perl_root, 'remote', 'get-url', $remote); +die "Refusing to update $perl_root: upstream remote $remote_url does not match $repository\n" + unless normalized_repository($remote_url) eq normalized_repository($repository); +my $latest_branch = remote_default_branch($perl_root, $remote); +die "Refusing to update $perl_root: checked-out branch $branch is not the latest upstream branch $latest_branch\n" + unless $branch eq $latest_branch; +die "Refusing to update $perl_root: upstream $upstream does not track $remote/$latest_branch\n" + unless $upstream eq "$remote/$latest_branch"; + +run('git', '-C', $perl_root, 'fetch', $remote); +unless (succeeds('git', '-C', $perl_root, 'merge-base', '--is-ancestor', 'HEAD', $upstream)) { + die "Refusing to update $perl_root: $upstream is not a fast-forward of HEAD\n"; +} +run('git', '-C', $perl_root, 'merge', '--ff-only', $upstream); +my $commit = capture_line('git', '-C', $perl_root, 'rev-parse', 'HEAD'); +print "Perl upstream commit: $commit\n"; + +if ($sync) { + my @command = ($^X, $sync_script); + push @command, '--only', $filter if defined $filter; + my $old = getcwd(); + chdir $project_root or die "Cannot enter $project_root: $!\n"; + run(@command); + chdir $old or die "Cannot restore $old: $!\n"; +} + +sub normalized_repository { + my ($value) = @_; + $value =~ s{\Agit\@github\.com:}{https://github.com/}i; + $value =~ s{\Assh://git\@github\.com/}{https://github.com/}i; + $value =~ s{/+\z}{}; + $value =~ s{\.git\z}{}; + return $value; +} + +sub remote_default_branch { + my ($checkout, $remote) = @_; + my $advertisement = capture('git', '-C', $checkout, 'ls-remote', '--symref', $remote, 'HEAD'); + my ($branch) = $advertisement =~ /^ref:\s+refs\/heads\/(\S+)\s+HEAD$/m; + die "Refusing to update $checkout: cannot determine the latest branch advertised by $remote\n" + unless defined $branch && length $branch; + return $branch; +} + +sub run { + my (@command) = @_; + print '+ ', join(' ', map { quote($_) } @command), "\n"; + system @command; + die "Command failed (exit " . ($? >> 8) . "): $command[0]\n" if $? != 0; +} + +sub succeeds { + my (@command) = @_; + print '+ ', join(' ', map { quote($_) } @command), "\n"; + system @command; + return $? == 0; +} + +sub capture { + my (@command) = @_; + open my $pipe, '-|', @command or die "Cannot run $command[0]: $!\n"; + local $/; + my $output = <$pipe> // ''; + close $pipe or return ''; + return $output; +} + +sub capture_line { + my (@command) = @_; + my $value = capture(@command); + $value =~ s/\s+\z//; + return $value; +} + +sub quote { + my ($value) = @_; + return $value if $value =~ /\A[-A-Za-z0-9_.\/:\@]+\z/; + $value =~ s/'/'"'"'/g; + return "'$value'"; +} + +sub usage { + my ($status) = @_; + print <<'USAGE'; +Usage: perl dev/import-perl5/update_perl5.pl [options] + --perl-root PATH checkout path (default: ./perl5) + --repository URL expected upstream repository + --sync-script PATH sync implementation (default: dev/import-perl5/sync.pl) + --sync run the complete import manifest after updating + --filter TEXT pass exactly one --only filter to sync.pl (requires --sync) + +Existing checkouts must be on the branch advertised as the repository's HEAD. +The helper never switches branches; it refuses non-default branches instead. +USAGE + exit $status; +} diff --git a/dev/prompts/alternation-capture-issue-analysis.md b/dev/prompts/alternation-capture-issue-analysis.md index 25960f0536..6da21accdf 100644 --- a/dev/prompts/alternation-capture-issue-analysis.md +++ b/dev/prompts/alternation-capture-issue-analysis.md @@ -1,5 +1,9 @@ # Alternation Capture Issue - Deep Dive Analysis +> **Historical analysis:** This predates the Phase 36 Joni cutover. Its Java +> `Matcher` comparisons explain the retired backend and are not claims about +> current production matching, which uses the vendored Joni fork exclusively. + ## Date 2025-10-07 diff --git a/dev/prompts/conditional-pattern-transformation-strategy.md b/dev/prompts/conditional-pattern-transformation-strategy.md index 869b9ae7c8..3f31313a7a 100644 --- a/dev/prompts/conditional-pattern-transformation-strategy.md +++ b/dev/prompts/conditional-pattern-transformation-strategy.md @@ -1,5 +1,9 @@ # Conditional Pattern Transformation Strategy +> **Historical strategy:** This predates the Phase 36 Joni cutover. Production +> conditionals are parsed and matched natively by the vendored Joni fork; the +> Java `Pattern` transformations below are retained only as design history. + ## Discovery Java regex does NOT support `(?(condition)yes|no)` syntax - it throws "Unknown inline modifier" error. diff --git a/dev/tools/README.md b/dev/tools/README.md index f228647e5b..5078cd27ba 100644 --- a/dev/tools/README.md +++ b/dev/tools/README.md @@ -22,6 +22,79 @@ lane, while `pat_psycho*` and `speed*` run afterward in a dedicated lane controlled by `--cpu-heavy-jobs` (default 2). This permits useful CPU parallelism without making their watchdogs contend with `pat*`. +### generate_regex_test_ledger.pl +**Purpose:** Derive the current Phase 36 regex corpus without a hand-maintained +file list or pinned Perl revision. + +The tool includes every current `perl5_t/t/re/*.t` file, scans `op/` and `uni/` +for regex-bearing tests, resolves test references from the feature matrix, +Phase 36 plan, and comparison policy, and records direct/thread pairs and unit +gates separately. It emits canonical JSON plus an optional one-path-per-line +runner list: + +```bash +perl dev/tools/generate_regex_test_ledger.pl \ + --runner-list /tmp/phase36-regex-files.txt \ + --output /tmp/phase36-regex-ledger.json +``` + +Use the same list to compare only those exact identities against a broader +historical runner log: + +```bash +perl dev/tools/compare_test_results.pl \ + --file-list /tmp/phase36-regex-files.txt \ + baseline.log candidate.json +``` + +The generated counts describe the current latest upstream checkout. Refresh +comparisons may record hashes for that run, but they must not encode a +historical Perl revision as the expected corpus. + +### run_phase36_regex_acceptance.pl + +**Purpose:** Compose the Phase 36 current-checkout ledger, bounded JVM and +interpreter runner legs, PR-958-normalized fail-closed comparisons, and exact +Joni packaging check into one immutable-artifact manifest. It records the +starting/final clean tracked-source state, current `perl5/` SHA as provenance, +and the bounded `jperl -v` injected SHA matched to that source, along with +list-form commands, exit statuses, counts, and SHA-256s for retained artifacts. + +The coordinator runs the real corpus only after creating the exact JAR/SBOM. +Workers use `--prepare-only` with injected fake tool paths to test the +composition without starting the corpus; the real invocation is: + +```bash +perl dev/tools/run_phase36_regex_acceptance.pl \ + --baseline logs/test_20260815_080000_958.log \ + --artifact-dir /tmp/phase36-acceptance \ + --jar target/perlonjava-standalone.jar --sbom build/reports/sbom.json +``` + +### verify-joni-packaging.pl + +**Purpose:** Fail closed on the final standalone JAR/SBOM boundary. The +two-argument verifier checks relocated Joni/JCodings class ownership, exact +checked-in notice bytes, unique Joni/JCodings CycloneDX identities, and the +declared Joni-to-JCodings dependency edge. It resolves notice sources relative +to the repository, so it may run from an artifact directory: + +```bash +perl dev/tools/verify-joni-packaging.pl standalone.jar merged-sbom.json +``` + +For a system-Perl oracle of an imported core test, remember that `t/test.pl` +replaces `@INC` with the imported `../lib`. Preload host-core modules needed by +the test before that reset. For example, the reproducible `op/do.t` oracle is: + +```bash +cd perl5_t/t +perl -Mstrict -MErrno -MPerlIO -MPerlIO::scalar op/do.t +``` + +This distinguishes a real TAP count from a zero-TAP host-module startup error; +it does not patch or otherwise modify the imported test. + ### reorganize_tests.sh **Purpose:** Reorganize test directory structure to separate PerlOnJava unit tests from standard Perl module tests. diff --git a/dev/tools/check_test_manifest.pl b/dev/tools/check_test_manifest.pl index 522f70c1a7..fa9a55e1b5 100644 --- a/dev/tools/check_test_manifest.pl +++ b/dev/tools/check_test_manifest.pl @@ -15,7 +15,7 @@ my ($expected, $path) = $line =~ /^([0-9a-f]{64})\s{2}(.+)$/ or die "Malformed manifest line $. in $manifest\n"; if (!-f $path) { - warn "Missing pinned test source: $path\n"; + warn "Missing manifest test source: $path\n"; $failed = 1; next; } @@ -23,7 +23,7 @@ binmode $source; my $actual = Digest::SHA->new(256)->addfile($source)->hexdigest; if ($actual ne $expected) { - warn "Pinned test source differs: $path\n"; + warn "Manifest test source differs: $path\n"; $failed = 1; } } diff --git a/dev/tools/compare_test_logs.pl b/dev/tools/compare_test_logs.pl index 40cfd61a50..924a405a42 100755 --- a/dev/tools/compare_test_logs.pl +++ b/dev/tools/compare_test_logs.pl @@ -2,6 +2,7 @@ use strict; use warnings; use Getopt::Long; +use FindBin; =head1 NAME @@ -21,6 +22,8 @@ =head1 SYNOPSIS --normalize-pr958-artifacts Normalize two exact, independently reconstructed PR 958 transcript artifacts; raw counts are printed + --strict-acceptance Run the fail-closed PR-958 acceptance comparison + --output FILE Write strict-acceptance JSON evidence to FILE --sort-by FIELD Sort by: name, diff, before, after (default: diff) --help Show this help message @@ -51,6 +54,8 @@ =head1 EXAMPLES my $help = 0; my $show_flakes = 0; # Set --show-flakes to include known-flake files in regression list my $normalize_pr958_artifacts = 0; +my $strict_acceptance = 0; +my $output_file; my @artifact_normalizations; # These are exact transcript signatures, not a file-level whitelist. They are @@ -118,6 +123,8 @@ =head1 EXAMPLES 'sort-by=s' => \$sort_by, 'show-flakes!' => \$show_flakes, 'normalize-pr958-artifacts!' => \$normalize_pr958_artifacts, + 'strict-acceptance!' => \$strict_acceptance, + 'output=s' => \$output_file, 'help|h' => \$help, ) or die "Error in command line arguments\n"; @@ -137,6 +144,10 @@ =head1 EXAMPLES --normalize-pr958-artifacts Normalize exact PR 958 transcript signatures and show both raw and normalized counts + --strict-acceptance Run the fail-closed PR-958 gate: reject regressions, + missing files, execution errors, timeout, zero TAP, + truncated/incomplete TAP, and malformed input + --output FILE Save strict-acceptance machine-readable JSON evidence --sort-by FIELD Sort by: name, diff, before, after (default: diff) --help Show this help message @@ -150,6 +161,17 @@ =head1 EXAMPLES my ($old_log, $new_log) = @ARGV; +if ($strict_acceptance) { + my @command = ($^X, "$FindBin::Bin/compare_test_results.pl", + '--fail-on-regression', '--fail-on-invalid', + '--normalize-pr958-artifacts'); + push @command, ('--output', $output_file) if defined $output_file; + push @command, $old_log, $new_log; + system @command; + die "Cannot execute strict acceptance comparator: $!\n" if $? == -1; + exit($? >> 8); +} + # Parse a log file and extract test results sub parse_log { my ($file, $side) = @_; diff --git a/dev/tools/compare_test_results.pl b/dev/tools/compare_test_results.pl index cd911a302b..02316c5fcb 100644 --- a/dev/tools/compare_test_results.pl +++ b/dev/tools/compare_test_results.pl @@ -11,6 +11,8 @@ my $expected_files; my $output_file; my $path_prefix; +my $file_list; +my $normalize_pr958_artifacts = 0; my $help = 0; GetOptions( 'fail-on-regression!' => \$fail_on_regression, @@ -18,21 +20,30 @@ 'expected-files=i' => \$expected_files, 'output=s' => \$output_file, 'path-prefix=s' => \$path_prefix, + 'file-list=s' => \$file_list, + 'normalize-pr958-artifacts!' => \$normalize_pr958_artifacts, 'help' => \$help, ) or usage(2); usage(0) if $help; my ($baseline_file, $candidate_file) = @ARGV; usage(2) unless defined $baseline_file && defined $candidate_file && @ARGV == 2; +die "--path-prefix and --file-list are mutually exclusive\n" + if defined $path_prefix && defined $file_list; -my $baseline = load_results($baseline_file); -my $candidate = load_results($candidate_file); +my $baseline = load_results($baseline_file, 'baseline'); +my $candidate = load_results($candidate_file, 'candidate'); if (defined $path_prefix) { $path_prefix = canonical_file($path_prefix); - $path_prefix .= '/' unless $path_prefix =~ m{/$}; + $path_prefix .= '/' unless $path_prefix =~ m{/$} || $path_prefix =~ /\.t\z/; $baseline = filter_results($baseline, $path_prefix); $candidate = filter_results($candidate, $path_prefix); } +if (defined $file_list) { + my $selected = load_file_list($file_list); + $baseline = filter_results_by_file($baseline, $selected); + $candidate = filter_results_by_file($candidate, $selected); +} my $comparison = compare_results($baseline, $candidate); $comparison->{expected_files} = $expected_files if defined $expected_files; @@ -58,14 +69,18 @@ sub usage { zero-TAP results, or an --expected-files mismatch --expected-files NUM Require exactly NUM candidate files --output FILE Save the normalized comparison as JSON - --path-prefix PATH Compare only files below this canonical path + --path-prefix PATH Compare one test file or files below a canonical path + --file-list FILE Compare only exact test paths listed one per line + --normalize-pr958-artifacts + Normalize the two exact reconstructed PR-958 baseline + transcript signatures and retain raw counts in JSON --help Show this help USAGE exit $status; } sub load_results { - my ($path) = @_; + my ($path, $side) = @_; open my $fh, '<:raw', $path or die "Cannot open $path: $!\n"; my $content = do { local $/; <$fh> }; close $fh; @@ -85,30 +100,66 @@ sub load_results { my %normalized; for my $file (keys %{$document->{results}}) { my $result = $document->{results}{$file}; - $normalized{canonical_file($file)} = { + my $entry = { ok => 0 + ($result->{ok_count} // 0), total => 0 + ($result->{total_tests} // 0), status => $result->{status} // 'unknown', + planned => 0 + ($result->{planned_tests} // $result->{total_tests} // 0), + actual => 0 + ($result->{actual_tests_run} // $result->{total_tests} // 0), + incomplete => 0 + ($result->{incomplete_tests} // 0), + exit_code => 0 + ($result->{exit_code} // 0), }; + normalize_pr958_artifact(canonical_file($file), $entry, $side); + $normalized{canonical_file($file)} = $entry; } return \%normalized; } my %results; for my $line (split /\n/, $content) { - next unless $line =~ /^\[\s*\d+\/\d+\]\s+(\S+)\s+\.\.\.\s+\S+\s+(\d+)\/(\d+)\s+ok\b/; - my ($file, $ok, $total) = ($1, $2, $3); - $results{canonical_file($file)} = { + next unless $line =~ /^\[\s*\d+\/\d+\]\s+(\S+)\s+\.\.\.\s+(\S+)\s+(\d+)\/(\d+)\s+ok\b/; + my ($file, $marker, $ok, $total) = ($1, $2, $3, $4); + my %status_for = ( + 'T' => 'timeout', 'I' => 'incomplete', '!' => 'error', + '?' => 'unknown', + ); + my $entry = { ok => 0 + $ok, total => 0 + $total, - status => $ok == $total ? 'pass' : 'partial', + status => $status_for{$marker} // ($ok == $total ? 'pass' : 'partial'), + planned => 0 + $total, + actual => 0 + $total, + incomplete => $marker eq 'I' ? 1 : 0, + exit_code => $marker eq '!' || $marker eq 'T' ? 1 : 0, }; + normalize_pr958_artifact(canonical_file($file), $entry, $side); + $results{canonical_file($file)} = $entry; } die "Captured runner log $path contains no per-file result lines\n" unless keys %results; return \%results; } +sub normalize_pr958_artifact { + my ($file, $entry, $side) = @_; + return unless $normalize_pr958_artifacts; + my %artifacts = ( + 'perl5_t/t/op/do.t|94|99' => [68, 71, + 'PR 958 duplicated its first 28 TAP assertions'], + 'perl5_t/t/japh/abigail.t|110|130' => [109, 130, + 'PR 958 logged one irreproducible extra pass'], + ); + my $artifact = $artifacts{join('|', $file, $entry->{ok}, $entry->{total})}; + return unless $artifact; + $entry->{raw_ok} = $entry->{ok}; + $entry->{raw_total} = $entry->{total}; + $entry->{normalization} = $artifact->[2]; + ($entry->{ok}, $entry->{total}) = @{$artifact}[0, 1]; + $entry->{planned} = $entry->{total}; + $entry->{actual} = $entry->{total}; + $entry->{normalization_side} = $side; +} + sub canonical_file { my ($file) = @_; $file =~ s{\\}{/}g; @@ -125,10 +176,32 @@ sub filter_results { return \%filtered; } +sub load_file_list { + my ($path) = @_; + open my $fh, '<:raw', $path or die "Cannot open file list $path: $!\n"; + my %selected; + while (my $line = <$fh>) { + $line =~ s/\r?\n\z//; + $line =~ s/^\s+|\s+$//g; + next if $line eq '' || $line =~ /^#/; + $selected{canonical_file($line)} = 1; + } + close $fh or die "Cannot close file list $path: $!\n"; + die "File list $path contains no test paths\n" unless keys %selected; + return \%selected; +} + +sub filter_results_by_file { + my ($results, $selected) = @_; + my %filtered = map { $_ => $results->{$_} } + grep { $selected->{$_} } keys %$results; + return \%filtered; +} + sub compare_results { my ($baseline, $candidate) = @_; my (@regressions, @improvements, @plan_changes, @missing, @added, - @execution_issues, @zero_tap); + @execution_issues, @zero_tap, @truncated); my ($baseline_ok, $candidate_ok, $baseline_total, $candidate_total) = (0, 0, 0, 0); $baseline_ok += $_->{ok} for values %$baseline; @@ -144,11 +217,19 @@ sub compare_results { status => $result->{status}, ok => $result->{ok}, total => $result->{total}, - } if $result->{status} =~ /\A(?:error|timeout|incomplete)\z/; + } if $result->{status} !~ /\A(?:pass|partial|fail)\z/ + || $result->{exit_code}; push @zero_tap, { file => $file, status => $result->{status}, } if $result->{total} == 0; + push @truncated, { + file => $file, + planned => $result->{planned}, + actual => $result->{actual}, + incomplete => $result->{incomplete}, + } if $result->{incomplete} + || ($result->{planned} > 0 && $result->{actual} < $result->{planned}); } for my $file (sort keys %all) { my ($before, $after) = ($baseline->{$file}, $candidate->{$file}); @@ -190,6 +271,7 @@ sub compare_results { added_files => \@added, execution_issues => \@execution_issues, zero_tap => \@zero_tap, + truncated => \@truncated, }; } @@ -200,11 +282,12 @@ sub print_report { print "Candidate: $candidate_file\n"; printf "Passing assertions: %d/%d -> %d/%d (%+d passing, %+d planned)\n", @{$summary}{qw(baseline_ok baseline_total candidate_ok candidate_total delta_ok delta_total)}; - printf "Files: %d -> %d; regressions=%d improvements=%d missing=%d added=%d execution-issues=%d zero-TAP=%d\n", + printf "Files: %d -> %d; regressions=%d improvements=%d missing=%d added=%d execution-issues=%d zero-TAP=%d truncated=%d\n", $summary->{baseline_files}, $summary->{candidate_files}, scalar(@{$comparison->{regressions}}), scalar(@{$comparison->{improvements}}), scalar(@{$comparison->{missing_files}}), scalar(@{$comparison->{added_files}}), - scalar(@{$comparison->{execution_issues}}), scalar(@{$comparison->{zero_tap}}); + scalar(@{$comparison->{execution_issues}}), scalar(@{$comparison->{zero_tap}}), + scalar(@{$comparison->{truncated}}); if (defined $comparison->{expected_files} && $summary->{candidate_files} != $comparison->{expected_files}) { printf "EXPECTED FILE COUNT MISMATCH: expected %d, found %d\n", @@ -232,6 +315,12 @@ sub print_report { printf " %s: status=%s\n", @{$_}{qw(file status)} for @{$comparison->{zero_tap}}; } + if (@{$comparison->{truncated}}) { + print "\nTRUNCATED OR INCOMPLETE TAP\n"; + printf " %s: planned=%d actual=%d incomplete=%d\n", + @{$_}{qw(file planned actual incomplete)} + for @{$comparison->{truncated}}; + } } sub has_invalid_candidate { @@ -239,6 +328,7 @@ sub has_invalid_candidate { return 1 if @{$comparison->{missing_files}}; return 1 if @{$comparison->{execution_issues}}; return 1 if @{$comparison->{zero_tap}}; + return 1 if @{$comparison->{truncated}}; return 1 if defined($required_files) && $comparison->{summary}{candidate_files} != $required_files; return 0; diff --git a/dev/tools/extract_regex_pod_inventory.pl b/dev/tools/extract_regex_pod_inventory.pl new file mode 100644 index 0000000000..c0d0a96d56 --- /dev/null +++ b/dev/tools/extract_regex_pod_inventory.pl @@ -0,0 +1,22 @@ +#!/usr/bin/env perl +use strict; +use warnings; +use File::Spec; +use FindBin; + +my $root = File::Spec->rel2abs(File::Spec->catdir($FindBin::Bin, '..', '..')); +my $perl_root = $ENV{PERLONJAVA_PERL_ROOT} // File::Spec->catdir($root, 'perl5'); +my @pods = qw(perlreref.pod perlrecharclass.pod perlrequick.pod perlrepository.pod perlre.pod perlretut.pod perlrebackslash.pod); +for my $pod (@pods) { + my $path = File::Spec->catfile($perl_root, 'pod', $pod); + open my $fh, '<', $path or die "Cannot read $path: $!\n"; + my (@headings, %constructs); + while (my $line = <$fh>) { + push @headings, $1 if $line =~ /^=head\d\s+(.+)/; + $constructs{$1}++ while $line =~ /(\(\?[^\s)]+|\(\*[^\s)]+|\\[pPNKkQERX])/g; + } + close $fh; + print "FILE\t$pod\n"; + print "HEADING\t$_\n" for @headings; + print "CONSTRUCT\t$_\n" for sort keys %constructs; +} diff --git a/dev/tools/generate_perl_unicode_data.pl b/dev/tools/generate_perl_unicode_data.pl index 7ce60d6194..a558c2ffd5 100644 --- a/dev/tools/generate_perl_unicode_data.pl +++ b/dev/tools/generate_perl_unicode_data.pl @@ -15,6 +15,7 @@ my $check = 0; my $list = 0; +my $refresh = 0; my @only; my $unicode_root; my $perl_root; @@ -24,6 +25,7 @@ GetOptions( 'check' => \$check, 'list' => \$list, + 'refresh' => \$refresh, 'only=s@' => \@only, 'unicode-root=s' => \$unicode_root, 'perl-root=s' => \$perl_root, @@ -32,11 +34,18 @@ 'help' => \$help, ) or usage(2); usage(0) if $help; +die "--refresh cannot be combined with --check or --list\n" if $refresh && ($check || $list); my $root = defined $root_override ? File::Spec->rel2abs($root_override) : repo_root($FindBin::Bin); my $manifest = decode_json(read_raw($manifest_path)); +my $schema_version = $manifest->{schema_version} // 0; die "$manifest_path has unsupported schema_version\n" - unless ($manifest->{schema_version} // 0) == 1; + unless $schema_version == 1 || $schema_version == 2; +my $current_checkout = $schema_version == 2 + && ($manifest->{perl_source_policy} // '') eq 'current-checkout'; +die "$manifest_path schema 2 requires perl_source_policy current-checkout\n" + if $schema_version == 2 && !$current_checkout; +die "--refresh requires schema 2 current-checkout provenance\n" if $refresh && !$current_checkout; my @entries = @{$manifest->{generators} // []}; die "$manifest_path defines no generators\n" unless @entries; @@ -102,16 +111,34 @@ version => $manifest->{unicode_version}, required => \@required, ); +if ($refresh) { + $manifest->{version_sha256} = sha256_hex(read_raw(File::Spec->catfile($unicode_root, 'version'))); + for my $entry (@entries) { + for my $field ('sources', 'perl_sources') { + my $base = $field eq 'sources' ? $unicode_root : ($perl_root // select_perl_root(repo_root => $root, unicode_root => $unicode_root, required => [keys %{$entry->{$field} // {}}])); + for my $relative (keys %{$entry->{$field} // {}}) { + $entry->{$field}{$relative} = sha256_hex(read_raw(File::Spec->catfile($base, split m{/}, $relative))); + } + } + } + for my $relative (keys %{$manifest->{shared_sources} // {}}) { + $manifest->{shared_sources}{$relative} = sha256_hex(read_raw(File::Spec->catfile($unicode_root, split m{/}, $relative))); + } + %source_hash = (%{$manifest->{shared_sources} // {}}); + %perl_source_hash = (); + for my $entry (@entries) { + $source_hash{$_} = $entry->{sources}{$_} for keys %{$entry->{sources} // {}}; + $perl_source_hash{$_} = $entry->{perl_sources}{$_} for keys %{$entry->{perl_sources} // {}}; + } +} read_unicode_version( path => File::Spec->catfile($unicode_root, 'version'), expected => $manifest->{unicode_version}, sha256 => $manifest->{version_sha256}, ); for my $relative (sort keys %source_hash) { - read_pinned_source( - path => File::Spec->catfile($unicode_root, split m{/}, $relative), - sha256 => $source_hash{$relative}, - ); + read_pinned_source(path => File::Spec->catfile($unicode_root, split m{/}, $relative), + sha256 => $source_hash{$relative}); } if (%perl_source_hash) { $perl_root //= select_perl_root( @@ -120,10 +147,21 @@ required => [sort keys %perl_source_hash], ); for my $relative (sort keys %perl_source_hash) { - read_pinned_source( - path => File::Spec->catfile($perl_root, split m{/}, $relative), - sha256 => $perl_source_hash{$relative}, - ); + read_pinned_source(path => File::Spec->catfile($perl_root, split m{/}, $relative), + sha256 => $perl_source_hash{$relative}); + } +} +if ($current_checkout) { + my $actual_commit = checkout_identity($perl_root, 'rev-parse', 'HEAD'); + my $actual_version = perl_language_version($perl_root); + if ($refresh) { + $manifest->{perl_commit} = $actual_commit; + $manifest->{perl_version} = $actual_version; + } else { + die "Perl checkout revision mismatch: expected $manifest->{perl_commit}, found $actual_commit\n" + unless ($manifest->{perl_commit} // '') eq $actual_commit; + die "Perl checkout version mismatch: expected $manifest->{perl_version}, found $actual_version\n" + unless ($manifest->{perl_version} // '') eq $actual_version; } } @@ -140,7 +178,8 @@ unless $first eq $second; my $actual_hash = sha256_hex($first); die "$entry->{name} generated SHA-256 mismatch: expected $entry->{output_sha256}, found $actual_hash\n" - unless $actual_hash eq $entry->{output_sha256}; + unless $refresh || $actual_hash eq $entry->{output_sha256}; + $entry->{output_sha256} = $actual_hash if $refresh; my $current = -f $output ? read_raw($output) : undef; if (defined $current && $current eq $first) { @@ -156,6 +195,7 @@ } exit 1 if $failed; +my @staged; for my $item (@publication) { my ($entry, $output, $bytes, $hash) = @$item; my $directory = dirname($output); @@ -165,9 +205,23 @@ close $temporary or die "Cannot close $temporary_path: $!\n"; die "$entry->{name} staged SHA-256 changed before publication\n" unless sha256_hex(read_raw($temporary_path)) eq $hash; + push @staged, [$entry, $output, $temporary_path, $hash]; +} +my $manifest_temporary_path; +if ($refresh) { + my ($temporary, $temporary_path) = tempfile('.unicode-manifest-XXXXXX', DIR => dirname($manifest_path), UNLINK => 0); + print {$temporary} JSON::PP->new->canonical->pretty->encode($manifest) or die "Cannot write $temporary_path: $!\n"; + close $temporary or die "Cannot close $temporary_path: $!\n"; + $manifest_temporary_path = $temporary_path; +} +for my $item (@staged) { + my ($entry, $output, $temporary_path, $hash) = @$item; rename $temporary_path, $output or die "Cannot publish $output: $!\n"; print "$entry->{name}: updated ($hash)\n"; } +if ($refresh) { + rename $manifest_temporary_path, $manifest_path or die "Cannot publish $manifest_path: $!\n"; +} sub run_generator { my ($script, $source_root, $pinned_perl_root) = @_; @@ -195,14 +249,37 @@ sub safe_relative_path { return $path; } +sub checkout_identity { + my ($root, @arguments) = @_; + open my $pipe, '-|', 'git', '-C', $root, @arguments + or die "Cannot inspect Perl checkout $root: $!\n"; + my $value = <$pipe> // ''; + close $pipe or die "Cannot inspect Perl checkout $root\n"; + chomp $value; + die "Perl checkout $root has no Git identity\n" unless length $value; + return $value; +} + +sub perl_language_version { + my ($root) = @_; + my $text = read_raw(File::Spec->catfile($root, 'patchlevel.h')); + my ($revision) = $text =~ /^#define\s+PERL_REVISION\s+(\d+)/m; + my ($version) = $text =~ /^#define\s+PERL_VERSION\s+(\d+)/m; + my ($subversion) = $text =~ /^#define\s+PERL_SUBVERSION\s+(\d+)/m; + die "Cannot derive Perl language version from $root/patchlevel.h\n" + unless defined $revision && defined $version && defined $subversion; + return join '.', $revision, $version, $subversion; +} + sub usage { my ($exit) = @_; print <<'USAGE'; Usage: perl dev/tools/generate_perl_unicode_data.pl [options] --check verify generated files without changing them + --refresh regenerate outputs and transactionally refresh schema-2 provenance --only NAME process one named generator (repeatable) --unicode-root PATH use an explicit Perl unicore source directory - --perl-root PATH use an explicit pinned Perl source checkout + --perl-root PATH use an explicit selected/current Perl source checkout --root PATH resolve manifest paths under PATH (testing/automation) --list list the complete generated-data inventory --help show this help diff --git a/dev/tools/generate_perl_unicode_scalar_name_data.pl b/dev/tools/generate_perl_unicode_scalar_name_data.pl new file mode 100644 index 0000000000..49bd7ad7a9 --- /dev/null +++ b/dev/tools/generate_perl_unicode_scalar_name_data.pl @@ -0,0 +1,175 @@ +#!/usr/bin/env perl +use strict; +use warnings; +use Digest::SHA qw(sha256_hex); +use Encode qw(encode); +use File::Spec; +use FindBin; +use MIME::Base64 qw(encode_base64); + +# Unicode data source copyright: +# © 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 + +my $repo_root = File::Spec->rel2abs(File::Spec->catdir($FindBin::Bin, '..', '..')); +my $source = $ENV{PERLONJAVA_NAME_PL} + // File::Spec->catfile($repo_root, 'src', 'main', 'perl', 'lib', 'unicore', 'Name.pl'); +open my $source_fh, '<:raw', $source or die "Cannot read $source: $!\n"; +local $/; +my $source_text = <$source_fh>; +close $source_fh or die "Cannot close $source: $!\n"; +my $source_sha256 = sha256_hex($source_text); +$source_text =~ /return <<'END';\r?\n(.*)\r?\nEND\r?\n?\z/s + or die "$source does not have the expected generated Name.pl format\n"; +my $records = $1; +$records =~ s/\r\n/\n/g; + +my (%first_code_point, @duplicate_names); +for my $record (split /\n\n/, $records) { + my ($code_points, $name, @extra) = split /\n/, $record; + die "Malformed Name.pl record: $record\n" + if !defined $name || @extra || !length $name; + next if $code_points =~ /\s/; # Multi-code-point sequences have a separate owner. + die "Invalid scalar code point '$code_points' for '$name'\n" + unless $code_points =~ /\A[0-9A-F]{5,6}\z/; + die "Non-ASCII or tab character in scalar name '$name'\n" + unless $name =~ /\A[\x20-\x7E]+\z/ && $name !~ /\t/; + if (exists $first_code_point{$name}) { + push @duplicate_names, $name; + next; # Match Name.pl's anchored search: the first name row wins. + } + $first_code_point{$name} = hex $code_points; +} + +my @names = sort keys %first_code_point; +die "Name.pl contains no scalar names\n" unless @names; +my $binary = encode_varint(scalar @names); +my $previous = ''; +for my $name (@names) { + my $prefix_length = common_prefix_length($previous, $name); + my $suffix = substr($name, $prefix_length); + $binary .= encode_varint($prefix_length) + . encode_varint(length $suffix) + . encode_varint($first_code_point{$name}) + . encode('ASCII', $suffix); + $previous = $name; +} +my $encoded = encode_base64($binary, ''); +my @chunks = $encoded =~ /.{1,8000}/g; + +print <<'HEADER'; +/* + * Generated from the current imported Perl unicore/Name.pl. + * Do not edit manually; run dev/tools/generate_perl_unicode_scalar_name_data.pl. + * + * Name.pl is generated by Perl's mktables from the Unicode Character Database. + * Duplicate-name policy matches Perl's anchored table search: the first row wins. + * Distinct names for the same code point are all retained as Unicode aliases. + * + * Unicode data source copyright: + * © 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 + */ +package org.perlonjava.runtime.regex; + +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Base64; + +public final class PerlUnicodeScalarNameData { +HEADER +print " public static final String SOURCE_SHA256 = \"$source_sha256\";\n"; +print " public static final int ENTRY_COUNT = ", scalar(@names), ";\n"; +print " public static final int DUPLICATE_NAME_COUNT = ", scalar(@duplicate_names), ";\n\n"; +print " private static final String[] ENCODED = {\n"; +print qq{ "$_",\n} for @chunks; +print <<'FOOTER'; + }; + + private static final String[] NAMES; + private static final int[] CODE_POINTS; + + static { + byte[] data = Base64.getDecoder().decode(String.join("", ENCODED)); + Cursor cursor = new Cursor(); + int count = readVarint(data, cursor); + if (count != ENTRY_COUNT) { + throw new IllegalStateException("Invalid generated Perl scalar-name count: " + count); + } + NAMES = new String[count]; + CODE_POINTS = new int[count]; + String previous = ""; + for (int index = 0; index < count; index++) { + int prefixLength = readVarint(data, cursor); + int suffixLength = readVarint(data, cursor); + int codePoint = readVarint(data, cursor); + if (prefixLength > previous.length() + || suffixLength > data.length - cursor.offset) { + throw new IllegalStateException("Invalid generated Perl scalar-name data"); + } + String suffix = new String( + data, cursor.offset, suffixLength, StandardCharsets.US_ASCII); + cursor.offset += suffixLength; + String name = previous.substring(0, prefixLength) + suffix; + NAMES[index] = name; + CODE_POINTS[index] = codePoint; + previous = name; + } + if (cursor.offset != data.length) { + throw new IllegalStateException("Trailing generated Perl scalar-name data"); + } + } + + public static int codePoint(String name) { + if (name == null) return -1; + int index = Arrays.binarySearch(NAMES, name); + return index < 0 ? -1 : CODE_POINTS[index]; + } + + static int entryCount() { + return NAMES.length; + } + + private static int readVarint(byte[] data, Cursor cursor) { + int value = 0; + int shift = 0; + while (cursor.offset < data.length && shift < 35) { + int current = data[cursor.offset++] & 0xff; + value |= (current & 0x7f) << shift; + if ((current & 0x80) == 0) return value; + shift += 7; + } + throw new IllegalStateException("Invalid generated Perl scalar-name varint"); + } + + private static final class Cursor { + private int offset; + } + + private PerlUnicodeScalarNameData() { + } +} +FOOTER + +sub common_prefix_length { + my ($left, $right) = @_; + my $limit = length($left) < length($right) ? length($left) : length($right); + my $offset = 0; + $offset++ while $offset < $limit + && substr($left, $offset, 1) eq substr($right, $offset, 1); + return $offset; +} + +sub encode_varint { + my ($value) = @_; + my $encoded = ''; + while ($value >= 0x80) { + $encoded .= chr(($value & 0x7f) | 0x80); + $value >>= 7; + } + return $encoded . chr($value); +} diff --git a/dev/tools/generate_regex_test_ledger.pl b/dev/tools/generate_regex_test_ledger.pl new file mode 100755 index 0000000000..f5140fb2e4 --- /dev/null +++ b/dev/tools/generate_regex_test_ledger.pl @@ -0,0 +1,176 @@ +#!/usr/bin/env perl +use strict; +use warnings; + +use File::Find qw(find); +use File::Spec; +use Getopt::Long qw(GetOptions); +use JSON::PP; + +my $tests_root = 'perl5_t/t'; +my $unit_root = 'src/test/resources/unit'; +my @references; +my $runner_list; +my $output; +my $help; +GetOptions( + 'tests-root=s' => \$tests_root, + 'unit-root=s' => \$unit_root, + 'reference=s@' => \@references, + 'runner-list=s' => \$runner_list, + 'output=s' => \$output, + 'help' => \$help, +) or usage(2); +usage(0) if $help; +usage(2) if @ARGV; + +@references = ( + 'docs/reference/feature-matrix.md', + 'dev/design/phase36-regex-parity.md', + 'dev/tools/compare_test_results.pl', +) unless @references; + +my @core = files_below(File::Spec->catdir($tests_root, 're')); +my @auxiliary = grep { regex_bearing($_) } + map { files_below(File::Spec->catdir($tests_root, $_)) } qw(op uni); + +my (%documented, @unresolved); +for my $reference (@references) { + next unless -f $reference; + my $contents = read_file($reference); + while ($contents =~ /`([^`\n]*?\.t)`/g) { + my $spelling = $1; + my @resolved = resolve_reference($spelling, $tests_root, $unit_root); + if (@resolved) { + $documented{$_} = 1 for @resolved; + } else { + push @unresolved, { source => $reference, spelling => $spelling }; + } + } +} + +my %runner = map { $_ => 1 } (@core, @auxiliary, + grep { index($_, "$tests_root/") == 0 } keys %documented); +my @runner = sort keys %runner; +my @unit_gates = sort grep { index($_, "$unit_root/") == 0 } keys %documented; + +my @thread_pairs; +for my $thread (grep { /_thr\.t\z/ } @core) { + (my $direct = $thread) =~ s/_thr\.t\z/.t/; + push @thread_pairs, { + direct => $direct, + thread => $thread, + direct_exists => -f $direct ? JSON::PP::true : JSON::PP::false, + }; +} + +my $ledger = { + schema_version => 1, + policy => 'current latest upstream perl5 checkout; no pinned revision', + summary => { + core_re_files => scalar @core, + auxiliary_regex_files => scalar @auxiliary, + runner_files => scalar @runner, + documented_unit_gates => scalar @unit_gates, + direct_thread_pairs => scalar @thread_pairs, + unresolved_references => scalar @unresolved, + }, + core_re_files => \@core, + auxiliary_regex_files => \@auxiliary, + runner_files => \@runner, + documented_unit_gates => \@unit_gates, + direct_thread_pairs => \@thread_pairs, + unresolved_references => \@unresolved, +}; + +write_lines($runner_list, @runner) if defined $runner_list; +my $json = JSON::PP->new->canonical->pretty->encode($ledger); +if (defined $output) { + write_file($output, $json); +} else { + print $json; +} + +sub usage { + my ($status) = @_; + print <<'USAGE'; +Usage: generate_regex_test_ledger.pl [OPTIONS] + +Mechanically derive the current Phase 36 regex test ledger from the complete +perl5_t/t/re corpus, regex-bearing op/ and uni/ files, and documented test +references. The checkout is always treated as current upstream input; no Perl +revision or historical checksum is encoded. + +Options: + --tests-root DIR imported Perl test root (default: perl5_t/t) + --unit-root DIR repository unit-test root + --reference FILE documentation/tool reference source (repeatable) + --runner-list FILE write one runnable imported test path per line + --output FILE write canonical JSON instead of stdout + --help show this help +USAGE + exit $status; +} + +sub files_below { + my ($root) = @_; + return () unless -d $root; + my @files; + find({ + no_chdir => 1, + wanted => sub { + return unless -f $_ && /\.t\z/; + my $path = $File::Find::name; + $path =~ s{\\}{/}g; + push @files, $path; + }, + }, $root); + return sort @files; +} + +sub regex_bearing { + my ($path) = @_; + my $source = read_file($path); + return 1 if $source =~ /(?:=~|!~)/; + return 1 if $source =~ /\b(?:qr|split|pos)\b/; + return 1 if $source =~ /\buse\s+re\b/; + return 1 if $source =~ /\\[pPNX]\{/; + return 0; +} + +sub resolve_reference { + my ($spelling, $tests, $units) = @_; + $spelling =~ s{\\}{/}g; + my @candidates; + if ($spelling =~ m{\Aperl5_t/t/}) { + push @candidates, $spelling; + } elsif ($spelling =~ m{\A(?:re|op|uni)/}) { + push @candidates, "$tests/$spelling"; + } elsif ($spelling !~ m{/}) { + for my $root ($tests, $units) { + push @candidates, grep { /\Q$spelling\E\z/ } files_below($root); + } + } + my %seen; + return sort grep { -f $_ && !$seen{$_}++ } @candidates; +} + +sub read_file { + my ($path) = @_; + open my $fh, '<:raw', $path or die "Cannot read $path: $!\n"; + my $contents = do { local $/; <$fh> }; + close $fh or die "Cannot close $path: $!\n"; + return $contents; +} + +sub write_lines { + my ($path, @lines) = @_; + write_file($path, join('', map { "$_\n" } @lines)); +} + +sub write_file { + my ($path, $contents) = @_; + open my $fh, '>:raw', $path or die "Cannot write $path: $!\n"; + print {$fh} $contents; + close $fh or die "Cannot close $path: $!\n"; +} diff --git a/dev/tools/perl_test_runner.pl b/dev/tools/perl_test_runner.pl index 17246ddada..dd96ff0de4 100755 --- a/dev/tools/perl_test_runner.pl +++ b/dev/tools/perl_test_runner.pl @@ -428,17 +428,6 @@ sub run_single_test { | base/lex.t | comp/parser.t }x ? "warn" : ""; - local $ENV{JPERL_REGEX_CODE_BLOCK_NOOP} = $test_file =~ m{ - re/pat_advanced.t - | re/overload.t - | re/regexp.t - | re/regexp_noamp.t - | re/regexp_normal.t - | re/regexp_notrie.t - | re/regexp_qr.t - | re/regexp_qr_embed.t - | re/regexp_trielist.t }x - ? "1" : ""; local $ENV{JPERL_OPTS} = $test_file =~ m{ re/pat.t | op/repeat.t diff --git a/dev/tools/perl_unicode_data_generators.json b/dev/tools/perl_unicode_data_generators.json index fa54fcd1fb..436eae6f2e 100644 --- a/dev/tools/perl_unicode_data_generators.json +++ b/dev/tools/perl_unicode_data_generators.json @@ -1,111 +1,132 @@ { - "schema_version": 1, - "unicode_version": "17.0.0", - "perl_version": "5.44.0", - "perl_commit": "de80c8ecd40c6d5b677847699e5482b44bc748c6", - "version_sha256": "8c30575264b2772c7a69c5bb6069a28f0e0a7a0df735871bde2d99ee674316ac", - "shared_sources": { - "PropertyAliases.txt": "4441f573caf952ffece1d7c892e7715bd7136dfc26f96eb6f268bf1e474715fb", - "PropValueAliases.txt": "670d2bebb48649c04fabfbf033308073dcff47946324a8033237254c048b3b01" - }, - "generators": [ - { - "name": "age", - "generator": "dev/tools/generate_perl_unicode_age_data.pl", - "output": "src/main/java/org/perlonjava/runtime/regex/PerlUnicodeAgeData.java", - "output_sha256": "f4ce8ee756e186ff401da5eae03d5ba13581efc169a5bc4f162a533f58ee2bbf", - "sources": {"DAge.txt": "f8ecdf768bdc210f201abd271d9bc587825618a86a7046a8146cc816393f1998"} - }, - { - "name": "bidi-class", - "generator": "dev/tools/generate_perl_unicode_bidi_class_data.pl", - "output": "src/main/java/org/perlonjava/runtime/regex/PerlUnicodeBidiClassData.java", - "output_sha256": "a762ff311149fd40c84f2390fd2a067a90d6172f7f7f0a652a34079bb4b2f70b", - "sources": {"extracted/DBidiClass.txt": "4867b4b7f0731ed1bfcd34cc6251211ff1542541fce0734b6fbda139ee80b3a4"} - }, - { - "name": "block", - "generator": "dev/tools/generate_perl_unicode_block_data.pl", - "output": "src/main/java/org/perlonjava/runtime/regex/PerlUnicodeBlockData.java", - "output_sha256": "8bba409ec13fe03da3c47545865917fb251136e1bc531c055deb12849c36b255", - "sources": {"Blocks.txt": "c0edefaf1a19771e830a82735472716af6bf3c3975f6c2a23ffbe2580fbbcb15"} - }, - { - "name": "combining-class", - "generator": "dev/tools/generate_perl_unicode_combining_class_data.pl", - "output": "src/main/java/org/perlonjava/runtime/regex/PerlUnicodeCombiningClassData.java", - "output_sha256": "9d0c99f58d8e80217914cd30877d358af2676e916dcb2e6bcc865adbc9522b3a", - "sources": {"extracted/DCombiningClass.txt": "191463abfbd202703c6fd6776a92a23ac44ec65e0476a7f95aa91ca492cef29b"} - }, - { - "name": "case-fold", - "generator": "dev/tools/generate_perl_unicode_case_fold_data.pl", - "output": "third_party/joni/src/org/joni/PerlUnicodeCaseFoldData.java", - "output_sha256": "4bab60ee50b08d24b9b69863688c2862c724fb58ba76a749974af074b19c3b82", - "sources": { - "CaseFolding.txt": "ff8d8fefbf123574205085d6714c36149eb946d717a0c585c27f0f4ef58c4183", - "SpecialCasing.txt": "efc25faf19de21b92c1194c111c932e03d2a5eaf18194e33f1156e96de4c9588" + "generators" : [ + { + "generator" : "dev/tools/generate_perl_unicode_age_data.pl", + "name" : "age", + "output" : "src/main/java/org/perlonjava/runtime/regex/PerlUnicodeAgeData.java", + "output_sha256" : "59fcaa610b14c0539069ee385564650f782277ad587775f2f167a07946fc427b", + "sources" : { + "DAge.txt" : "f8ecdf768bdc210f201abd271d9bc587825618a86a7046a8146cc816393f1998" + } }, - "perl_sources": { - "regen/regcharclass_multi_char_folds.pl": "b2f896452d2b30da3e04800f478c60c1fd0b03d6b668689b020f1e3cf1f1cdd9", - "regen/mk_invlists.pl": "20a6e3d507a66f4594586485568134873485b08e23383f3dc4e6b3047569267b", - "lib/unicore/mktables": "e3ac360c03d18779fea6d6497fbbe53798135da55e3764d3c9f90a79bbf7e8b5", - "charclass_invlists.inc": "c83c6471e7c188f21a20c6285af83f57d0bd09392f3243e4cc3743f0a5d5052c", - "regcharclass.h": "b6005d471764b31d04063ccd561c88d165a2a30f9bae9b75172eb7b59672754e", - "regen/regcharclass.pl": "852a8a7814f08a155d79fead2656fe2b4450ab17a2bce8a1127016119c9c3bc3" - } - }, - { - "name": "decomposition-type", - "generator": "dev/tools/generate_perl_unicode_decomposition_type_data.pl", - "output": "src/main/java/org/perlonjava/runtime/regex/PerlUnicodeDecompositionTypeData.java", - "output_sha256": "9847d3b794c45557ff6f61618f2b9271633334ab72c3b1c35c4585f174e0a629", - "sources": {"extracted/DDecompositionType.txt": "f44e5ceaf40edc1fe06ea0404e8bebc7d356dcc38aac076543b6874008a06e3e"} - }, - { - "name": "east-asian-width", - "generator": "dev/tools/generate_perl_unicode_east_asian_width_data.pl", - "output": "src/main/java/org/perlonjava/runtime/regex/PerlUnicodeEastAsianWidthData.java", - "output_sha256": "7878246c37247c85a5bfa53b5392f1decf58552ed2fa41aab9a53fd9e61ed87e", - "sources": {"extracted/DEastAsianWidth.txt": "0b5523a2217cb318d20b329a05d31eec5af5686ba09d263b85bb75a28989a3a8"} - }, - { - "name": "general-category", - "generator": "dev/tools/generate_perl_unicode_general_category_data.pl", - "output": "src/main/java/org/perlonjava/runtime/regex/PerlUnicodeGeneralCategoryData.java", - "output_sha256": "89bc29ef27536a2aead54ab6a063cbaca878d0545e6bce071078eafe7a259211", - "sources": {"extracted/DGeneralCategory.txt": "d62e5bab70ca74f099343f71224fa051cb1fdd61a1ab45c0488c44cfc0b6102e"} - }, - { - "name": "joining-group", - "generator": "dev/tools/generate_perl_unicode_joining_group_data.pl", - "output": "src/main/java/org/perlonjava/runtime/regex/PerlUnicodeJoiningGroupData.java", - "output_sha256": "37a10623c068620d0eb0a7a60f8c68ef313b8518c4bd3207e17530fd3cf412e5", - "sources": {"extracted/DJoinGroup.txt": "bb67e0c00b88acfa5be633967b66b23326844a86e49c6fde7b57960d3af66cae"} - }, - { - "name": "numeric-value", - "generator": "dev/tools/generate_perl_unicode_numeric_value_data.pl", - "output": "src/main/java/org/perlonjava/runtime/regex/PerlUnicodeNumericValueData.java", - "output_sha256": "d040f3f91da08274a90c608f3cbb2202b5ca901c729898b486fd2f1647660b17", - "sources": {"extracted/DNumValues.txt": "139b976bdc288be01c80f018523da769cf2845109b5a7f0f8a432db64bfedcfa"} - }, - { - "name": "script", - "generator": "dev/tools/generate_perl_unicode_script_data.pl", - "output": "src/main/java/org/perlonjava/runtime/regex/PerlUnicodeScriptData.java", - "output_sha256": "e27079c728d4817a7edd5f3ec7f7c2a009d96909187a84b6a2f15c53933904f6", - "sources": { - "Scripts.txt": "9f5e50d3abaee7d6ce09480f325c706f485ae3240912527e651954d2d6b035bf", - "ScriptExtensions.txt": "ec2107e58825a1586acee8e0911ce18260394ac8b87e535ca325f1ccbeb06bc6" + { + "generator" : "dev/tools/generate_perl_unicode_bidi_class_data.pl", + "name" : "bidi-class", + "output" : "src/main/java/org/perlonjava/runtime/regex/PerlUnicodeBidiClassData.java", + "output_sha256" : "a762ff311149fd40c84f2390fd2a067a90d6172f7f7f0a652a34079bb4b2f70b", + "sources" : { + "extracted/DBidiClass.txt" : "4867b4b7f0731ed1bfcd34cc6251211ff1542541fce0734b6fbda139ee80b3a4" + } + }, + { + "generator" : "dev/tools/generate_perl_unicode_block_data.pl", + "name" : "block", + "output" : "src/main/java/org/perlonjava/runtime/regex/PerlUnicodeBlockData.java", + "output_sha256" : "8bba409ec13fe03da3c47545865917fb251136e1bc531c055deb12849c36b255", + "sources" : { + "Blocks.txt" : "c0edefaf1a19771e830a82735472716af6bf3c3975f6c2a23ffbe2580fbbcb15" + } + }, + { + "generator" : "dev/tools/generate_perl_unicode_combining_class_data.pl", + "name" : "combining-class", + "output" : "src/main/java/org/perlonjava/runtime/regex/PerlUnicodeCombiningClassData.java", + "output_sha256" : "9d0c99f58d8e80217914cd30877d358af2676e916dcb2e6bcc865adbc9522b3a", + "sources" : { + "extracted/DCombiningClass.txt" : "191463abfbd202703c6fd6776a92a23ac44ec65e0476a7f95aa91ca492cef29b" + } + }, + { + "generator" : "dev/tools/generate_perl_unicode_case_fold_data.pl", + "name" : "case-fold", + "output" : "third_party/joni/src/org/joni/PerlUnicodeCaseFoldData.java", + "output_sha256" : "4bab60ee50b08d24b9b69863688c2862c724fb58ba76a749974af074b19c3b82", + "perl_sources" : { + "charclass_invlists.inc" : "c83c6471e7c188f21a20c6285af83f57d0bd09392f3243e4cc3743f0a5d5052c", + "lib/unicore/mktables" : "e3ac360c03d18779fea6d6497fbbe53798135da55e3764d3c9f90a79bbf7e8b5", + "regcharclass.h" : "b6005d471764b31d04063ccd561c88d165a2a30f9bae9b75172eb7b59672754e", + "regen/mk_invlists.pl" : "20a6e3d507a66f4594586485568134873485b08e23383f3dc4e6b3047569267b", + "regen/regcharclass.pl" : "852a8a7814f08a155d79fead2656fe2b4450ab17a2bce8a1127016119c9c3bc3", + "regen/regcharclass_multi_char_folds.pl" : "b2f896452d2b30da3e04800f478c60c1fd0b03d6b668689b020f1e3cf1f1cdd9" + }, + "sources" : { + "CaseFolding.txt" : "ff8d8fefbf123574205085d6714c36149eb946d717a0c585c27f0f4ef58c4183", + "SpecialCasing.txt" : "efc25faf19de21b92c1194c111c932e03d2a5eaf18194e33f1156e96de4c9588" + } + }, + { + "generator" : "dev/tools/generate_perl_unicode_decomposition_type_data.pl", + "name" : "decomposition-type", + "output" : "src/main/java/org/perlonjava/runtime/regex/PerlUnicodeDecompositionTypeData.java", + "output_sha256" : "9847d3b794c45557ff6f61618f2b9271633334ab72c3b1c35c4585f174e0a629", + "sources" : { + "extracted/DDecompositionType.txt" : "f44e5ceaf40edc1fe06ea0404e8bebc7d356dcc38aac076543b6874008a06e3e" + } + }, + { + "generator" : "dev/tools/generate_perl_unicode_east_asian_width_data.pl", + "name" : "east-asian-width", + "output" : "src/main/java/org/perlonjava/runtime/regex/PerlUnicodeEastAsianWidthData.java", + "output_sha256" : "7878246c37247c85a5bfa53b5392f1decf58552ed2fa41aab9a53fd9e61ed87e", + "sources" : { + "extracted/DEastAsianWidth.txt" : "0b5523a2217cb318d20b329a05d31eec5af5686ba09d263b85bb75a28989a3a8" + } + }, + { + "generator" : "dev/tools/generate_perl_unicode_general_category_data.pl", + "name" : "general-category", + "output" : "src/main/java/org/perlonjava/runtime/regex/PerlUnicodeGeneralCategoryData.java", + "output_sha256" : "89bc29ef27536a2aead54ab6a063cbaca878d0545e6bce071078eafe7a259211", + "sources" : { + "extracted/DGeneralCategory.txt" : "d62e5bab70ca74f099343f71224fa051cb1fdd61a1ab45c0488c44cfc0b6102e" + } + }, + { + "generator" : "dev/tools/generate_perl_unicode_joining_group_data.pl", + "name" : "joining-group", + "output" : "src/main/java/org/perlonjava/runtime/regex/PerlUnicodeJoiningGroupData.java", + "output_sha256" : "37a10623c068620d0eb0a7a60f8c68ef313b8518c4bd3207e17530fd3cf412e5", + "sources" : { + "extracted/DJoinGroup.txt" : "bb67e0c00b88acfa5be633967b66b23326844a86e49c6fde7b57960d3af66cae" + } + }, + { + "generator" : "dev/tools/generate_perl_unicode_numeric_value_data.pl", + "name" : "numeric-value", + "output" : "src/main/java/org/perlonjava/runtime/regex/PerlUnicodeNumericValueData.java", + "output_sha256" : "d040f3f91da08274a90c608f3cbb2202b5ca901c729898b486fd2f1647660b17", + "sources" : { + "extracted/DNumValues.txt" : "139b976bdc288be01c80f018523da769cf2845109b5a7f0f8a432db64bfedcfa" + } + }, + { + "generator" : "dev/tools/generate_perl_unicode_script_data.pl", + "name" : "script", + "output" : "src/main/java/org/perlonjava/runtime/regex/PerlUnicodeScriptData.java", + "output_sha256" : "e27079c728d4817a7edd5f3ec7f7c2a009d96909187a84b6a2f15c53933904f6", + "sources" : { + "ScriptExtensions.txt" : "ec2107e58825a1586acee8e0911ce18260394ac8b87e535ca325f1ccbeb06bc6", + "Scripts.txt" : "9f5e50d3abaee7d6ce09480f325c706f485ae3240912527e651954d2d6b035bf" + } + }, + { + "generator" : "dev/tools/generate_perl_unicode_unikemet_data.pl", + "name" : "unikemet", + "output" : "src/main/java/org/perlonjava/runtime/regex/PerlUnicodeUnikemetData.java", + "output_sha256" : "4adc6e3549ee2d71e4ec6b7f70b5addf1672aac2ab68168ee3b43a5f82de4546", + "sources" : { + "Unikemet.txt" : "76a3081265e6eb673873f9c93d6f36062e82c7ed027c5c1a592accfbe48c20a5" + } } - }, - { - "name": "unikemet", - "generator": "dev/tools/generate_perl_unicode_unikemet_data.pl", - "output": "src/main/java/org/perlonjava/runtime/regex/PerlUnicodeUnikemetData.java", - "output_sha256": "4adc6e3549ee2d71e4ec6b7f70b5addf1672aac2ab68168ee3b43a5f82de4546", - "sources": {"Unikemet.txt": "76a3081265e6eb673873f9c93d6f36062e82c7ed027c5c1a592accfbe48c20a5"} - } - ] + ], + "perl_commit" : "fa00284182335e5fed578460346efb88843f08da", + "perl_source_policy" : "current-checkout", + "perl_version" : "5.45.2", + "schema_version" : 2, + "shared_sources" : { + "PropValueAliases.txt" : "670d2bebb48649c04fabfbf033308073dcff47946324a8033237254c048b3b01", + "PropertyAliases.txt" : "4441f573caf952ffece1d7c892e7715bd7136dfc26f96eb6f268bf1e474715fb" + }, + "unicode_version" : "17.0.0", + "version_sha256" : "8c30575264b2772c7a69c5bb6069a28f0e0a7a0df735871bde2d99ee674316ac" } diff --git a/dev/tools/run_phase36_regex_acceptance.pl b/dev/tools/run_phase36_regex_acceptance.pl new file mode 100644 index 0000000000..4a72888980 --- /dev/null +++ b/dev/tools/run_phase36_regex_acceptance.pl @@ -0,0 +1,373 @@ +#!/usr/bin/env perl +use strict; +use warnings; + +use Cwd qw(abs_path getcwd); +use Digest::SHA qw(sha256_hex); +use File::Basename qw(dirname); +use File::Spec; +use Getopt::Long qw(GetOptions); +use JSON::PP; + +my %option = ( + perl => $^X, + ledger_tool => 'dev/tools/generate_regex_test_ledger.pl', + runner_tool => 'dev/tools/perl_test_runner.pl', + comparator_tool => 'dev/tools/compare_test_results.pl', + packaging_tool => 'dev/tools/verify-joni-packaging.pl', + jperl => './jperl', + timeout => 300, + version_timeout => 30, + jobs => 5, +); +my $help; +GetOptions( + 'baseline=s' => \$option{baseline}, + 'artifact-dir=s' => \$option{artifact_dir}, + 'jar=s' => \$option{jar}, + 'sbom=s' => \$option{sbom}, + 'perl=s' => \$option{perl}, + 'source-dir=s' => \$option{source_dir}, + 'perl5-dir=s' => \$option{perl5_dir}, + 'jperl=s' => \$option{jperl}, + 'timeout=i' => \$option{timeout}, + 'version-timeout=i' => \$option{version_timeout}, + 'jobs=i' => \$option{jobs}, + 'ledger-tool=s' => \$option{ledger_tool}, + 'runner-tool=s' => \$option{runner_tool}, + 'comparator-tool=s' => \$option{comparator_tool}, + 'packaging-tool=s' => \$option{packaging_tool}, + 'prepare-only!' => \$option{prepare_only}, + 'help' => \$help, +) or usage(2); +usage(0) if $help; +usage(2) if @ARGV; + +for my $required (qw(baseline artifact_dir jar sbom)) { + die "--$required is required\n" unless defined $option{$required} + && length $option{$required}; +} +die "--timeout must be positive\n" unless $option{timeout} > 0; +die "--version-timeout must be positive\n" unless $option{version_timeout} > 0; +die "--jobs must be positive\n" unless $option{jobs} > 0; + +my $root = $option{source_dir} // getcwd(); +$option{perl5_dir} //= File::Spec->catdir($root, 'perl5'); +validate_file($option{baseline}, 'PR-958 baseline'); +validate_file($option{jar}, 'standalone JAR'); +validate_file($option{sbom}, 'SBOM'); +validate_directory($option{artifact_dir}, 'artifact directory'); +for my $tool (qw(ledger_tool runner_tool comparator_tool packaging_tool)) { + validate_file($option{$tool}, "$tool path"); +} +validate_program($option{perl}, 'Perl executable'); +validate_program($option{jperl}, 'jperl executable'); + +my $start_sha = git_sha($root); +my $start_state = tracked_state($root); +my $perl5_sha = git_sha($option{perl5_dir}); +my %path = map { $_ => File::Spec->catfile($option{artifact_dir}, $_) } qw( + regex-ledger.json + regex-files.txt + jvm-results.json + interpreter-results.json + jvm-comparison.json + interpreter-comparison.json + ledger.log + jvm-runner.log + interpreter-runner.log + jvm-comparison.log + interpreter-comparison.log + packaging.log + jperl-version.log + manifest.json +); +for my $name (keys %path) { + die "Refusing to overwrite retained artifact $path{$name}\n" if -e $path{$name}; +} + +my @commands; +my %statuses; +run_logged( + name => 'jperl-version', command => [$option{jperl}, '-v'], + log => $path{'jperl-version.log'}, commands => \@commands, statuses => \%statuses, + timeout => $option{version_timeout}, +); +my $runner_sha = parse_runner_sha($path{'jperl-version.log'}, $start_sha); +run_logged( + name => 'ledger', + command => [$option{perl}, $option{ledger_tool}, + '--runner-list', $path{'regex-files.txt'}, '--output', $path{'regex-ledger.json'}], + log => $path{'ledger.log'}, + commands => \@commands, statuses => \%statuses, +); + +my $ledger = load_json($path{'regex-ledger.json'}, 'ledger'); +die "Ledger has unresolved references\n" if ($ledger->{summary}{unresolved_references} // 0) != 0; +my @files = load_file_list($path{'regex-files.txt'}); +die "Ledger runner list is empty\n" unless @files; +my $expected_files = scalar @files; + +my @runner_common = ($option{perl}, $option{runner_tool}, + '--jperl', $option{jperl}, '--timeout', $option{timeout}, '--jobs', $option{jobs}); +run_logged( + name => 'jvm-runner', + command => [@runner_common, '--output', $path{'jvm-results.json'}, @files], + log => $path{'jvm-runner.log'}, + environment => { JPERL_INTERPRETER => undef }, + commands => \@commands, statuses => \%statuses, +); +run_logged( + name => 'interpreter-runner', + command => [@runner_common, '--output', $path{'interpreter-results.json'}, @files], + log => $path{'interpreter-runner.log'}, + environment => { JPERL_INTERPRETER => 1 }, + commands => \@commands, statuses => \%statuses, +); + +for my $leg ( + ['jvm', $path{'jvm-results.json'}, $path{'jvm-comparison.json'}], + ['interpreter', $path{'interpreter-results.json'}, $path{'interpreter-comparison.json'}], +) { + run_logged( + name => "$leg->[0]-comparison", + command => [$option{perl}, $option{comparator_tool}, + '--fail-on-regression', '--fail-on-invalid', + '--normalize-pr958-artifacts', '--expected-files', $expected_files, + '--file-list', $path{'regex-files.txt'}, '--output', $leg->[2], + $option{baseline}, $leg->[1]], + log => $path{"$leg->[0]-comparison.log"}, + commands => \@commands, statuses => \%statuses, + ); + verify_comparison($leg->[2], $expected_files); +} +run_logged( + name => 'packaging', + command => [$option{perl}, $option{packaging_tool}, $option{jar}, $option{sbom}], + log => $path{'packaging.log'}, commands => \@commands, statuses => \%statuses, +); + +my $final_sha = git_sha($root); +die "Checkout HEAD changed during acceptance: $start_sha -> $final_sha\n" + unless $start_sha eq $final_sha; +die "Tracked source state changed during acceptance\n" + unless tracked_state($root) eq $start_state; + +my @retained = sort grep { -f $path{$_} } keys %path; +my $manifest = { + schema_version => 1, + mode => $option{prepare_only} ? 'prepare-only' : 'acceptance', + source => { + starting_sha => $start_sha, + final_sha => $final_sha, + perl5_sha_as_provenance => $perl5_sha, + tracked_state_signature => $start_state, + }, + baseline => abs_file($option{baseline}), + artifact_directory => abs_path($option{artifact_dir}), + expected_files => $expected_files, + verified_runner_sha => $runner_sha, + ledger_summary => $ledger->{summary}, + commands => \@commands, + exit_statuses => \%statuses, + artifacts => { map { $_ => { path => abs_file($path{$_}), sha256 => sha256_file($path{$_}) } } @retained }, +}; +write_json($path{'manifest.json'}, $manifest); +print "Phase 36 regex acceptance manifest: $path{'manifest.json'}\n"; + +sub usage { + my ($status) = @_; + print <<'USAGE'; +Usage: run_phase36_regex_acceptance.pl --baseline FILE --artifact-dir DIR --jar FILE --sbom FILE [OPTIONS] + +Compose the Phase 36 ledger, runner, comparator, and packaging gates into one +fail-closed immutable-artifact acceptance record. The current perl5 checkout is +recorded as provenance only, never compared to a pinned revision. + +Options: + --prepare-only Exercise the composition with injected fake tools; + never use this as authority for the real corpus. + --perl PATH --jperl PATH Tool executables (default perl / ./jperl) + --source-dir DIR Clean source checkout to verify (default cwd) + --perl5-dir DIR Current imported perl5 checkout (default ./perl5) + --timeout N --jobs N Existing runner bounds and worker budget + --version-timeout N Hard bound for the jperl identity probe (default 30) + --ledger-tool PATH --runner-tool PATH --comparator-tool PATH + --packaging-tool PATH Injectable list-form subprocess tools for testing +USAGE + exit $status; +} + +sub validate_file { + my ($path, $label) = @_; + die "$label is missing or empty: $path\n" unless -f $path && -s $path; +} + +sub validate_directory { + my ($path, $label) = @_; + die "$label is missing: $path\n" unless -d $path; +} + +sub validate_program { + my ($program, $label) = @_; + if ($program =~ m{/}) { + die "$label is missing or not executable: $program\n" unless -x $program; + return; + } + for my $directory (split /:/, ($ENV{PATH} // '')) { + return if -x File::Spec->catfile($directory, $program); + } + die "$label is not on PATH: $program\n"; +} + +sub git_sha { + my ($directory) = @_; + die "Git checkout is missing: $directory\n" unless -d $directory; + my $output = capture_command(['git', '-C', $directory, 'rev-parse', 'HEAD']); + $output =~ s/\s+\z//; + die "Cannot determine checkout HEAD for $directory\n" unless $output =~ /\A[0-9a-f]{40}\z/; + return $output; +} + +sub tracked_state { + my ($directory) = @_; + my $status = capture_command(['git', '-C', $directory, 'status', '--porcelain', '--untracked-files=no']); + die "Tracked source checkout is not clean\n" if length $status; + return sha256_hex(capture_command(['git', '-C', $directory, 'diff', '--binary', 'HEAD'])); +} + +sub parse_runner_sha { + my ($log, $source_sha) = @_; + my $contents = read_raw($log); + my @sha = $contents =~ /\b([0-9a-f]{7,40})\b/ig; + for my $candidate (@sha) { + return $candidate if index($source_sha, lc $candidate) == 0; + } + die "jperl -v does not report the source Git SHA or prefix\n"; +} + +sub load_file_list { + my ($file) = @_; + open my $fh, '<:raw', $file or die "Cannot read runner list $file: $!\n"; + my @files; + while (my $line = <$fh>) { + $line =~ s/\r?\n\z//; + next if $line =~ /^\s*(?:#|\z)/; + die "Runner list contains an empty path\n" unless length $line; + die "Runner list references missing test path: $line\n" unless -f $line; + push @files, $line; + } + close $fh or die "Cannot close runner list $file: $!\n"; + return @files; +} + +sub read_raw { + my ($file) = @_; + open my $fh, '<:raw', $file or die "Cannot read $file: $!\n"; + my $contents = do { local $/; <$fh> }; + close $fh or die "Cannot close $file: $!\n"; + return $contents; +} + +sub run_logged { + my (%arg) = @_; + my @command = @{$arg{command}}; + my $status = run_to_log($arg{log}, $arg{environment}, $arg{timeout}, @command); + push @{$arg{commands}}, { name => $arg{name}, argv => \@command, + environment => $arg{environment} // {} }; + $arg{statuses}{$arg{name}} = $status; + if ($status == 124 && defined $arg{timeout}) { + warn "$arg{name} timed out after $arg{timeout}s; see $arg{log}\n"; + exit 124; + } + die "$arg{name} failed with exit status $status; see $arg{log}\n" if $status != 0; +} + +sub run_to_log { + my ($log, $environment, $timeout, @command) = @_; + my $pid = fork(); + die "Cannot fork $command[0]: $!\n" unless defined $pid; + if ($pid == 0) { + open STDOUT, '>:raw', $log or die "Cannot write $log: $!\n"; + open STDERR, '>&', \*STDOUT or die "Cannot redirect stderr: $!\n"; + if ($environment) { + for my $key (keys %$environment) { + defined $environment->{$key} ? ($ENV{$key} = $environment->{$key}) : delete $ENV{$key}; + } + } + exec { $command[0] } @command; + die "Cannot execute $command[0]: $!\n"; + } + if (defined $timeout) { + my $completed = eval { + local $SIG{ALRM} = sub { die "acceptance child timeout\n" }; + alarm $timeout; + waitpid($pid, 0); + alarm 0; + 1; + }; + if (!$completed) { + alarm 0; + kill 'TERM', $pid; + select undef, undef, undef, 0.1; + kill 'KILL', $pid if kill 0, $pid; + waitpid($pid, 0); + return 124; + } + } else { + waitpid($pid, 0); + } + return $? >> 8 if $? != -1 && ($? & 127) == 0; + return 255; +} + +sub capture_command { + my ($command) = @_; + open my $fh, '-|', @$command or die "Cannot execute $command->[0]: $!\n"; + my $output = do { local $/; <$fh> }; + close $fh or die "Command $command->[0] failed with status $?\n"; + return $output; +} + +sub load_json { + my ($file, $label) = @_; + open my $fh, '<:raw', $file or die "Cannot read $label $file: $!\n"; + my $document = eval { JSON::PP->new->utf8->decode(do { local $/; <$fh> }) }; + close $fh; + die "Invalid $label JSON in $file\n" unless $document && ref $document eq 'HASH'; + return $document; +} + +sub verify_comparison { + my ($file, $expected_files) = @_; + my $comparison = load_json($file, 'comparison'); + die "Comparison $file has no summary\n" unless ref $comparison->{summary} eq 'HASH'; + my $count = $comparison->{summary}{candidate_files}; + die "Comparison $file has file count drift\n" + unless defined $count && $count == $expected_files; + for my $key (qw(regressions missing_files added_files execution_issues zero_tap truncated)) { + die "Comparison $file has non-empty $key\n" + unless ref($comparison->{$key}) eq 'ARRAY' && !@{$comparison->{$key}}; + } +} + +sub sha256_file { + my ($file) = @_; + open my $fh, '<:raw', $file or die "Cannot hash $file: $!\n"; + my $sha = Digest::SHA->new(256); + $sha->addfile($fh); + close $fh; + return $sha->hexdigest; +} + +sub abs_file { + my ($file) = @_; + return abs_path($file) // File::Spec->rel2abs($file); +} + +sub write_json { + my ($file, $document) = @_; + open my $fh, '>:raw', $file or die "Cannot write $file: $!\n"; + print {$fh} JSON::PP->new->canonical->pretty->encode($document); + close $fh or die "Cannot close $file: $!\n"; +} diff --git a/dev/tools/tests/compare_test_results_acceptance.t b/dev/tools/tests/compare_test_results_acceptance.t new file mode 100644 index 0000000000..308104d27c --- /dev/null +++ b/dev/tools/tests/compare_test_results_acceptance.t @@ -0,0 +1,160 @@ +use strict; +use warnings; + +use File::Spec; +use File::Temp qw(tempdir); +use FindBin; +use JSON::PP; +use Test::More; + +my $root = File::Spec->rel2abs( + File::Spec->catdir($FindBin::Bin, '..', '..', '..')); +my $tool = File::Spec->catfile($root, 'dev', 'tools', 'compare_test_results.pl'); +my $legacy_tool = File::Spec->catfile($root, 'dev', 'tools', 'compare_test_logs.pl'); +my $temporary = tempdir(CLEANUP => 1); + +subtest 'progress with complete direct and thread records passes' => sub { + my $baseline = write_json('baseline.json', { + 'perl5_t/t/re/pat.t' => result(8, 10, 'partial'), + 'perl5_t/t/re/pat_thr.t' => result(8, 10, 'partial'), + }); + my $candidate = write_json('progress.json', { + 'perl5_t/t/re/pat.t' => result(9, 10, 'partial'), + 'perl5_t/t/re/pat_thr.t' => result(10, 10, 'pass'), + }); + my ($status, $output, $report) = run_strict($baseline, $candidate, 'progress-report.json'); + is($status, 0, 'strict comparison accepts progress'); + like($output, qr/regressions=0 improvements=2 missing=0/, 'summary reports progress'); + is_deeply([sort map { $_->{file} } @{$report->{improvements}}], + [qw(perl5_t/t/re/pat.t perl5_t/t/re/pat_thr.t)], + 'direct and thread files remain separate identities'); +}; + +subtest 'each invalid candidate class exits nonzero' => sub { + my $baseline = write_json('invalid-baseline.json', { + 'perl5_t/t/re/a.t' => result(2, 2, 'pass'), + 'perl5_t/t/re/b.t' => result(2, 2, 'pass'), + }); + my @cases = ( + [missing => {'perl5_t/t/re/a.t' => result(2, 2, 'pass')}, qr/MISSING FILES/], + [regression => { + 'perl5_t/t/re/a.t' => result(1, 2, 'partial'), + 'perl5_t/t/re/b.t' => result(2, 2, 'pass'), + }, qr/REGRESSIONS/], + [timeout => { + 'perl5_t/t/re/a.t' => result(2, 2, 'pass'), + 'perl5_t/t/re/b.t' => result(0, 0, 'timeout', exit_code => 124), + }, qr/EXECUTION ISSUES/], + [error => { + 'perl5_t/t/re/a.t' => result(2, 2, 'pass'), + 'perl5_t/t/re/b.t' => result(0, 0, 'error', exit_code => 1), + }, qr/status=error/], + [zero_tap => { + 'perl5_t/t/re/a.t' => result(2, 2, 'pass'), + 'perl5_t/t/re/b.t' => result(0, 0, 'pass'), + }, qr/ZERO TAP/], + [truncated => { + 'perl5_t/t/re/a.t' => result(2, 2, 'pass'), + 'perl5_t/t/re/b.t' => result(1, 2, 'incomplete', actual_tests_run => 1, + planned_tests => 2, incomplete_tests => 1), + }, qr/TRUNCATED OR INCOMPLETE TAP/], + ); + for my $case (@cases) { + my ($name, $results, $diagnostic) = @$case; + my $candidate = write_json("$name.json", $results); + my ($status, $output) = run_strict($baseline, $candidate, "$name-report.json"); + is($status, 1, "$name is rejected"); + like($output, $diagnostic, "$name has an explicit diagnostic"); + } +}; + +subtest 'exact PR-958 artifacts normalize without hiding real loss' => sub { + my $baseline = write_log('pr958.log', <<'BASELINE'); +[ 1/3] perl5_t/t/op/do.t ... x 94/99 ok (1.00s) +[ 2/3] perl5_t/t/japh/abigail.t ... x 110/130 ok (1.00s) +[ 3/3] perl5_t/t/op/real.t ... x 7/10 ok (1.00s) +BASELINE + my $candidate = write_log('pr958-new.log', <<'CANDIDATE'); +[ 1/3] perl5_t/t/op/do.t ... x 69/71 ok (1.00s) +[ 2/3] perl5_t/t/japh/abigail.t ... x 109/130 ok (1.00s) +[ 3/3] perl5_t/t/op/real.t ... x 6/10 ok (1.00s) +CANDIDATE + my ($status, $output, $report) = run_strict($baseline, $candidate, + 'pr958-report.json', '--normalize-pr958-artifacts'); + is($status, 1, 'unlisted real loss still fails'); + is($report->{summary}{baseline_ok}, 184, 'baseline uses normalized pass counts'); + is_deeply([map { $_->{file} } @{$report->{regressions}}], + ['perl5_t/t/op/real.t'], 'only the real regression remains'); + like($output, qr/op\/real\.t/, 'human report names the real regression'); +}; + +subtest 'malformed input is rejected' => sub { + my $baseline = write_json('malformed-baseline.json', { + 'perl5_t/t/re/a.t' => result(1, 1, 'pass'), + }); + my $malformed = write_log('malformed.log', "not a runner log\n"); + my ($status, $output) = run_strict($baseline, $malformed, 'malformed-report.json'); + isnt($status, 0, 'malformed input exits nonzero'); + like($output, qr/contains no per-file result lines/, 'parse failure is explicit'); +}; + +subtest 'compare_test_logs exposes the fail-closed acceptance gate' => sub { + my $baseline = write_json('wrapper-baseline.json', { + 'perl5_t/t/re/a.t' => result(2, 2, 'pass'), + }); + my $candidate = write_json('wrapper-candidate.json', { + 'perl5_t/t/re/a.t' => result(1, 2, 'partial'), + }); + my $report = File::Spec->catfile($temporary, 'wrapper-report.json'); + my @command = ($^X, $legacy_tool, '--strict-acceptance', '--output', $report, + $baseline, $candidate); + my $output = qx{@command 2>&1}; + is($? >> 8, 1, 'compatibility entrypoint propagates gate failure'); + like($output, qr/REGRESSIONS/, 'compatibility entrypoint emits human evidence'); + ok(-s $report, 'compatibility entrypoint writes JSON evidence'); +}; + +done_testing; + +sub result { + my ($ok, $total, $status, %extra) = @_; + return { + ok_count => $ok, + total_tests => $total, + status => $status, + planned_tests => $extra{planned_tests} // $total, + actual_tests_run => $extra{actual_tests_run} // $total, + incomplete_tests => $extra{incomplete_tests} // 0, + exit_code => $extra{exit_code} // 0, + }; +} + +sub write_json { + my ($name, $results) = @_; + return write_log($name, JSON::PP->new->canonical->pretty->encode({results => $results})); +} + +sub write_log { + my ($name, $contents) = @_; + my $path = File::Spec->catfile($temporary, $name); + open my $fh, '>:raw', $path or die "cannot write $path: $!"; + print {$fh} $contents; + close $fh or die "cannot close $path: $!"; + return $path; +} + +sub run_strict { + my ($baseline, $candidate, $report_name, @extra) = @_; + my $report_path = File::Spec->catfile($temporary, $report_name); + my @command = ($^X, $tool, '--fail-on-regression', '--fail-on-invalid', + '--output', $report_path, @extra, $baseline, $candidate); + my $output = qx{@command 2>&1}; + my $status = $? >> 8; + my $report; + if (-e $report_path) { + open my $fh, '<:raw', $report_path or die "cannot read $report_path: $!"; + $report = JSON::PP->new->decode(do { local $/; <$fh> }); + close $fh; + } + return ($status, $output, $report); +} diff --git a/dev/tools/tests/compare_test_results_exact_path.t b/dev/tools/tests/compare_test_results_exact_path.t new file mode 100644 index 0000000000..34a1f7b340 --- /dev/null +++ b/dev/tools/tests/compare_test_results_exact_path.t @@ -0,0 +1,44 @@ +use strict; +use warnings; + +use File::Spec; +use File::Temp qw(tempdir); +use FindBin; +use JSON::PP; +use Test::More tests => 3; + +my $root = File::Spec->rel2abs( + File::Spec->catdir($FindBin::Bin, '..', '..', '..')); +my $tool = File::Spec->catfile($root, 'dev', 'tools', + 'compare_test_results.pl'); +my $temporary = tempdir(CLEANUP => 1); +my $baseline = File::Spec->catfile($temporary, 'baseline.json'); +my $candidate = File::Spec->catfile($temporary, 'candidate.json'); +my $json = JSON::PP->new->canonical->encode({ + results => { + 'perl5_t/t/re/a.t' => { + ok_count => 2, total_tests => 2, status => 'pass', + }, + 'perl5_t/t/re/ab.t' => { + ok_count => 3, total_tests => 3, status => 'pass', + }, + }, +}); +write_file($baseline, $json); +write_file($candidate, $json); + +my @command = ($^X, $tool, '--path-prefix', 'perl5_t/t/re/a.t', + $baseline, $candidate); +my $output = qx{@command 2>&1}; +is($? >> 8, 0, 'one-file path prefix succeeds'); +like($output, qr/Files: 1 -> 1/, + 'one-file path prefix selects exactly one result'); +unlike($output, qr/ab\.t/, + 'neighboring filename is not selected by an exact test path'); + +sub write_file { + my ($path, $contents) = @_; + open my $fh, '>:raw', $path or die "Cannot write $path: $!\n"; + print {$fh} $contents; + close $fh or die "Cannot close $path: $!\n"; +} diff --git a/dev/tools/tests/compare_test_results_file_list.t b/dev/tools/tests/compare_test_results_file_list.t new file mode 100644 index 0000000000..8501ef8866 --- /dev/null +++ b/dev/tools/tests/compare_test_results_file_list.t @@ -0,0 +1,61 @@ +use strict; +use warnings; + +use File::Spec; +use File::Temp qw(tempdir); +use FindBin; +use JSON::PP; +use Test::More tests => 5; + +my $root = File::Spec->rel2abs( + File::Spec->catdir($FindBin::Bin, '..', '..', '..')); +my $tool = File::Spec->catfile($root, 'dev', 'tools', + 'compare_test_results.pl'); +my $temporary = tempdir(CLEANUP => 1); +my $baseline = File::Spec->catfile($temporary, 'baseline.json'); +my $candidate = File::Spec->catfile($temporary, 'candidate.json'); +my $file_list = File::Spec->catfile($temporary, 'regex-files.txt'); + +write_file($baseline, results_json( + 'perl5_t/t/re/a.t' => [2, 2], + 'perl5_t/t/re/ab.t' => [3, 3], + 'perl5_t/t/op/plain.t' => [4, 4], +)); +write_file($candidate, results_json( + 'perl5_t/t/re/a.t' => [1, 2], + 'perl5_t/t/re/ab.t' => [3, 3], +)); +write_file($file_list, "# generated ledger\n./perl5_t/t/re/a.t\n\n"); + +my @command = ($^X, $tool, '--file-list', $file_list, + $baseline, $candidate); +my $output = qx{@command 2>&1}; +is($? >> 8, 0, 'exact file-list comparison succeeds'); +like($output, qr/Files: 1 -> 1/, + 'only the listed identity is compared'); +like($output, qr/a\.t: 2\/2 -> 1\/2/, + 'listed regression is retained'); +unlike($output, qr/ab\.t|plain\.t/, + 'unlisted neighboring and unrelated files are excluded'); + +my $conflict = qx{$^X $tool --file-list $file_list --path-prefix perl5_t/t/re $baseline $candidate 2>&1}; +isnt($? >> 8, 0, 'conflicting filters are rejected'); + +sub results_json { + my (%counts) = @_; + my %results = map { + $_ => { + ok_count => $counts{$_}[0], + total_tests => $counts{$_}[1], + status => $counts{$_}[0] == $counts{$_}[1] ? 'pass' : 'partial', + } + } keys %counts; + return JSON::PP->new->canonical->encode({ results => \%results }); +} + +sub write_file { + my ($path, $contents) = @_; + open my $fh, '>:raw', $path or die "Cannot write $path: $!\n"; + print {$fh} $contents; + close $fh or die "Cannot close $path: $!\n"; +} diff --git a/dev/tools/tests/generate_regex_test_ledger.t b/dev/tools/tests/generate_regex_test_ledger.t new file mode 100644 index 0000000000..216b314d6f --- /dev/null +++ b/dev/tools/tests/generate_regex_test_ledger.t @@ -0,0 +1,77 @@ +use strict; +use warnings; + +use File::Path qw(make_path); +use File::Spec; +use File::Temp qw(tempdir); +use FindBin; +use JSON::PP; +use Test::More; + +my $root = File::Spec->rel2abs( + File::Spec->catdir($FindBin::Bin, '..', '..', '..')); +my $tool = File::Spec->catfile($root, 'dev', 'tools', + 'generate_regex_test_ledger.pl'); +my $temporary = tempdir(CLEANUP => 1); +my $tests = File::Spec->catdir($temporary, 'perl5_t', 't'); +my $units = File::Spec->catdir($temporary, 'unit'); +make_path(map { File::Spec->catdir($tests, $_) } qw(re op uni)); +make_path($units); + +write_file(File::Spec->catfile($tests, 're', 'a.t'), "ok 1; qr/a/;\n"); +write_file(File::Spec->catfile($tests, 're', 'a_thr.t'), "ok 1;\n"); +write_file(File::Spec->catfile($tests, 'op', 'match.t'), "'a' =~ /a/;\n"); +write_file(File::Spec->catfile($tests, 'op', 'plain.t'), "ok 1;\n"); +write_file(File::Spec->catfile($tests, 'uni', 'property.t'), "qr/\\p{L}/;\n"); +write_file(File::Spec->catfile($units, 'focused.t'), "ok 1;\n"); +my $reference = File::Spec->catfile($temporary, 'reference.md'); +write_file($reference, "Gates: `focused.t`, `op/plain.t`, `missing.t`.\n"); +my $json_path = File::Spec->catfile($temporary, 'ledger.json'); +my $list_path = File::Spec->catfile($temporary, 'runner.list'); + +my @command = ($^X, $tool, + '--tests-root', $tests, + '--unit-root', $units, + '--reference', $reference, + '--runner-list', $list_path, + '--output', $json_path); +system @command; +is($? >> 8, 0, 'ledger generation succeeds'); + +my $ledger = JSON::PP->new->decode(read_file($json_path)); +is($ledger->{summary}{core_re_files}, 2, 'complete re directory is counted'); +is($ledger->{summary}{auxiliary_regex_files}, 2, + 'regex-bearing op and uni files are discovered'); +is($ledger->{summary}{runner_files}, 5, + 'documented auxiliary imported tests join the runner list'); +is_deeply($ledger->{documented_unit_gates}, + [File::Spec->catfile($units, 'focused.t')], + 'documented unit gate is resolved separately'); +is($ledger->{summary}{direct_thread_pairs}, 1, + 'direct/thread pair is recorded'); +ok($ledger->{direct_thread_pairs}[0]{direct_exists}, + 'thread pair records its direct test'); +is($ledger->{summary}{unresolved_references}, 1, + 'unresolved documented gate is explicit'); + +my @runner = grep { length } split /\n/, read_file($list_path); +is(scalar @runner, 5, 'runner list contains each canonical path once'); +is(scalar(grep { /plain\.t\z/ } @runner), 1, + 'documented non-regex auxiliary test is retained once'); + +done_testing; + +sub write_file { + my ($path, $contents) = @_; + open my $fh, '>:raw', $path or die "Cannot write $path: $!\n"; + print {$fh} $contents; + close $fh or die "Cannot close $path: $!\n"; +} + +sub read_file { + my ($path) = @_; + open my $fh, '<:raw', $path or die "Cannot read $path: $!\n"; + my $contents = do { local $/; <$fh> }; + close $fh or die "Cannot close $path: $!\n"; + return $contents; +} diff --git a/dev/tools/tests/perl_unicode_generator_pipeline.t b/dev/tools/tests/perl_unicode_generator_pipeline.t index 0f60e58660..b14d858f28 100644 --- a/dev/tools/tests/perl_unicode_generator_pipeline.t +++ b/dev/tools/tests/perl_unicode_generator_pipeline.t @@ -21,17 +21,28 @@ make_path($unicode, $perl_root, $tools, $output_dir); my $version = "17.0.0\n"; my $source = "# test Unicode table\n0041 ; Example\n"; -my $generated = "generated\n"; +my $generated = "# test Unicode table\n0041 ; Example\n# pinned Perl generator source\n"; write_file(File::Spec->catfile($unicode, 'version'), $version); write_file(File::Spec->catfile($unicode, 'table.txt'), $source); my $perl_source = "# pinned Perl generator source\n"; write_file(File::Spec->catfile($perl_root, 'source.pl'), $perl_source); +write_file(File::Spec->catfile($perl_root, 'patchlevel.h'), "#define PERL_REVISION 5\n#define PERL_VERSION 45\n#define PERL_SUBVERSION 2\n"); +system('git', '-C', $perl_root, 'init', '-q') == 0 or die 'Cannot initialize fixture checkout'; +system('git', '-C', $perl_root, 'config', 'user.email', 'test@example.invalid') == 0 or die 'Cannot configure fixture checkout'; +system('git', '-C', $perl_root, 'config', 'user.name', 'Fixture') == 0 or die 'Cannot configure fixture checkout'; +system('git', '-C', $perl_root, 'add', '.') == 0 or die 'Cannot stage fixture checkout'; +system('git', '-C', $perl_root, 'commit', '-qm', 'fixture') == 0 or die 'Cannot commit fixture checkout'; + write_file(File::Spec->catfile($tools, 'generate.pl'), <<'GENERATOR'); #!/usr/bin/env perl use strict; use warnings; binmode STDOUT, ':raw'; -print "generated\n"; +for my $path ("$ENV{PERLONJAVA_UNICODE_ROOT}/table.txt", "$ENV{PERLONJAVA_PERL_ROOT}/source.pl") { + open my $input, '<:raw', $path or die $!; + print while <$input>; + close $input; +} GENERATOR my $output = File::Spec->catfile($output_dir, 'Data.java'); write_file($output, "stale\n"); @@ -59,6 +70,26 @@ is($status, 0, '--list succeeds without reading source data'); like($log, qr/^example\s+tools\/generate\.pl\s+generated\/Data\.java\s+/m, '--list exposes manifest provenance'); +# Schema 2 deliberately follows an explicitly supplied current checkout. The +# old hashes remain provenance for a later regeneration, but do not freeze the +# checkout to a historical Perl commit. +my $current_manifest = File::Spec->catfile($temporary, 'current-manifest.json'); +my $current_value = decode_json(read_file($manifest)); +$current_value->{schema_version} = 2; +$current_value->{perl_source_policy} = 'current-checkout'; +delete $current_value->{perl_commit}; +write_manifest($current_manifest, $current_value); +write_file(File::Spec->catfile($unicode, 'table.txt'), "moving current source\n"); +($status, $log) = run_pipeline_with_manifest($current_manifest, '--check'); +is($status, 255, 'current-checkout check rejects stale source provenance'); +like($log, qr/table\.txt SHA-256 mismatch/, 'stale current source is named'); +($status, $log) = run_pipeline_with_manifest($current_manifest, '--refresh'); +is($status, 0, 'refresh updates source provenance and dependent output'); +($status, $log) = run_pipeline_with_manifest($current_manifest, '--check'); +is($status, 0, 'refreshed current checkout is checkable'); +write_file(File::Spec->catfile($unicode, 'table.txt'), $source); +write_file($output, "stale\n"); + ($status, $log) = run_pipeline('--check'); is($status, 1, '--check rejects stale output'); like($log, qr/example: stale generated output/, 'stale output is identified'); @@ -114,12 +145,16 @@ is(read_file($output), $generated, 'nondeterminism leaves published output untou done_testing; sub run_pipeline { - my (@arguments) = @_; + return run_pipeline_with_manifest($manifest, @_); +} + +sub run_pipeline_with_manifest { + my ($selected_manifest, @arguments) = @_; my $error = gensym; my $pid = open3(undef, my $stdout, $error, $^X, $pipeline, '--root', $temporary, - '--manifest', $manifest, + '--manifest', $selected_manifest, '--unicode-root', $unicode, '--perl-root', $perl_root, @arguments); diff --git a/dev/tools/tests/run_phase36_regex_acceptance.t b/dev/tools/tests/run_phase36_regex_acceptance.t new file mode 100644 index 0000000000..2d61e6e67c --- /dev/null +++ b/dev/tools/tests/run_phase36_regex_acceptance.t @@ -0,0 +1,220 @@ +use strict; +use warnings; + +use File::Path qw(make_path); +use File::Spec; +use File::Temp qw(tempdir); +use FindBin; +use JSON::PP; +use Test::More; + +my $root = File::Spec->rel2abs( + File::Spec->catdir($FindBin::Bin, '..', '..', '..')); +my $tool = File::Spec->catfile($root, 'dev', 'tools', + 'run_phase36_regex_acceptance.pl'); +my $temporary = tempdir(CLEANUP => 1); +my $source = File::Spec->catdir($temporary, 'source'); +make_path($source); +system('git', 'init', '-q', $source) == 0 or die 'Cannot initialize source fixture'; +system('git', '-C', $source, 'config', 'user.email', 'fixture@example.test') == 0 or die 'Cannot configure fixture'; +system('git', '-C', $source, 'config', 'user.name', 'Fixture') == 0 or die 'Cannot configure fixture'; +write_file(File::Spec->catfile($source, 'tracked.txt'), "fixture\n"); +system('git', '-C', $source, 'add', 'tracked.txt') == 0 or die 'Cannot stage fixture'; +system('git', '-C', $source, 'commit', '-qm', 'fixture') == 0 or die 'Cannot commit fixture'; +my $artifacts = File::Spec->catdir($temporary, 'artifacts'); +make_path($artifacts); +my $test_file = File::Spec->catfile($temporary, 'focused.t'); +write_file($test_file, "1..1\nok 1\n"); +my $baseline = File::Spec->catfile($temporary, 'pr958.log'); +my $jar = File::Spec->catfile($temporary, 'perlonjava.jar'); +my $sbom = File::Spec->catfile($temporary, 'sbom.json'); +write_file($baseline, "[ 1/1] $test_file ... . 1/1 ok\n"); +write_file($jar, "fake jar\n"); +write_file($sbom, "{}\n"); + +my $record = File::Spec->catfile($temporary, 'calls.jsonl'); +my $ledger = fake_tool('ledger.pl', <<'LEDGER'); +use JSON::PP; +my ($list, $output); +while (@ARGV) { + my $arg = shift @ARGV; + $list = shift @ARGV if $arg eq '--runner-list'; + $output = shift @ARGV if $arg eq '--output'; +} +open my $lfh, '>:raw', $list or die $!; +print {$lfh} "$ENV{ACCEPT_TEST_FILE}\n"; +close $lfh; +open my $ofh, '>:raw', $output or die $!; +print {$ofh} JSON::PP->new->encode({summary => {unresolved_references => 0, runner_files => 1}}); +close $ofh; +LEDGER +my $runner = fake_tool('runner.pl', <<'RUNNER'); +use JSON::PP; +my @args = @ARGV; +my $output; +while (@ARGV) { + my $arg = shift @ARGV; + $output = shift @ARGV if $arg eq '--output'; +} +open my $rfh, '>>:raw', $ENV{ACCEPT_RECORD} or die $!; +print {$rfh} JSON::PP->new->canonical->encode({kind => 'runner', argv => \@args, + interpreter => $ENV{JPERL_INTERPRETER}}), "\n"; +close $rfh; +open my $ofh, '>:raw', $output or die $!; +print {$ofh} JSON::PP->new->encode({results => {}}); +close $ofh; +RUNNER +my $comparator = fake_tool('comparator.pl', <<'COMPARATOR'); +use JSON::PP; +my @args = @ARGV; +my $output; +while (@ARGV) { + my $arg = shift @ARGV; + $output = shift @ARGV if $arg eq '--output'; +} +open my $rfh, '>>:raw', $ENV{ACCEPT_RECORD} or die $!; +print {$rfh} JSON::PP->new->canonical->encode({kind => 'comparator', argv => \@args}), "\n"; +close $rfh; +open my $ofh, '>:raw', $output or die $!; +print {$ofh} JSON::PP->new->encode({summary => {candidate_files => 1}, + regressions => [], missing_files => [], added_files => [], + execution_issues => [], zero_tap => [], truncated => []}); +close $ofh; +COMPARATOR +my $packaging = fake_tool('packaging.pl', <<'PACKAGING'); +use JSON::PP; +open my $rfh, '>>:raw', $ENV{ACCEPT_RECORD} or die $!; +print {$rfh} JSON::PP->new->canonical->encode({kind => 'packaging', argv => \@ARGV}), "\n"; +close $rfh; +print "packaging fake passed\n"; +PACKAGING +my $jperl = fake_tool('jperl', <<'JPERL'); +#!/usr/bin/env perl +print "PerlOnJava fake $ENV{ACCEPT_SOURCE_SHA}\n"; +JPERL +chmod 0755, $jperl or die "Cannot chmod fake jperl: $!"; +open my $git, '-|', 'git', '-C', $source, 'rev-parse', 'HEAD' or die "Cannot run git: $!"; +my $source_sha = do { local $/; <$git> }; +close $git or die "Cannot close git: $?"; +chomp $source_sha; + +local $ENV{ACCEPT_TEST_FILE} = $test_file; +local $ENV{ACCEPT_RECORD} = $record; +local $ENV{ACCEPT_SOURCE_SHA} = $source_sha; +my @command = ($^X, $tool, '--prepare-only', + '--baseline', $baseline, '--artifact-dir', $artifacts, + '--jar', $jar, '--sbom', $sbom, + '--source-dir', $source, '--perl5-dir', $source, + '--jperl', $jperl, + '--ledger-tool', $ledger, '--runner-tool', $runner, + '--comparator-tool', $comparator, '--packaging-tool', $packaging, + '--timeout', 17, '--jobs', 3); +system @command; +is($? >> 8, 0, 'prepare-only composition with fake tools succeeds'); + +my $manifest = load_json(File::Spec->catfile($artifacts, 'manifest.json')); +is($manifest->{mode}, 'prepare-only', 'manifest records non-production mode'); +is($manifest->{expected_files}, 1, 'manifest records generated exact file count'); +is($manifest->{source}{starting_sha}, $manifest->{source}{final_sha}, + 'manifest records unchanged checkout HEAD'); +ok($manifest->{source}{perl5_sha_as_provenance} =~ /^[0-9a-f]{40}$/, + 'current perl5 revision is provenance'); +is($manifest->{verified_runner_sha}, $source_sha, 'manifest records verified runner SHA'); +for my $name (qw(regex-ledger.json regex-files.txt jvm-results.json + interpreter-results.json jvm-comparison.json interpreter-comparison.json + ledger.log jvm-runner.log interpreter-runner.log jvm-comparison.log + interpreter-comparison.log packaging.log)) { + ok($manifest->{artifacts}{$name}{sha256} =~ /^[0-9a-f]{64}$/, + "$name has a retained SHA-256"); +} +ok($manifest->{artifacts}{'jperl-version.log'}{sha256} =~ /^[0-9a-f]{64}$/, + 'retained jperl version log has a SHA-256'); + +my @calls = map { JSON::PP->new->decode($_) } + grep { length } split /\n/, read_file($record); +my @runner_calls = grep { $_->{kind} eq 'runner' } @calls; +is(scalar @runner_calls, 2, 'exactly JVM and interpreter runner legs execute'); +is($runner_calls[0]{interpreter} // '', '', 'JVM leg clears interpreter environment'); +is($runner_calls[1]{interpreter}, 1, 'interpreter leg sets interpreter environment'); +for my $call (@runner_calls) { + is_deeply([grep { /focused\.t\z/ } @{$call->{argv}}], [$test_file], + 'each runner receives the same exact generated file list'); + ok(grep($_ eq '--timeout', @{$call->{argv}}), 'runner receives existing timeout option'); +} +my @comparison_calls = grep { $_->{kind} eq 'comparator' } @calls; +is(scalar @comparison_calls, 2, 'both result legs are compared'); +for my $call (@comparison_calls) { + ok(grep($_ eq '--normalize-pr958-artifacts', @{$call->{argv}}), + 'comparison enables PR-958 normalization'); + ok(grep($_ eq '--fail-on-invalid', @{$call->{argv}}), + 'comparison is fail-closed for invalid records'); +} +is(scalar(grep { $_->{kind} eq 'packaging' } @calls), 1, + 'exact artifact packaging verification executes once'); + +my $sleeping_jperl = fake_tool('sleeping-jperl', <<'SLEEPING_JPERL'); +#!/usr/bin/env perl +sleep 30; +SLEEPING_JPERL +chmod 0755, $sleeping_jperl or die "Cannot chmod sleeping fake jperl: $!"; +my $timeout_artifacts = File::Spec->catdir($temporary, 'timeout-artifacts'); +make_path($timeout_artifacts); +my @timeout_command = @command; +for (my $i = 0; $i < @timeout_command; $i++) { + $timeout_command[$i + 1] = $sleeping_jperl + if $timeout_command[$i] eq '--jperl'; + $timeout_command[$i + 1] = $timeout_artifacts + if $timeout_command[$i] eq '--artifact-dir'; +} +push @timeout_command, '--version-timeout', 1; +my $timeout_output = capture_tool(@timeout_command); +is($? >> 8, 124, 'hung jperl identity probe exits with timeout status'); +like($timeout_output, qr/jperl-version timed out after 1s/, + 'hung identity probe has a specific timeout diagnostic'); + +done_testing; + +sub fake_tool { + my ($name, $contents) = @_; + my $path = File::Spec->catfile($temporary, $name); + write_file($path, $contents); + return $path; +} + +sub capture_tool { + my (@command) = @_; + pipe my $read, my $write or die "pipe: $!"; + my $pid = fork(); + die "fork: $!" unless defined $pid; + if ($pid == 0) { + close $read; + open STDOUT, '>&', $write or die $!; + open STDERR, '>&', $write or die $!; + exec { $command[0] } @command; + die "exec: $!"; + } + close $write; + my $output = do { local $/; <$read> }; + close $read; + waitpid($pid, 0); + return $output; +} + +sub write_file { + my ($path, $contents) = @_; + open my $fh, '>:raw', $path or die "Cannot write $path: $!"; + print {$fh} $contents; + close $fh or die "Cannot close $path: $!"; +} + +sub read_file { + my ($path) = @_; + open my $fh, '<:raw', $path or die "Cannot read $path: $!"; + my $contents = do { local $/; <$fh> }; + close $fh or die "Cannot close $path: $!"; + return $contents; +} + +sub load_json { + return JSON::PP->new->decode(read_file($_[0])); +} diff --git a/dev/tools/tests/verify_joni_packaging.t b/dev/tools/tests/verify_joni_packaging.t new file mode 100644 index 0000000000..788b7df41f --- /dev/null +++ b/dev/tools/tests/verify_joni_packaging.t @@ -0,0 +1,178 @@ +use strict; +use warnings; + +use File::Path qw(make_path); +use File::Find qw(find); +use File::Spec; +use File::Temp qw(tempdir); +use FindBin; +use IO::Compress::Zip qw($ZipError); +use JSON::PP; +use Test::More; + +my $root = File::Spec->rel2abs(File::Spec->catdir($FindBin::Bin, '..', '..', '..')); +my $tool = File::Spec->catfile($root, 'dev', 'tools', 'verify-joni-packaging.pl'); +my $temporary = tempdir(CLEANUP => 1); +my $joni_ref = 'pkg:maven/org.jruby.joni/joni@2.2.7?type=jar'; +my $jcodings_ref = 'pkg:maven/org.jruby.jcodings/jcodings@1.0.64?type=jar'; + +subtest 'green artifact has relocated classes, exact notices, and SBOM edge' => sub { + my ($jar, $sbom) = fixture('green'); + my ($status, $output) = run_tool($jar, $sbom); + is($status, 0, 'green artifact verifies'); + like($output, qr/verification passed/, 'green artifact reports success'); +}; + +subtest 'packaging entry failure families are fail-closed' => sub { + my ($missing_notice_jar, $sbom) = fixture('missing-notice', omit_notice => 1); + rejected($missing_notice_jar, $sbom, qr/missing joni-LICENSE/, 'absent notice'); + my ($wrong_notice_jar, $same_sbom) = fixture('wrong-notice', wrong_notice => 1); + rejected($wrong_notice_jar, $same_sbom, qr/notice bytes differ/, 'wrong notice bytes'); + my ($unrelocated_jar, $another_sbom) = fixture('unrelocated', unrelocated => 1); + rejected($unrelocated_jar, $another_sbom, qr/unrelocated Joni classes/, 'unrelocated class'); + my ($duplicate_class_jar, $duplicate_class_sbom) = + fixture('duplicate-class', duplicate_class => 1); + rejected($duplicate_class_jar, $duplicate_class_sbom, qr/duplicate class entry/, + 'duplicate relocated class'); + my ($duplicate_notice_jar, $duplicate_notice_sbom) = + fixture('duplicate-notice', duplicate_notice => 1); + rejected($duplicate_notice_jar, $duplicate_notice_sbom, qr/duplicate notice/, + 'duplicate notice'); +}; + +subtest 'SBOM failure families are fail-closed' => sub { + my ($jar, $sbom) = fixture('wrong-version', sbom => sub { $_[0]{components}[0]{version} = '9.9.9' }); + rejected($jar, $sbom, qr/wrong joni version/, 'wrong Joni version'); + ($jar, $sbom) = fixture('wrong-jcodings-version', sbom => sub { $_[0]{components}[1]{version} = '9.9.9' }); + rejected($jar, $sbom, qr/wrong jcodings version/, 'wrong JCodings version'); + ($jar, $sbom) = fixture('missing-joni', sbom => sub { shift @{$_[0]{components}} }); + rejected($jar, $sbom, qr/missing vendored joni/, 'missing Joni component'); + ($jar, $sbom) = fixture('missing-jcodings', sbom => sub { pop @{$_[0]{components}} }); + rejected($jar, $sbom, qr/missing vendored jcodings/, 'missing JCodings component'); + ($jar, $sbom) = fixture('duplicate-purl', sbom => sub { push @{$_[0]{components}}, { + type => 'library', 'bom-ref' => 'other', purl => $joni_ref, + group => 'example', name => 'other', version => '1' } }); + rejected($jar, $sbom, qr/duplicate purl/, 'duplicate purl'); + ($jar, $sbom) = fixture('missing-edge', sbom => sub { $_[0]{dependencies}[0]{dependsOn} = [] }); + rejected($jar, $sbom, qr/missing Joni -> JCodings dependency edge/, 'missing dependency edge'); + ($jar, $sbom) = fixture('duplicate-relation', sbom => sub { push @{$_[0]{dependencies}}, { ref => $joni_ref, dependsOn => [$jcodings_ref] } }); + rejected($jar, $sbom, qr/duplicate Joni dependency relations/, 'duplicate dependency relation'); + ($jar, $sbom) = fixture('bad-relation', sbom => sub { $_[0]{dependencies}[0]{dependsOn} = {} }); + rejected($jar, $sbom, qr/dependency relation is malformed/, 'non-array dependency relation'); + ($jar, $sbom) = fixture('malformed-json'); + write_file($sbom, '{ malformed'); + rejected($jar, $sbom, qr/Malformed SBOM JSON/, 'malformed SBOM'); +}; + +done_testing; + +sub fixture { + my ($name, %option) = @_; + my $tree = File::Spec->catdir($temporary, $name, 'tree'); + make_path(File::Spec->catdir($tree, 'org', 'perlonjava', 'internal', 'joni')); + make_path(File::Spec->catdir($tree, 'org', 'perlonjava', 'internal', 'jcodings')); + make_path(File::Spec->catdir($tree, 'META-INF', 'licenses')); + write_file(File::Spec->catfile($tree, 'org', 'perlonjava', 'internal', 'joni', 'Regex.class'), 'joni'); + write_file(File::Spec->catfile($tree, 'org', 'perlonjava', 'internal', 'jcodings', 'Encoding.class'), 'jcodings'); + if ($option{unrelocated}) { + make_path(File::Spec->catdir($tree, 'org', 'joni')); + write_file(File::Spec->catfile($tree, 'org', 'joni', 'Regex.class'), 'bad'); + } + my %source = ( + 'joni-LICENSE.txt' => File::Spec->catfile($root, 'third_party', 'joni', 'LICENSE'), + 'jcodings-LICENSE.txt' => File::Spec->catfile($root, 'third_party', 'licenses', 'jcodings-LICENSE.txt'), + 'joni-PERLONJAVA-NOTICE.md' => File::Spec->catfile($root, 'third_party', 'joni', 'PERLONJAVA-NOTICE.md'), + ); + for my $notice (keys %source) { + next if $option{omit_notice} && $notice eq 'joni-LICENSE.txt'; + my $bytes = read_file($source{$notice}); + $bytes = 'wrong' if $option{wrong_notice} && $notice eq 'joni-LICENSE.txt'; + write_file(File::Spec->catfile($tree, 'META-INF', 'licenses', $notice), $bytes); + } + my $jar = File::Spec->catfile($temporary, "$name.jar"); + if ($option{duplicate_class} || $option{duplicate_notice}) { + create_zip_fixture($jar, $tree, + $option{duplicate_class} + ? 'org/perlonjava/internal/joni/Regex.class' + : 'META-INF/licenses/joni-LICENSE.txt'); + } else { + system('jar', 'cf', $jar, '-C', $tree, '.'); + die "jar fixture failed" if $? != 0; + } + my $document = { + components => [ + { type => 'library', 'bom-ref' => $joni_ref, purl => $joni_ref, + group => 'org.jruby.joni', name => 'joni', version => '2.2.7' }, + { type => 'library', 'bom-ref' => $jcodings_ref, purl => $jcodings_ref, + group => 'org.jruby.jcodings', name => 'jcodings', version => '1.0.64' }, + ], + dependencies => [{ ref => $joni_ref, dependsOn => [$jcodings_ref] }], + }; + $option{sbom}->($document) if $option{sbom}; + my $sbom = File::Spec->catfile($temporary, "$name.json"); + write_file($sbom, JSON::PP->new->canonical->encode($document)); + return ($jar, $sbom); +} + +sub create_zip_fixture { + my ($jar, $tree, $duplicate) = @_; + my @names; + find({ no_chdir => 1, wanted => sub { + return unless -f $_; + my $name = File::Spec->abs2rel($_, $tree); + $name =~ s{\\}{/}g; + push @names, $name; + }}, $tree); + @names = sort @names; + push @names, $duplicate; + my $first = shift @names; + my $zip = IO::Compress::Zip->new($jar, Name => $first) + or die "Cannot create duplicate-entry fixture: $ZipError"; + print {$zip} read_file(File::Spec->catfile($tree, split m{/}, $first)); + for my $name (@names) { + $zip->newStream(Name => $name) + or die "Cannot add duplicate-entry fixture stream: $ZipError"; + print {$zip} read_file(File::Spec->catfile($tree, split m{/}, $name)); + } + close $zip or die "Cannot close duplicate-entry fixture: $ZipError"; +} + +sub rejected { + my ($jar, $sbom, $expected, $name) = @_; + my ($status, $output) = run_tool($jar, $sbom); + isnt($status, 0, "$name is rejected"); + like($output, $expected, "$name has specific diagnostic"); +} + +sub run_tool { + pipe my $read, my $write or die "pipe: $!"; + my $pid = fork(); + die "fork: $!" unless defined $pid; + if ($pid == 0) { + close $read; + open STDOUT, '>&', $write or die $!; + open STDERR, '>&', $write or die $!; + exec { $^X } $^X, $tool, @_[0, 1]; + die "exec: $!"; + } + close $write; + my $output = do { local $/; <$read> }; + close $read; + waitpid($pid, 0); + return ($? >> 8, $output); +} + +sub write_file { + my ($file, $contents) = @_; + open my $fh, '>:raw', $file or die "Cannot write $file: $!"; + print {$fh} $contents; + close $fh or die "Cannot close $file: $!"; +} + +sub read_file { + my ($file) = @_; + open my $fh, '<:raw', $file or die "Cannot read $file: $!"; + my $contents = do { local $/; <$fh> }; + close $fh or die "Cannot close $file: $!"; + return $contents; +} diff --git a/dev/tools/verify-joni-packaging.pl b/dev/tools/verify-joni-packaging.pl index 27e6760c92..7fdd614c5d 100644 --- a/dev/tools/verify-joni-packaging.pl +++ b/dev/tools/verify-joni-packaging.pl @@ -2,48 +2,128 @@ use strict; use warnings; +use Cwd qw(abs_path getcwd); +use File::Spec; +use File::Temp qw(tempdir); +use FindBin qw($Bin); use JSON::PP; die "Usage: $0 \n" unless @ARGV == 2; my ($jar_file, $sbom_file) = @ARGV; +die "Standalone JAR is missing or empty: $jar_file\n" unless -f $jar_file && -s $jar_file; +die "SBOM is missing or empty: $sbom_file\n" unless -f $sbom_file && -s $sbom_file; +$jar_file = abs_path($jar_file); +$sbom_file = abs_path($sbom_file); +my $root = abs_path(File::Spec->catdir($Bin, '..', '..')) + or die "Cannot resolve repository root from $Bin\n"; +my %notices = ( + 'joni-LICENSE.txt' => File::Spec->catfile($root, 'third_party', 'joni', 'LICENSE'), + 'jcodings-LICENSE.txt' => File::Spec->catfile($root, 'third_party', 'licenses', 'jcodings-LICENSE.txt'), + 'joni-PERLONJAVA-NOTICE.md' => File::Spec->catfile($root, 'third_party', 'joni', 'PERLONJAVA-NOTICE.md'), +); my %entries; open my $jar_fh, '-|', 'jar', 'tf', $jar_file or die "Cannot list $jar_file: $!\n"; while (my $entry = <$jar_fh>) { chomp $entry; - $entries{$entry} = 1; + $entries{$entry}++; } close $jar_fh or die "Cannot list $jar_file: jar exited with status $?\n"; +for my $entry (keys %entries) { + next unless $entry =~ m{^(?:org/joni/|org/jcodings/|org/perlonjava/internal/(?:joni|jcodings)/)} + && $entry =~ /\.class\z/; + die "Standalone JAR contains duplicate class entry $entry\n" if $entries{$entry} != 1; +} die "Standalone JAR contains unrelocated Joni classes\n" - if grep { m{^org/joni/} } keys %entries; + if grep { m{^org/joni/.*\.class\z} } keys %entries; die "Standalone JAR contains unrelocated JCodings classes\n" - if grep { m{^org/jcodings/} } keys %entries; + if grep { m{^org/jcodings/.*\.class\z} } keys %entries; +die "Standalone JAR contains retired regex backend selector\n" + if $entries{'org/perlonjava/runtime/regex/RegexBackendPolicy.class'}; die "Standalone JAR does not contain relocated Joni classes\n" - unless grep { m{^org/perlonjava/internal/joni/} } keys %entries; + unless grep { m{^org/perlonjava/internal/joni/.*\.class\z} } keys %entries; die "Standalone JAR does not contain relocated JCodings classes\n" - unless grep { m{^org/perlonjava/internal/jcodings/} } keys %entries; + unless grep { m{^org/perlonjava/internal/jcodings/.*\.class\z} } keys %entries; -for my $notice (qw( - joni-LICENSE.txt - jcodings-LICENSE.txt - joni-PERLONJAVA-NOTICE.md -)) { +for my $notice (sort keys %notices) { die "Standalone JAR is missing $notice\n" unless $entries{"META-INF/licenses/$notice"}; + die "Standalone JAR contains duplicate notice $notice\n" + unless $entries{"META-INF/licenses/$notice"} == 1; + die "Standalone JAR notice bytes differ for $notice\n" + unless jar_entry_bytes($jar_file, "META-INF/licenses/$notice") eq read_raw($notices{$notice}); } -open my $sbom_fh, '<', $sbom_file or die "Cannot open $sbom_file: $!\n"; -local $/; -my $sbom = JSON::PP->new->utf8->decode(<$sbom_fh>); -close $sbom_fh; - -my ($joni) = grep { - ($_->{group} // '') eq 'org.jruby.joni' - && ($_->{name} // '') eq 'joni' - && ($_->{version} // '') eq '2.2.7' -} @{$sbom->{components} // []}; -die "Combined SBOM is missing vendored Joni 2.2.7\n" unless $joni; +my $sbom = load_json($sbom_file); +my $components = $sbom->{components}; +die "Combined SBOM has no components array\n" unless ref $components eq 'ARRAY'; +my $dependencies = $sbom->{dependencies}; +die "Combined SBOM has no dependencies array\n" unless ref $dependencies eq 'ARRAY'; +my $joni_ref = 'pkg:maven/org.jruby.joni/joni@2.2.7?type=jar'; +my $jcodings_ref = 'pkg:maven/org.jruby.jcodings/jcodings@1.0.64?type=jar'; +assert_unique_component_ids($components); +assert_component($components, 'org.jruby.joni', 'joni', '2.2.7', $joni_ref); +assert_component($components, 'org.jruby.jcodings', 'jcodings', '1.0.64', $jcodings_ref); +my @relations = grep { ($_->{ref} // '') eq $joni_ref } @$dependencies; +die "Combined SBOM is missing Joni dependency relation\n" unless @relations; +die "Combined SBOM has duplicate Joni dependency relations\n" unless @relations == 1; +die "Combined SBOM Joni dependency relation is malformed\n" + unless ref $relations[0]{dependsOn} eq 'ARRAY'; +die "Combined SBOM is missing Joni -> JCodings dependency edge\n" + unless grep { $_ eq $jcodings_ref } @{$relations[0]{dependsOn}}; print "Joni packaging verification passed\n"; + +sub read_raw { + my ($file) = @_; + open my $fh, '<:raw', $file or die "Cannot read $file: $!\n"; + my $contents = do { local $/; <$fh> }; + close $fh or die "Cannot close $file: $!\n"; + return $contents; +} + +sub jar_entry_bytes { + my ($jar, $entry) = @_; + my $directory = tempdir(CLEANUP => 1); + my $original = getcwd(); + chdir $directory or die "Cannot enter temporary directory: $!\n"; + my $status = system('jar', 'xf', $jar, $entry); + my $error = $!; + chdir $original or die "Cannot return to $original: $!\n"; + die "Cannot extract $entry from $jar: $error\n" if $status != 0; + return read_raw(File::Spec->catfile($directory, split m{/}, $entry)); +} + +sub load_json { + my ($file) = @_; + my $document = eval { JSON::PP->new->utf8->decode(read_raw($file)) }; + die "Malformed SBOM JSON in $file: $@\n" unless $document && ref $document eq 'HASH'; + return $document; +} + +sub assert_unique_component_ids { + my ($components) = @_; + my (%refs, %purls); + for my $component (@$components) { + die "SBOM component is not an object\n" unless ref $component eq 'HASH'; + for my $field (['bom-ref', \%refs], ['purl', \%purls]) { + my ($name, $seen) = @$field; + next unless defined $component->{$name} && length $component->{$name}; + die "Combined SBOM has duplicate $name $component->{$name}\n" + if $seen->{$component->{$name}}++; + } + } +} + +sub assert_component { + my ($components, $group, $name, $version, $ref) = @_; + my @matching = grep { ($_->{group} // '') eq $group && ($_->{name} // '') eq $name } @$components; + die "Combined SBOM is missing vendored $name $version\n" unless @matching; + die "Combined SBOM has duplicate $name components\n" unless @matching == 1; + my $component = $matching[0]; + die "Combined SBOM has wrong $name version\n" unless ($component->{version} // '') eq $version; + die "Combined SBOM has wrong $name bom-ref\n" unless ($component->{'bom-ref'} // '') eq $ref; + die "Combined SBOM has wrong $name purl\n" unless ($component->{purl} // '') eq $ref; +} diff --git a/docs/design/joni-callout-fork.md b/docs/design/joni-callout-fork.md index 8784a22e63..0b37f41669 100644 --- a/docs/design/joni-callout-fork.md +++ b/docs/design/joni-callout-fork.md @@ -1,48 +1,74 @@ -# Vendored Joni Callout Engine - -## Purpose - -Perl executable regex constructs must run while the matcher owns provisional -captures and its backtracking stack. Stock Joni provides the required -stack-based matcher but does not expose match-time callbacks or unwind -notifications. PerlOnJava therefore vendors a minimally extended Joni engine. - -This document defines the current architecture and acceptance contract. Change -history, imported revision details, and completed-work records belong in Git -commit messages, not here. - -## Repository and dependency model - -- Joni is a pinned source snapshot in `third_party/joni`. Its production sources - and upstream tests are dedicated source sets in the root Gradle project. This - keeps the code boundary explicit without exposing the vendored engine as a - separately resolved project dependency. -- The source retains the upstream `org.joni` packages to keep changes reviewable - and suitable for upstream submission. -- The vendored project is the only Joni implementation on PerlOnJava's compile - and runtime classpaths. -- JCodings remains an upstream binary dependency because PerlOnJava does not - modify its encoding implementation. -- Automatic routing temporarily keeps ordinary patterns on Java. Patterns with - matcher features that Java cannot represent and the forced-Joni compatibility - gate use the vendored engine. The accepted final architecture removes Java - matching and the selector after semantic and performance parity. - -## Internal callout syntax - -The structured Perl regex frontend emits `(?{=CALL:})` for plain and -conditional callbacks and `(?{=DYNAMIC:})` for dynamic subprograms only in -an engine-facing skeleton. `` is a non-negative decimal index into the -callback table owned by that regex value. The fork parses these representations -into dedicated callout nodes; it never parses Perl source. +# Vendored Joni callout engine + +## Purpose and boundary + +Perl executable regex constructs run while the matcher owns provisional +captures and its backtracking stack. A post-match hook cannot implement their +semantics. PerlOnJava therefore maintains a Joni source fork with runtime-neutral +callout and dynamic-subprogram APIs. + +The fork is a matcher, not a Perl evaluator. It receives opaque integer IDs and +calls an interface; it never imports PerlOnJava runtime classes or parses Perl +callback bodies. The Perl frontend and runtime own source admission, closure +capture, `use re 'eval'`, diagnostics, and Perl-visible state. + +All production regexes use this fork. There is no Java matcher, and the legacy +`RegexPreprocessor` is absent. Limited Java source-policy scanning and adapter +token materialization still prepare admitted source for native Joni. The +remaining scanner rejects extended-class string properties and unresolved user +properties whose composition needs host context; it does not implement matcher +semantics. The historical +`RegexBackendPolicy` model exists only in test scope, while +`JoniRegexPattern.compatibilityPatternDescription` is a display compatibility +surface; neither can become alternate matcher input. + +## Source and dependency model + +Maintained sources live in `third_party/joni/src/org/joni` and retain upstream +`org.joni` packages so the fork remains reviewable. Gradle adds them to the main +source set and compiles imported fork tests from the separate `joniTest` source +set. JCodings remains an upstream binary dependency; the fork uses its encoding +and baseline fold primitives without depending on a modified JCodings API. + +The fork adds parser nodes, bytecode, matcher stack entries, and the following +public hooks: + +- `CalloutHandler`, `CalloutResult`, `CalloutAction`, and `MatchView`; +- `DynamicPatternResult` for host-supplied nested programs; +- `CharacterPropertyResolver` and its range result; +- `NamedCharacterResolver`; +- `WideScalarCodec`; +- `PerlPropertyValueMatcher` for runtime-neutral property-value wildcards. + +Keep these APIs free of `org.perlonjava` types. Engine tests should be expressible +with only Joni and JCodings classes. + +## Trusted engine syntax + +The structured Perl frontend represents executable parts separately from text. +`RuntimeRegexTemplate` assigns each part an index in the regex value's callback +table and stores a private slot sentinel. Sentinel starts in interpolated text +are escaped, and embedded callback-bearing regexes have their slots validated +and renumbered. Only `materializeTrustedCallouts()` converts validated slots to +engine-facing syntax immediately before Joni compilation: + +```text +(?{=CALL:}) +(?{=DYNAMIC:}) +``` -Runtime-interpolated pattern text must not be promoted to trusted skeleton -syntax. The PerlOnJava frontend remains responsible for preserving source -origin and rejecting injected internal tokens. +`` is a non-negative decimal table index. A CALL token is also used as an +internal conditional predicate when it occurs in a regex condition. +`StringSegmentParser` is the producer of callback AST parts, +`RuntimeRegexTemplate` builds their callback table, and `trustedCalloutCount` +bounds the IDs that Joni accepts. `maskCallouts()` shields trusted slots while +admitted runtime Perl source is reparsed. Literal or interpolated text spelling +`(?{=CALL:0})` has no slot provenance and therefore cannot address the callback +table. The fork remains deliberately unaware of Perl source provenance. -## Engine API +## Runtime-neutral API -The fork exposes a runtime-neutral API in `org.joni`: +The central interfaces are: ```java interface CalloutHandler { @@ -50,12 +76,7 @@ interface CalloutHandler { default DynamicPatternResult executeDynamic(int calloutId, MatchView match); void unwind(Object backtrackToken); default void complete(Object successfulToken) { unwind(successfulToken); } -} - -final class DynamicPatternResult { - Regex getRegex(); - CalloutHandler getCalloutHandler(); - Object getBacktrackToken(); + default void finish(boolean matched) {} } interface MatchView { @@ -63,223 +84,186 @@ interface MatchView { int captureCount(); int captureBegin(int capture); int captureEnd(int capture); + int lastClosedCapture(); + String controlMark(); +} + +final class DynamicPatternResult { + Regex getRegex(); + CalloutHandler getCalloutHandler(); + Object getBacktrackToken(); } ``` -The handler is installed on each `Matcher`, not on the compiled `Regex`, so a -shared compiled pattern can execute concurrently with runtime-local callback -state. - -`CalloutResult` selects `CONTINUE` or `FAIL` and may carry an opaque unwind -token. The engine neither interprets that token nor depends on PerlOnJava -runtime classes. - -`DynamicPatternResult` supplies a compiled nested program, its matcher-local -handler, and the token for the dynamic expression's provisional Perl state. The -default `executeDynamic` implementation fails fast, so handlers that only use -plain callouts remain source compatible. - -## Execution and unwind contract - -1. The callout opcode invokes the handler with the callout ID and a read-only - view of the current byte position and provisional capture boundaries. -2. A non-null token is stored in a matcher stack frame before execution - continues or fails. -3. Backtracking across that frame calls `unwind(token)` exactly once. -4. Successful completion calls `complete(token)` for every still-active token in - reverse execution order. Its default implementation delegates to `unwind`, - preserving the cleanup-only contract for engine-neutral handlers. -5. Failed completion, interruption, timeout, and handler exceptions unwind every - still-active token in reverse execution order. -6. A `FAIL` result enters normal matcher backtracking after installing the frame, - so cleanup follows the same path as later-pattern failure. -7. A dynamic callout resolves its nested program only when execution reaches - the opcode. The nested matcher yields one result at a time; an outer failure - resumes the nested matcher at its next alternative before the outer engine - backtracks past the dynamic frame. -8. Nested captures remain private to the nested matcher. Its endpoint advances - the outer input position, while outer capture numbering and match variables - remain unchanged. -9. Completing or abandoning a nested continuation propagates completion or - unwind to all of its active callback tokens exactly once. -10. Patterns without callout nodes allocate no handler state or callout frames. - -Callback conditions use an internal conditional-callout opcode. `CONTINUE` -selects the yes branch and `FAIL` selects the no branch without treating the -condition itself as a failed match. - -## Matcher-control boundaries - -`(*ACCEPT)` is represented as a dedicated AST node and bytecode opcode; it is -not rewritten into an assertion or callback. At execution it accepts the -nearest matcher-program boundary: - -- At the top level, it completes the whole match at the current input position - and skips the remaining pattern. -- In a subpattern call, it completes that call and resumes the caller after the - call site. -- In a positive lookahead, it completes the assertion, restores its zero-width - input position, and resumes the enclosing program. -- In a dynamic `(??{...})` program, it completes the nested matcher while the - enclosing matcher continues with its suffix. - -Captures opened inside the accepted boundary close at the current input -position. Captures outside that boundary remain active. Backtracking and -dynamic-continuation frames abandoned by acceptance are completed exactly once. -Because suffixes after a control verb are not necessarily reachable, programs -containing matcher-control opcodes bypass Joni's ordinary mandatory-literal and -minimum-length optimizer unless that optimizer becomes control-flow aware. - -## Structured Perl frontend - -Literal callback bodies are represented as lexical `SubroutineNode` closures. -The parser emits a `regexTemplate` operation whose ordered parts contain normal -interpolation values and explicit `regexCallback` wrappers. Runtime template -construction assigns callback IDs and produces the engine-facing skeleton. - -Optimistic callbacks use the same structured path. Standalone `(*{ code })` -callbacks execute as zero-width BLOCK callouts and publish their result through -`$^R`; `(?(*{ code })yes|no)` predicates execute as CONDITION callouts, select -their branch from the result's truth, and leave `$^R` unchanged. The matcher -publishes `$^N` from capture-close order rather than deriving it from `$+`, whose -meaning is the highest-numbered defined capture. - -An interpolated coderef remains ordinary interpolation because only the parser -can create a callback wrapper. Runtime strings containing Perl eval groups never -become trusted callback skeletons. They retain the existing security checks and, -where compatibility mode permits unsupported eval groups, the existing -zero-width no-op behavior. - -At execution, the bridge publishes provisional numbered captures and offsets, -runs the closure in scalar context, and updates `$^R` for plain callbacks only. -Each token checkpoints regex state, `$^R`, and the dynamic-local stack. Backtrack -unwind restores all three; successful completion restores dynamic scope while -retaining the last successful plain callback result. Dynamic locals created by -one callback remain active along the matcher's forward path, including later -callbacks, until that path is unwound or the match completes. The ordinary -closure epilogue therefore does not tear down a callback's local frame; the -matcher token owns it. - -Callback closures are Perl pseudo blocks, not ordinary subroutine or loop -boundaries. An unhandled `last`, `next`, `redo`, or `goto` cannot target a loop -or label outside the callback. The bridge converts escaped control flow to the -corresponding pseudo-block diagnostic before it can reach surrounding Perl -frames. Recursive callback re-entry has an engine-owned depth ceiling independent -of the JVM's configured native stack size. - -Every structured executable callback template selects Joni, including a -callback whose body happens to return a constant: `(?{ 1 })` still has match-time -side effects and unwind semantics. Runtime-dependent dynamic-pattern expressions -also select Joni and execute only when their opcode is reached. Semantically safe -constant expressions may use the compile-time fold path; constants with captures -or top-level alternatives remain dynamic so they cannot change outer grouping or -capture numbers. - -Literal match targets have one stable scalar identity per compiled call site so -`pos()` and `/g` survive repeated loop execution without allowing two identical -literal occurrences to share state. - -## Capture view - -Capture offsets are byte offsets relative to the matcher's input buffer, matching -Joni's native representation. Capture zero describes the provisional overall -match from the current match start to the current instruction position. Unset -captures return `Region.REGION_NOTPOS`. The bridge converts offsets to Perl -character positions when publishing match variables. - -The view is valid only during `execute`; handlers must copy any data they retain. -The engine must not allocate a `Region` snapshot for each callout. - -## Packaging and namespace isolation - -Source code remains in `org.joni`, but the standalone JAR relocates it to -`org.perlonjava.internal.joni`. JCodings is relocated to -`org.perlonjava.internal.jcodings` because Joni's API and implementation refer -to its classes. This lets an embedding application load PerlOnJava beside JRuby -or stock Joni without linkage collisions. - -The standalone JAR contains the unmodified Joni and JCodings license texts and a -separate PerlOnJava modification notice under `META-INF/licenses`. The SBOM must -identify the vendored Joni component, its upstream version, MIT license, and -JCodings dependency. - -## Regex preprocessing boundary - -Do not move the entire `RegexPreprocessor` into the Joni fork. The ownership -boundary is: - -- PerlOnJava owns Perl source policy and runtime integration: trusted callback - templates, `use re 'eval'` security, lexical warnings, user-defined Unicode - properties, Perl diagnostics, named/branch-reset capture mapping, and backend - selection. -- A backend-neutral Perl normalization layer may own syntax aliases shared by - all engines, such as accepted named-group spellings and modifier validation. -- Joni should own matcher semantics required by Perl, including condition - execution, backtracking-visible state, native capture behavior, case-folding - differences, and constructs that cannot be represented faithfully by textual - rewrites. -- The Java-only adapter retains Java `Pattern` syntax rewrites and stack-safety - workarounds only while the Java route exists. The Joni adapter may temporarily - materialize constructs whose native grammar is not complete, but it must use - Joni—not Java regex—to execute property-value wildcard expressions. - -Migration is incremental, but the destination is fixed: Joni becomes the sole -production matcher. Each preprocessing rule is classified as source policy, -backend-neutral syntax, Java adaptation, or matcher semantics. Matcher semantics -move into focused Joni changes with differential Perl tests. Java adaptation is -deleted with the Java route; source policy remains in PerlOnJava. - -The compatibility inventory is the regex section of -`docs/reference/feature-matrix.md`. The current selector routes subpattern -calls, conditions, control verbs, ASCII-strict folds, and every structured -executable callback template, including runtime `(??{...})`. Ordinary patterns -remain part of the forced-Joni corpus even before automatic routing changes. -Semantically safe constant dynamic expressions may still fold to pattern text; -embedded closures never become compile-time constants because their execution -and unwind are observable. - -## Remaining integration gates - -- Complete native extended character classes and a non-executing - `(?(DEFINE)...)` container, then delete their textual rewrites. -- Carry Perl charset mode and byte/Unicode provenance through property/class, - literal, reverse-expansion, and backreference folding. -- Parse nested property-value regex syntax inside Joni character properties and - remove adapter range materialisation. -- Restore original source names and exact Perl diagnostics after temporary - internal encodings. -- Remove Java matching, Java-only preprocessing, and backend selection after the - complete semantic and performance gates pass. - -## Verification - -- The complete imported Joni suite passes through the root build. -- Existing recursive-regex tests match stock Joni behavior. -- Focused tests cover provisional captures, repeated execution after - backtracking, `FAIL`, nested frames, handler exceptions, interruption, and - exact-once reverse-order unwind. -- Optimistic-callback tests cover standalone execution, conditional truth, - `$^R`, exact `$^N` capture-close order, `$+`, and alternative reachability. -- The standalone JAR contains no `org/joni` or `org/jcodings` classes, contains - both relocated trees, and includes all required notices. -- An embedding smoke test can load stock Joni and PerlOnJava together. -- Full `make` and the focused direct/thread regex matrix pass. -- The executable-callback and dynamic-pattern unit tests pass under standard - Perl and both PerlOnJava execution backends. -- Dynamic-pattern tests cover delayed expression evaluation, returned strings - and `qr//` values, private nested captures, outer-suffix backtracking, nested - callback cleanup, and recursive `qr//` values. -- Matcher-control tests cover top-level, empty, subpattern-call, positive - lookahead, and dynamic-program acceptance, including capture endpoints and - skipped callbacks. -- `dev/tools/perl_test_runner.pl perl5_t/t/re/` is compared file-by-file with - `../PerlOnJava/logs/test_20260815_080000_958.log`; no previously passing regex - file may regress, and changed pass counts or blocked-test totals are reported. - -## Stop conditions - -- Do not approximate callbacks as post-match hooks. -- Do not enable a callback form if provisional state or unwind is incomplete. -- Do not implement dynamic patterns as atomic nested matches; their alternatives - must participate in outer backtracking. -- Keep unsupported syntax fatal until its complete semantic gate passes. +`CalloutResult` chooses `CONTINUE` or `FAIL` and may carry an opaque token. +`MatchView` is read-only and valid only during the call; capture and position +values are Joni byte offsets, and unset captures use `Region.REGION_NOTPOS`. +`lastClosedCapture()` represents capture-close order for Perl's `$^N`, which is +not equivalent to the highest-numbered active capture. `controlMark()` exposes +the current backtracking-visible mark. + +The handler is installed on a `Matcher`, not on the compiled `Regex`. One +compiled program can therefore be shared while each operation keeps independent +callback state. Handlers that do not implement dynamic programs inherit a +fail-fast `executeDynamic` default. + +## Token lifecycle + +The matcher and handler share this exact contract: + +1. The callout opcode invokes the handler with its ID and provisional view. +2. A returned non-null token is stored in a matcher stack entry before normal + execution or failure continues. +3. Backtracking across that entry calls `unwind(token)` exactly once. +4. A token retained by the selected successful path receives + `complete(token)` exactly once, in reverse execution order. +5. A `FAIL` result enters ordinary backtracking after its token is registered. +6. Active tokens are resolved before `finish(true)` or `finish(false)` closes + the matcher invocation. +7. If a handler throws before returning a token, the handler must clean up state + created by that invocation; Joni cannot register a token it never received. + +`complete` defaults to `unwind`, so cleanup-only handlers remain valid. The Perl +bridge overrides completion because a successful callback retains different +state from an abandoned one. Patterns without callout nodes do not allocate +Perl callback handlers or callout stack frames. + +For the top-level matcher, `JoniRegexMatcher` calls `finish` after Joni resolves +the token stack. Joni's nested dynamic continuation calls its own handler's +`finish` when that continuation completes or is abandoned. + +## Dynamic subprograms + +`executeDynamic` returns a compiled nested `Regex`, its matcher-local handler, +and the token for the dynamic expression's provisional state. Joni creates a +nested matcher only when execution reaches the opcode. + +The nested matcher is a continuation, not an atomic boolean test. It yields one +candidate endpoint at a time; if the outer suffix fails, the outer matcher asks +the continuation for its next alternative before abandoning the dynamic frame. +Nested captures remain private, while the selected endpoint advances the outer +input. Completion or abandonment resolves every nested callback token and calls +the nested handler's `finish` exactly once. + +This behavior is required for `(??{...})`: expression evaluation is delayed, +returned strings and `qr//` values participate in outer backtracking, and a +recursive returned regex uses the same continuation contract. + +## Perl bridge + +`JoniRegexPattern.PerlCalloutHandler` is the runtime implementation. Before +running a closure it publishes provisional numbered captures and offsets. A +token checkpoints Perl regex/capture state, the prior `$^R`, dynamic-local +level, result metadata, and, for dynamic evaluation, the prior capture view. +The callback's `pos` value is published and restored around invocation; it is +not stored in the token. Control marks are exposed through `MatchView`, not +copied into every token. + +Plain callbacks run in scalar context and update `$^R`; conditional callbacks +select a branch without changing `$^R`. `$^N` comes from `lastClosedCapture`, +not from `$+`. Forward execution keeps callback locals visible to later +callbacks on the same path. `unwind` restores abandoned state; `complete` +restores dynamic scope while retaining the selected callback result; `finish` +publishes or restores the final operation state. + +Callback closures are Perl pseudo blocks. Unhandled `last`, `next`, `redo`, or +`goto` cannot escape into an enclosing Perl loop or label. Callback exceptions +restore the bridge's dynamic level even though no Joni token was returned. +The PerlOnJava pseudo-block runtime limits recursive callback re-entry to 1,024 +levels independently of JVM native stack size. + +Every parser-created executable callback remains match-time observable. A body +that happens to return a constant is not converted into a non-executable +pattern. Only semantically safe constant dynamic expressions may use the +compile-time fold path; captures or top-level alternatives keep a dynamic +program boundary. + +## Matcher control and optimization + +Control verbs are native AST nodes and opcodes. `(*ACCEPT)` accepts the nearest +matcher-program boundary: the whole top-level program, a subpattern call, a +positive lookahead, or a dynamic nested program. It closes captures opened in +that boundary at the current position and completes abandoned callback and +continuation frames exactly once. `(*FAIL)`, `(*PRUNE)`, `(*SKIP)`, `(*THEN)`, +`(*COMMIT)`, and mark forms likewise participate in native backtracking. + +Optimizer facts are derived from the Joni AST. Programs with control-verb state +or dynamic options bypass ordinary search optimization. Dynamic callout nodes +have unbounded maximum length, and Perl multi-fold nodes can suppress literal +and minimum-length facts when those facts would be unsafe. Do not restore an +optimizer shortcut without testing its control-flow, encoding, and fold +assumptions. + +## Encoding and property hooks + +Joni works in encoding byte offsets. Unicode programs use UTF-8; byte programs +use ISO-8859-1. PerlOnJava maps offsets at the adapter boundary. `WideScalarCodec` +lets the engine recognize PerlOnJava's reversible internal representation for +surrogate and above-Unicode scalar values without learning about Perl runtime +objects. + +`CharacterPropertyResolver.Result` carries inclusive Unicode and wide ranges +plus the property's case-fold policy. The parser preserves that provenance +through ordinary and extended class algebra. `NamedCharacterResolver` supplies +scalar names and sequences. `PerlPropertyValueMatcher` compiles the value-side +regex used by Perl property wildcards with Joni semantics. + +JCodings remains responsible for byte traversal and baseline folds. Generated +current-Perl tables and maintained Joni policy add Perl aliases, boundary rules, +simple and multi-code-point closure, byte provenance, and `/d`, `/u`, `/a`, and +`/aa` eligibility. + +The generated-data contract is maintained by the PerlOnJava adapter rather than +the runtime-neutral hook API. Registered property and fold tables are checked by +`dev/tools/generate_perl_unicode_data.pl --check`; scalar-name, +named-sequence, and Joni boundary tables currently use standalone generators +and require explicit regeneration and byte comparison. See the canonical +[regex implementation document](../../dev/implementation/regex.md#encoding-and-unicode-ownership) +for ownership and precedence details. + +## Packaging and notices + +Source packages stay `org.joni`, but the standalone JAR relocates Joni to +`org.perlonjava.internal.joni` and JCodings to +`org.perlonjava.internal.jcodings`. This prevents linkage collisions when an +embedding application also loads JRuby or stock Joni. + +The JAR contains byte-identical copies of: + +- `third_party/joni/LICENSE` as `META-INF/licenses/joni-LICENSE.txt`; +- `third_party/licenses/jcodings-LICENSE.txt`; +- `third_party/joni/PERLONJAVA-NOTICE.md` as + `META-INF/licenses/joni-PERLONJAVA-NOTICE.md`. + +The combined SBOM identifies vendored Joni 2.2.7, JCodings 1.0.64, their +licenses, and the Joni-to-JCodings dependency. Do not remove or rewrite upstream +copyright headers in maintained sources. + +## Change verification + +A fork change requires evidence at the boundary it modifies: + +- `make test-joni` for direct lexer, parser, compiler, optimizer, matcher, and + callout behavior; +- system-Perl validation followed by both PerlOnJava execution backends for + changed Perl fixtures; +- focused callback tests for provisional captures, `$^R`, `$^N`, dynamic + locals, exceptions, exact-once unwind/completion, and nested continuations; +- matcher-control tests for top-level, subpattern, lookahead, and dynamic + program boundaries; +- `make` for the complete unit, fork, packaging, and notice gate; +- the Gradle `verifyJoniPackaging` task, run by `make`, which invokes + `dev/tools/verify-joni-packaging.pl` with the standalone JAR and merged SBOM; +- the imported `perl5_t/t/re/` corpus compared file by file against its accepted + baseline. + +Never approximate callbacks as post-match hooks, dynamic patterns as atomic +nested matches, or control verbs as source rewrites. Unsupported syntax remains +fatal unless the explicit development-only `JPERL_UNIMPLEMENTED=warn` policy is +requested; that downgrade is not semantic support. + +Related documents: + +- [Regex implementation](../../dev/implementation/regex.md) +- [Phase 36 acceptance plan](../../dev/design/phase36-regex-parity.md) +- [Standalone library RFC](../../dev/design/perl-regex-library-rfc.md) (proposal only) diff --git a/docs/reference/feature-matrix.md b/docs/reference/feature-matrix.md index ee983512da..3028d63cd3 100644 --- a/docs/reference/feature-matrix.md +++ b/docs/reference/feature-matrix.md @@ -353,63 +353,60 @@ my @copy = @{$z}; # ERROR --- ## Regular Expressions -- ✅ **Basic Matching**: Operators `qr//`, `m//`, `s///`, `split` are implemented. -- ✅ **Regex modifiers**: Modifiers `/p` `/i` `/m` `/s` `/n` `/g` `/c` `/r` `/e` `/ee` `/x` `/xx` are implemented. -- ✅ **Special variables**: The special variables `$1`, `$2`... are implemented. -- ✅ **Transliteration**: `tr` and `y` transliteration operators are implemented. -- ✅ **`pos`**: `pos` operator is implemented. -- ✅ **`\G`**: `\G` operator in regex is implemented. -- ✅ **`\N{name}`**: `\N{name}` and `\N{U+hex}` operator for named characters in regex is implemented. -- ✅ **`\N`**: Not-newline operator. -- ✅ **lvalue `pos`**: lvalue `pos` operator is implemented. -- ✅ **`m?pat?`** one-time match is implemented. -- ✅ **`reset`** resetting one-time match is implemented -- ✅ **`@-`, `@+`, `%+`, `%-`, `@{^CAPTURE}`, `${^LAST_SUCCESSFUL_PATTERN}` variables**: regex special variables are implemented -- ✅ **`$&` variables**: `` $` ``, `$&`, `$'`, `$+` special variables are implemented, and aliases: `${^PREMATCH}`, `${^MATCH}`, `${^POSTMATCH}`. -- ✅ **`[[:pattern:]]`**: `[[:ascii:]]`, `[[:print:]]` are implemented. -- ✅ **Matching plain strings**: `$var =~ "Test"` is implemented. -- ✅ **Inline comments**: `(?#comment)` in regex is implemented. -- ✅ **caret modifier**: `(?^` embedded pattern-match modifier, shorthand equivalent to "d-imnsx". -- ✅ **\b inside character class**: `[\b]` is supported in regex. -- ✅ **Vertical whitespace escapes**: Native Joni `\v` matches U+000A..U+000D, U+0085, U+2028, and U+2029; `\V` matches the complement. Direct and character-class forms match Perl, and `reg_posixcc.t` passes 2,560/2,560 on both execution backends. -- ✅ **Unicode boundary assertions**: `\b{gcb}`, `\b{sb}`, `\b{wb}`, and `\b{lb}` (and their `\B` forms) execute natively in Joni from reproducible pinned Perl 5.44 Unicode 17.0 data. The complete 239,866-assertion generated boundary corpus passes on both backends. -- ✅ **Variable Interpolation in Regex**: Features like `${var}` for embedding variables. -- ✅ **Non-capturing groups**: `(?:...)` is implemented. -- ✅ **Named Capture Groups**: Defining named capture groups using `(?...)` or `(?'name'...)` is supported. -- ✅ **Backreferences to Named Groups**: Using `\k` or `\g{name}` for backreferences to named groups is supported. -- ✅ **Relative Backreferences**: Using `\g{-n}` for relative backreferences. -- ✅ **Basic Unicode Properties**: Common `\p{...}` and `\P{...}` forms such as `\p{L}` execute through Joni. General_Category assignments now enter the forked Joni parser unchanged and resolve to pinned Perl ranges there. -- 🟡 **Perl Unicode Property Syntax**: Perl-specific properties execute through Joni from generated pinned Perl 5.44 Unicode 17.0 data. Exact assignments use Joni's range-resolver API with explicit per-family fold policy. Property-value wildcard expressions are compiled and executed by the forked Joni matcher, then temporarily materialized as selected ranges by the adapter; Java regex no longer evaluates them. No-fold properties inside composed classes and some generated alias/diagnostic cases remain migration work. -- 🟡 **Named Unicode Sequences**: A generated pinned 461-entry Perl Unicode 17 table resolves multi-code-point `\\N{name}` sequences before scalar names in strings and Joni patterns. Temporary internal encoding and exact diagnostics for unknown or restricted class uses remain migration work. -- ✅ **Possessive Quantifiers**: Quantifiers like `*+`, `++`, `?+`, and `{n,m}+`, which disable backtracking, are supported. -- ✅ **Atomic Grouping**: Use of `(?>...)` for atomic groups is supported. -- ✅ **`\K` assertion**: Keep left — in `s///`, text before `\K` is preserved; match variables reflect only the portion after `\K`. Ordinary KEEP assertions route through native Joni and no longer use the Java marker rewrite; the adapter still rejects KEEP inside lookaround until the Joni analyser emits Perl's diagnostic directly. -- ✅ **Preprocessor**: `\Q`, `\L`, `\U`, `\l`, `\u`, `\E` are preprocessed in regex. -- ✅ **Overloading**: `qr` overloading is implemented. See also [overload pragma](#pragmas). -- ✅ **Python-style named groups**: `(?P...)` and `(?P=name)` are parsed natively by Joni with Perl capture numbering, duplicate-name behavior, and malformed/unknown-name diagnostics. -- ✅ **Alpha assertion aliases**: `(*pla:...)`, `(*plb:...)`, `(*nla:...)`, `(*nlb:...)`, `(*atomic:...)`, and the corresponding long spellings are parsed natively by Joni with Perl nesting, capture numbering, backtracking, assertion-condition predicates, and malformed-form diagnostics. -- 🟡 **Underscored numeric regex escapes**: Joni natively parses Perl spellings such as `\x{0_0_4_1}` and `\o{0_0_1_0_1}` through U+10FFFF, including literal/class forms, bare high-octal UTF-8 code points, truncation behavior, and structural diagnostics. The frontend normalization remains for forced-Java compatibility; exact `use re 'strict'` diagnostics and Perl code points above U+10FFFF through signed IV max remain source-policy/representation debt. - -- ✅ **Dynamically-scoped regex variables**: Provisional captures, `$^R`, `$^N`, match positions, and callback locals follow matcher paths and unwind on backtracking. -- ✅ **Recursive and Dynamic Patterns**: `(?R)`, `(?0)`, and runtime `(??{ code })` execute through Joni. Dynamic expressions may return strings or `qr//` values, nested alternatives participate in outer backtracking without changing outer grouping or capture numbering, and callback and pure-pattern recursion have engine-owned depth ceilings. -- ✅ **Backtracking Control Verbs**: `(*ACCEPT)`, `(*FAIL)`/`(*F)`, `(*PRUNE)`, `(*SKIP)`, `(*THEN)`, and `(*COMMIT)` execute through Joni with matcher-owned cut boundaries. Atomic groups `(?>...)` are supported. -- ✅ **Marks and named skip targets**: `(*MARK:NAME)` and its `(*:NAME)` shorthand, named `(*SKIP:NAME)`, `$REGMARK`, and `$REGERROR` execute through Joni and follow the selected backtracking path. -- 🟡 **Regex Definitions**: `(?(DEFINE)...)` containers and numbered or named calls to their subpatterns execute through Joni. The frontend still rewrites the non-executing container into an equivalent internal form; native Joni ownership and removal of that rewrite remain in progress. -- ✅ **Lookbehind Assertions**: Fixed and bounded variable-length positive and negative lookbehind assertions execute through Joni, including nested lookahead. Removing the remaining compatibility routing requires the complete lookbehind corpus and native diagnostics to pass. -- ✅ **Branch Reset Groups**: `(?|...)` resets capture numbering across alternatives and preserves mapped match variables. -- ✅ **Advanced Subroutine Calls**: Sub-pattern calls with numbered or named references like `(?1)` and `(?&name)` execute through Joni. -- ✅ **Conditional Expressions**: Numbered and named capture conditions, positive and negative assertion conditions, recursion conditions `(?(R))`, `(?(R1))`, and `(?(R&name))`, executable callback conditions, and optimistic predicates execute through Joni. -- 🟡 **Extended Unicode Regex Features**: Generated Perl property families, invalid-property gates, and Unicode boundaries execute through Joni. The complete property corpus currently passes 83,616/83,648 identically on JVM and interpreter; the 32 residual assertions are only deprecated `Hyphen`/`IsHyphen` warning diagnostics, while membership assertions pass. Boundary, grapheme, sentence, word, and line corpora have their separate complete gates below. -- ✅ **Extended Grapheme Clusters**: Native `\b{gcb}`/`\B{gcb}` implement GB1–GB13 and GB999, and `\X` includes repeated GB9c Indic conjuncts. The complete 8,516-assertion GCB/`\X` section of authoritative chunk 05 passes identically on JVM and interpreter. -- ✅ **Unicode Sentence Boundaries**: Native `\b{sb}`/`\B{sb}` implement SB1–SB11 and SB998 from the reproducible Perl 5.44 Unicode 17.0 sentence-break table. Authoritative chunk 05 passes 14,976/14,976 identically on JVM and interpreter. -- ✅ **Unicode Word Boundaries**: Native `\b{wb}`/`\B{wb}` implement WB1–WB16 and WB999 from reproducible Perl 5.44 Unicode 17.0 word-break and extended-pictographic tables. Authoritative chunk 10 passes 19,510/19,510 identically on JVM and interpreter. -- ✅ **Unicode Line Boundaries**: Native `\b{lb}`/`\B{lb}` implement Unicode 17 UAX #14 from reproducible pinned line-break, category, width, and emoji tables. Authoritative chunks 06–09 pass 205,380/205,380 identically on JVM and interpreter. -- ✅ **Embedded Code in Regex**: `(?{ code })`, optimistic callbacks `(*{ code })`, executable callback conditions, and `(??{ code })` run as lexical closures in Joni with provisional captures and backtracking unwind. Callback `local` frames follow matcher paths, and escaped loop control or `goto` stops at the callback pseudo-block boundary. `$^N` follows capture-close order independently of `$+`. -- ✅ **Regex Debugging**: Lexically scoped `use/no re 'debug'` and `debugcolor` are supported, including runtime snapshot ownership. -- ✅ **Runtime Regex Evaluation**: `use re 'eval'` controls whether interpolated patterns containing eval groups may compile. Admitted runtime source is compiled into lexical callback closures and preserves its package, visible lexical cells, Unicode or byte source type, default regex modifiers, and match-once state. Literal callbacks, interpolated `qr//` values (including local, referenced, and tied arrays), raw runtime eval groups, callback conditions, and standalone `(?(DEFINE)...)` containers may be composed in one Joni pattern; dynamic callbacks may return further admitted executable source. -- ✅ **Regex Compilation Flags**: Lexically scoped default flags from `use/no re '/imsx'` are applied to literal, interpolated, and runtime-compiled regex values. -- 🟡 **Perl capture and ASCII fold modifiers**: Top-level and scoped `/n` suppress unnamed captures. `/a` and `/aa` matching is available through the Joni path, but native property/class closure, byte/Unicode provenance, literal reverse expansion, and backreference folding are still being moved from adapter protections into the fork. -- ✅ **Perl Named Captures**: Names may contain underscores, and duplicate named groups preserve Perl-style `%+`/`%-` and backreference behavior. + +All production matching uses the vendored Joni fork through `RuntimeRegex` and +`JoniRegexPattern`; there is no production Java matcher or preprocessor route. +A test-scope-only `RegexBackendPolicy` model compiles immutable compatibility +tests but is absent from production packaging. Status below means +the named behavior is demonstrated by source and a focused gate, not that every +Perl diagnostic, optimizer path, or complete upstream corpus is closed. + +The review covers the current `perl5/pod/perlreref.pod`, `perlrecharclass.pod`, +`perlrequick.pod`, `perlrepository.pod`, `perlre.pod`, `perlretut.pod`, and +`perlrebackslash.pod` inventory. POD syntax examples are grouped by semantic +family; documentation headings such as NAME, DESCRIPTION, BUGS, SEE ALSO, +AUTHORS, and repository prose are intentionally excluded from capability +claims. The review classified 565 inventory rows: 516 map to a capability +family, 42 are intentional descriptive/tutorial exclusions, and seven record +the source POD files; no rows were left unclassified. + +| Family | Status | Supported behavior and evidence | Boundary | +|---|---|---|---| +| Operations, interpolation, and state | ✅ | `qr//`, `m//`, `s///`, `split`, `tr///`, `y///`, interpolation, `m?PAT?`, `reset`, `/g`, `/c`, `pos`, `\G`, match offsets, `$1`, `$&`, `$'`, `$+`, `%+`, and `%-`; `RuntimeRegex.java`, `regex_g_pos.t`, `regex_c_pos.t`, `regex_once.t`, `regex_mark_control.t`. | Reuse and state are runtime-local; complete corpus parity remains a release gate. | +| Modifiers and quoting | 🟡 | `/i`, `/m`, `/s`, `/p`, `/n`, `/x`, `/xx`, `/g`, `/c`, `/r`, `/e`, `/ee`, `(?^...)`, scoped option groups, `(?#...)`, `\Q...\E`, and case escapes; `RegexFlags.java`, `RegexQuoteMeta.java`, `regex_xx.t`, `regex_n.t`, `re_debug_pragma.t`. | `/d`, `/u`, `/l`, `/a`, and `/aa` provenance and folding differ by pattern/subject mode; unresolved portions are partial rather than a Java fallback. | +| Atoms, quantifiers, and ordinary classes | 🟡 | Literals, `.`, anchors, alternation, captures/non-captures, greedy/lazy/possessive quantifiers, atomic groups, `\K`, POSIX classes, `\d`, `\w`, `\s`, `\h`, `\v`, `\R`, `\N`, and `\X`; `JoniRegexPattern.java`, `regex_possessive_quantifier.t`, `regex_atomic_group.t`, `joni_keep_progress.t`, `vertical_whitespace_escape.t`. | Forward/reverse literal and character-class fold expansion remains an open semantic gate; KEEP in lookaround and exact malformed-pattern wording are also partial. | +| Escapes, numeric forms, and references | 🟡 | Control, octal, hexadecimal, named, absolute, relative, and named references are parsed by Joni; `numeric_escape_underscores.t`, `native_numeric_backreference_boundaries.t`, `native_escape_named_reference_diagnostics.t`, `joni_relative_group_call_diagnostics.t`. | Exact `re 'strict'` messages and values outside ordinary Unicode/signed scalar representation remain divergent. | +| Unicode properties, names, and character-class algebra | 🟡 | Current-Perl generated properties, aliases, POSIX compatibility, `\p`/`\P`, `\N{name}`, multi-code-point names, `(?[...])`, and property-value wildcards execute in Joni; `UnicodeResolver.java`, `unicode_all_property.t`, `unicode_named_sequences.t`, `joni_named_character_sequences.t`, `unicode_property_value_wildcards.t`, `extended_more_character_class.t`. | Exact unknown/restricted-name and property diagnostics, plus remaining fold/provenance cases, are partial. Generated data refreshes from the latest upstream checkout rather than a pinned Perl SHA. | +| Captures, names, branch reset, and backreferences | 🟡 | Perl and Python named captures, duplicate names, numbered/relative/named backreferences, `(?|...)`, `/n`, and capture publication; `branch_reset_capture_semantics.t`, `branch_reset_named_call.t`, `regex_duplicate_named_backreference.t`, `regex_named_capture.t`, `casefold_literal_backreference.t`, `joni_ascii_strict_backreference_folds.t`. | Case-insensitive backreference folding is covered for existing cases, but its full-fold/charset interaction shares the unresolved literal/class fold boundary; malformed-reference diagnostics remain partial. | +| Lookarounds and alpha aliases | 🟡 | Positive/negative lookahead, fixed and bounded lookbehind, nested assertions, and `(*pla:...)`/`(*plb:...)`/`(*nla:...)`/`(*nlb:...)`; `lookbehind_native_acceptance.t`, `extended_unicode_lookbehind.t`, `alpha_assertion_native_routing.t`. | Variable-width limits, KEEP-in-lookaround, and exact failure positions remain partial. | +| Calls, recursion, DEFINE, and conditions | ✅ | `(?R)`, `(?0)`, numbered/named/signed-relative calls, `(?(DEFINE)...)`, capture/assertion/recursion conditions, and branch-reset calls; `recursive_patterns.t`, `joni_whole_pattern_recursion.t`, `recursion_conditions.t`, `conditional_native_routing.t`. | Engine depth ceilings and remaining malformed-condition diagnostics are explicit limits. | +| Code groups and dynamic programs | 🟡 | Parser-created `(?{...})`, `(*{...})`, callback conditions, and `(??{...})` execute as matcher-local Joni callouts with backtracking unwind; dynamic values may be strings or `qr//`; `executable_callbacks.t`, `dynamic_patterns.t`, `native_dynamic_pattern_contract.t`, `callback_exception_unwind.t`. | Raw runtime executable text requires `use re 'eval'`; untrusted interpolated callback text is not promoted to executable code. | +| Control verbs and marks | ✅ | `(*ACCEPT)`, `(*FAIL)`/`(*F)`, `(*PRUNE)`, `(*SKIP)`, `(*THEN)`, `(*COMMIT)`, `(*MARK:NAME)`, `(*:NAME)`, `$REGMARK`, and `$REGERROR`; `perl_control_verbs.t`, `control_verb_paths.t`, `named_accept_fail_control_verbs.t`, `regex_mark_control.t`. | Optimizer behavior intentionally yields to matcher control flow; performance evidence is separate. | +| Unicode boundaries and byte behavior | 🟡 | `\b{gcb}`, `\b{sb}`, `\b{wb}`, `\b{lb}`, `\B` forms, UTF-8 offset mapping, byte-mode identity mapping, and wide scalar encoding; `grapheme_boundary_rules.t`, `sentence_boundary_rules.t`, `word_boundary_rules.t`, `line_boundary_rules.t`, `wide_scalar_engine_semantics.t`. | Charset-mode folds and byte-backed class provenance are active partial work. | +| Warnings, diagnostics, debug, and performance | 🟡 | Source-positioned compile errors, `use re 'strict'` policy, `use/no re 'debug'`, `debugcolor`, and warning inheritance; `RegexDiagnosticFormatter.java`, `frontend_regex_diagnostic_provenance.t`, `native_compile_diagnostics.t`, `re_debug_pragma.t`. | Remaining native lexer/parser diagnostic families and optimizer `speed*` behavior are active work; parser acceptance is not proof of exact Perl diagnostics. | +| Custom engines and non-Perl interfaces | ❌ | `perlre` custom regex-engine hooks and host-defined engine protocols are not implemented. | PerlOnJava supports its bundled Joni engine only. | + +### Pending final integrated verification + +This first-pass matrix is pinned to integrated parent +`5054f236ea8533c46b1068275bdbd703c3207ace`. A later pass may promote only rows +whose required tests pass on the final immutable integration artifact: + +- `/d` byte-backed class provenance and its charset/fold interaction; +- remaining native lexer/parser diagnostics and exact source-position wording; +- optimizer-sensitive literal/fold search behavior, including the `speed*` + corpus. + +No result is predicted here; until that artifact exists, these boundaries remain +partial regardless of progress in POJ3, POJ4, or POJ5 worktrees. + +The current source-level architecture is described in +[`dev/implementation/regex.md`](../../dev/implementation/regex.md) and the +runtime-neutral callback/packaging contract in +[`docs/design/joni-callout-fork.md`](../design/joni-callout-fork.md). The Phase +36 plan remains the authority for integration and release completion; active +P3 `/d` provenance, P4 diagnostic, and P5 optimizer work is deliberately marked +partial here until its commits and shared gates are integrated. ## Statements and Special Operators diff --git a/src/main/java/org/perlonjava/backend/bytecode/BytecodeCompiler.java b/src/main/java/org/perlonjava/backend/bytecode/BytecodeCompiler.java index 724d644097..f0ea3aa046 100644 --- a/src/main/java/org/perlonjava/backend/bytecode/BytecodeCompiler.java +++ b/src/main/java/org/perlonjava/backend/bytecode/BytecodeCompiler.java @@ -2,7 +2,6 @@ import org.perlonjava.backend.jvm.EmitterContext; -import org.perlonjava.backend.jvm.EmitterMethodCreator; import org.perlonjava.frontend.analysis.ConstantFoldingVisitor; import org.perlonjava.frontend.analysis.FindDeclarationVisitor; import org.perlonjava.frontend.analysis.RegexUsageDetector; @@ -132,9 +131,6 @@ private void emitNormalLoopResult() { // separately from the register table because closure analysis may first // materialize a reference as a lexical before the body reaches `local`. private final Set capturedOurVariableNames = new HashSet<>(); - // BEGIN support for named subroutine closures - int currentSubroutineBeginId = 0; // BEGIN ID for current named subroutine (0 = not in named sub) - Set currentSubroutineClosureVars = new HashSet<>(); // Variables captured from outer scope // EmitterContext for strict checks and other compile-time options private EmitterContext emitterContext; // Register allocation @@ -143,6 +139,9 @@ private void emitNormalLoopResult() { private int maxRegisterEverUsed = 2; // Track highest register ever allocated // True when this compiler was constructed for eval STRING (has parentRegistry) private boolean isEvalString; + // Runtime regex interpolation can synthesize executable source through + // overload, so the containing CV must expose all of its live lexical cells. + private boolean tracksRuntimeRegexLexicals; // True when compiling inside a defer block (control flow out of defer is prohibited) private boolean isInDeferBlock; // True when compiling inside a map/grep block (explicit return must use RETURN_NONLOCAL) @@ -866,6 +865,14 @@ public InterpretedCode compile(Node node, EmitterContext ctx) { // Store context for strict checks and other compile-time options this.emitterContext = ctx; + if (node != null) { + VariableCollectorVisitor runtimeSourceCollector = + new VariableCollectorVisitor(new HashSet<>()); + node.accept(runtimeSourceCollector); + tracksRuntimeRegexLexicals = + runtimeSourceCollector.requiresAllRuntimeLexicals(); + } + // Detect closure variables if context is provided if (ctx != null) { detectClosureVariables(node, ctx); @@ -994,6 +1001,7 @@ public InterpretedCode compile(Node node, EmitterContext ctx) { // Set optimization flag - if no LOCAL_* or PUSH_LOCAL_VARIABLE opcodes were emitted, // the interpreter can skip DynamicVariableManager.getLocalLevel/popToLocalLevel code.usesLocalization = this.usesLocalization; + code.tracksRuntimeRegexLexicals = this.tracksRuntimeRegexLexicals; // Attach the `our` registry so eval STRING can inherit caller's `our` aliases code.ourVariableRegistry = ourVariableRegistry.isEmpty() ? null : ourVariableRegistry; // Store goto label map for dynamic goto support (goto $variable) @@ -1037,7 +1045,7 @@ private void detectClosureVariables(Node ast, EmitterContext ctx) { Set used = new HashSet<>(); VariableCollectorVisitor collector = new VariableCollectorVisitor(used); ast.accept(collector); - if (!collector.hasEvalString()) { + if (!collector.requiresAllRuntimeLexicals()) { usedVars = used; } } @@ -1440,6 +1448,11 @@ public void visit(BlockNode node) { // EmitBlock.emitPostBlockStrictOptions() in the JVM backend. Object postBlockStrictOptions = node.getAnnotation("postBlockStrictOptions"); if (postBlockStrictOptions instanceof Integer hints) { + if (!node.getBooleanAnnotation("blockIsSubroutine")) { + Object postBlockWarningBits = node.getAnnotation("postBlockWarningBits"); + emit(Opcodes.SET_CALL_SITE_WARNING_BITS); + emit(addToStringPool(postBlockWarningBits instanceof String bits ? bits : "")); + } emit(Opcodes.SET_CALL_SITE_HINTS); emit(hints); } @@ -1826,18 +1839,9 @@ void handleArrayElementAccess(BinaryOperatorNode node, OperatorNode leftOp) { String varName = ((IdentifierNode) leftOp.operand).name; String arrayVarName = "@" + varName; - // Get the array register - check closure, lexical, then global + // Get the array register - check lexical, then global int arrayReg; - if (currentSubroutineBeginId != 0 && currentSubroutineClosureVars != null - && currentSubroutineClosureVars.contains(arrayVarName) - && !isDynamicOurVariable(arrayVarName)) { - arrayReg = allocateRegister(); - int nameIdx = addToStringPool(arrayVarName); - emitWithToken(Opcodes.RETRIEVE_BEGIN_ARRAY, node.getIndex()); - emitReg(arrayReg); - emit(nameIdx); - emit(currentSubroutineBeginId); - } else if (hasVariable(arrayVarName) && !isOurVariable(arrayVarName)) { + if (hasVariable(arrayVarName) && !isOurVariable(arrayVarName)) { arrayReg = getVariableRegister(arrayVarName); } else { // 'our' arrays (or undeclared globals) must be fetched from the global @@ -1940,16 +1944,7 @@ void handleArraySlice(BinaryOperatorNode node, OperatorNode leftOp) { String varName = ((IdentifierNode) leftOp.operand).name; String arrayVarName = "@" + varName; - if (currentSubroutineBeginId != 0 && currentSubroutineClosureVars != null - && currentSubroutineClosureVars.contains(arrayVarName) - && !isDynamicOurVariable(arrayVarName)) { - arrayReg = allocateRegister(); - int nameIdx = addToStringPool(arrayVarName); - emitWithToken(Opcodes.RETRIEVE_BEGIN_ARRAY, node.getIndex()); - emitReg(arrayReg); - emit(nameIdx); - emit(currentSubroutineBeginId); - } else if (hasVariable(arrayVarName) && !isDynamicOurVariable(arrayVarName)) { + if (hasVariable(arrayVarName) && !isDynamicOurVariable(arrayVarName)) { arrayReg = getVariableRegister(arrayVarName); } else { arrayReg = allocateRegister(); @@ -2060,18 +2055,9 @@ void handleHashElementAccess(BinaryOperatorNode node, OperatorNode leftOp) { String varName = ((IdentifierNode) leftOp.operand).name; String hashVarName = "%" + varName; - // Get the hash register - check closure, lexical, then global + // Get the hash register - check lexical, then global int hashReg; - if (currentSubroutineBeginId != 0 && currentSubroutineClosureVars != null - && currentSubroutineClosureVars.contains(hashVarName) - && !isDynamicOurVariable(hashVarName)) { - hashReg = allocateRegister(); - int nameIdx = addToStringPool(hashVarName); - emitWithToken(Opcodes.RETRIEVE_BEGIN_HASH, node.getIndex()); - emitReg(hashReg); - emit(nameIdx); - emit(currentSubroutineBeginId); - } else if (hasVariable(hashVarName) && !isOurVariable(hashVarName)) { + if (hasVariable(hashVarName) && !isOurVariable(hashVarName)) { hashReg = getVariableRegister(hashVarName); } else { // 'our' hashes (or undeclared globals) must be fetched from the global @@ -2187,16 +2173,7 @@ void handleHashSlice(BinaryOperatorNode node, OperatorNode leftOp) { String varName = ((IdentifierNode) leftOp.operand).name; String hashVarName = "%" + varName; - if (currentSubroutineBeginId != 0 && currentSubroutineClosureVars != null - && currentSubroutineClosureVars.contains(hashVarName) - && !isDynamicOurVariable(hashVarName)) { - hashReg = allocateRegister(); - int nameIdx = addToStringPool(hashVarName); - emitWithToken(Opcodes.RETRIEVE_BEGIN_HASH, node.getIndex()); - emitReg(hashReg); - emit(nameIdx); - emit(currentSubroutineBeginId); - } else if (hasVariable(hashVarName) && !isDynamicOurVariable(hashVarName)) { + if (hasVariable(hashVarName) && !isDynamicOurVariable(hashVarName)) { hashReg = getVariableRegister(hashVarName); } else { hashReg = allocateRegister(); @@ -2327,16 +2304,7 @@ void handleHashKeyValueSlice(BinaryOperatorNode node, OperatorNode leftOp) { String varName = ((IdentifierNode) leftOp.operand).name; String hashVarName = "%" + varName; - if (currentSubroutineBeginId != 0 && currentSubroutineClosureVars != null - && currentSubroutineClosureVars.contains(hashVarName) - && !isDynamicOurVariable(hashVarName)) { - hashReg = allocateRegister(); - int nameIdx = addToStringPool(hashVarName); - emitWithToken(Opcodes.RETRIEVE_BEGIN_HASH, node.getIndex()); - emitReg(hashReg); - emit(nameIdx); - emit(currentSubroutineBeginId); - } else if (hasVariable(hashVarName) && !isDynamicOurVariable(hashVarName)) { + if (hasVariable(hashVarName) && !isDynamicOurVariable(hashVarName)) { hashReg = getVariableRegister(hashVarName); } else { hashReg = allocateRegister(); @@ -3025,6 +2993,7 @@ void compileVariableDeclaration(OperatorNode node, String op) { } default -> throwCompilerException("Unsupported variable type: " + sigil); } + emitActiveLexicalBinding(reg, varName); // Match JVM EmitVariable: MODIFY_*_ATTRIBUTES must run for : ATTR(...) // declarations even when storage comes from RETRIEVE_BEGIN_* (closure @@ -3090,6 +3059,7 @@ void compileVariableDeclaration(OperatorNode node, String op) { } default -> throwCompilerException("Unsupported variable type: " + sigil); } + emitActiveLexicalBinding(reg, varName); // Runtime attribute dispatch for state variables with attributes emitVarAttrsIfNeeded(node, reg, sigil); @@ -3442,6 +3412,7 @@ void compileVariableDeclaration(OperatorNode node, String op) { default -> throwCompilerException("Unsupported variable type in list declaration: " + sigil); } + emitActiveLexicalBinding(reg, varName); // A captured declaration-list slot is retrieved from the // persistent definition-time cell, but attributes still @@ -4602,20 +4573,7 @@ void compileVariableReference(OperatorNode node, String op) { if (node.operand instanceof IdentifierNode) { String varName = "$" + ((IdentifierNode) node.operand).name; - // Check if this is a closure variable captured from outer scope via PersistentVariable - if (currentSubroutineBeginId != 0 && currentSubroutineClosureVars.contains(varName) - && !isDynamicOurVariable(varName)) { - // This is a closure variable - use RETRIEVE_BEGIN_SCALAR - int rd = allocateOutputRegister(); - int nameIdx = addToStringPool(varName); - - emitWithToken(Opcodes.RETRIEVE_BEGIN_SCALAR, node.getIndex()); - emitReg(rd); - emit(nameIdx); - emit(currentSubroutineBeginId); - - lastResultReg = rd; - } else if (hasVariable(varName) && !isOurVariable(varName)) { + if (hasVariable(varName) && !isOurVariable(varName)) { // Lexical variable (my/state) - use existing register lastResultReg = getVariableRegister(varName); } else if (hasVariable(varName) && isOurVariable(varName)) { @@ -4735,19 +4693,8 @@ void compileVariableReference(OperatorNode node, String op) { return; } - // Check if this is a closure variable captured from outer scope via PersistentVariable int arrayReg; - if (currentSubroutineBeginId != 0 && currentSubroutineClosureVars.contains(varName) - && !isDynamicOurVariable(varName)) { - // This is a closure variable - use RETRIEVE_BEGIN_ARRAY - arrayReg = allocateRegister(); - int nameIdx = addToStringPool(varName); - - emitWithToken(Opcodes.RETRIEVE_BEGIN_ARRAY, node.getIndex()); - emitReg(arrayReg); - emit(nameIdx); - emit(currentSubroutineBeginId); - } else if (hasVariable(varName) && !isOurVariable(varName)) { + if (hasVariable(varName) && !isOurVariable(varName)) { // Lexical array (my/state) - use existing register arrayReg = getVariableRegister(varName); } else if (hasVariable(varName) && isOurVariable(varName)) { @@ -4852,16 +4799,7 @@ void compileVariableReference(OperatorNode node, String op) { String varName = "%" + ((IdentifierNode) node.operand).name; int hashReg; - if (currentSubroutineBeginId != 0 && currentSubroutineClosureVars != null - && currentSubroutineClosureVars.contains(varName) - && !isDynamicOurVariable(varName)) { - hashReg = allocateRegister(); - int nameIdx = addToStringPool(varName); - emitWithToken(Opcodes.RETRIEVE_BEGIN_HASH, node.getIndex()); - emitReg(hashReg); - emit(nameIdx); - emit(currentSubroutineBeginId); - } else if (hasVariable(varName) && !isOurVariable(varName)) { + if (hasVariable(varName) && !isOurVariable(varName)) { // Lexical hash (my/state) - use existing register hashReg = getVariableRegister(varName); } else if (hasVariable(varName) && isOurVariable(varName)) { @@ -5230,6 +5168,16 @@ void emitLexicalAlias(int register, String variableName) { emit(addToStringPool(variableName)); } + void emitActiveLexicalBinding(int register, String variableName) { + emit(Opcodes.BIND_ACTIVE_LEXICAL); + emitReg(register); + emit(addToStringPool(variableName)); + } + + boolean tracksRuntimeRegexLexicals() { + return tracksRuntimeRegexLexicals; + } + /** * Apply Perl's context conversion to an array value. This is shared by * named arrays and dereferenced arrays: scalar {@code @$ref} is the array @@ -5361,7 +5309,7 @@ TreeMap collectVisiblePerlVariablesNarrowed(Node body) { Set used = new HashSet<>(); VariableCollectorVisitor collector = new VariableCollectorVisitor(used); body.accept(collector); - if (collector.hasEvalString()) return all; + if (collector.requiresAllRuntimeLexicals()) return all; TreeMap narrowed = new TreeMap<>(); for (Map.Entry e : all.entrySet()) { if (used.contains(e.getValue())) { @@ -5799,43 +5747,7 @@ private void visitNamedSubroutine(SubroutineNode node) { closureCapturedVarNames.addAll(closureVarNames); - int beginId = 0; - if (!closureVarIndices.isEmpty()) { - beginId = EmitterMethodCreator.classCounter.getAndIncrement(); - - // Store each closure variable in PersistentVariable globals - for (int i = 0; i < closureVarNames.size(); i++) { - String varName = closureVarNames.get(i); - int varReg = closureVarIndices.get(i); - - // Get the variable type from the sigil - String sigil = varName.substring(0, 1); - String bareVarName = varName.substring(1); - String beginVarName = PersistentVariable.beginPackage(beginId) + "::" + bareVarName; - - // Store the variable value in PersistentVariable global - int nameIdx = addToStringPool(beginVarName); - switch (sigil) { - case "$" -> { - emit(Opcodes.STORE_GLOBAL_SCALAR); - emit(nameIdx); - emitReg(varReg); - } - case "@" -> { - emit(Opcodes.STORE_GLOBAL_ARRAY); - emit(nameIdx); - emitReg(varReg); - } - case "%" -> { - emit(Opcodes.STORE_GLOBAL_HASH); - emit(nameIdx); - emitReg(varReg); - } - } - } - } - - // Step 3: Compile the subroutine body with a packed registry for captured variables. + // Step 2: Compile the subroutine body with a packed registry for captured variables. // The closure created at runtime packs capturedVars sequentially into registers 3.., // so the compiled sub body must use the same packed register layout. Map packedRegistry = new HashMap<>(); @@ -5863,16 +5775,12 @@ private void visitNamedSubroutine(SubroutineNode node) { // Inherit pragma flags so BEGIN { $^H = ... } changes propagate into sub body inheritPragmaFlags(subCompiler); - // Set the BEGIN ID in the sub-compiler so it knows to use RETRIEVE_BEGIN opcodes - subCompiler.currentSubroutineBeginId = beginId; - subCompiler.currentSubroutineClosureVars = new HashSet<>(closureVarNames); - // Subroutine bodies should use RUNTIME context so the calling context // (VOID/SCALAR/LIST) propagates correctly at runtime via register 2 (wantarray). subCompiler.currentCallContext = RuntimeContextType.RUNTIME; - // Step 4: Compile the subroutine body - // Sub-compiler will use RETRIEVE_BEGIN opcodes for closure variables + // Step 3: Compile the subroutine body. Captured variables resolve directly + // through the packed registers instead of a copied synthetic global cell. InterpretedCode subCode = subCompiler.compile(node.block); subCode.futureAsyncAwaitSub = node.getBooleanAnnotation("futureAsyncAwaitSub"); subCode.futureAsyncAwaitFutureClass = @@ -5884,7 +5792,7 @@ private void visitNamedSubroutine(SubroutineNode node) { System.out.println(Disassemble.disassemble(subCode)); } - // Step 5: Emit bytecode to create closure or simple code ref + // Step 4: Emit bytecode to create closure or simple code ref int codeReg = allocateRegister(); if (closureVarIndices.isEmpty()) { @@ -5906,7 +5814,7 @@ private void visitNamedSubroutine(SubroutineNode node) { } } - // Step 6: Store in global namespace + // Step 5: Store in global namespace String fullName = node.name; if (!fullName.contains("::")) { fullName = getCurrentPackage() + "::" + fullName; // Use getCurrentPackage() for proper package tracking @@ -5917,7 +5825,7 @@ private void visitNamedSubroutine(SubroutineNode node) { emit(nameIdx); emitReg(codeReg); - // Step 7: Register subroutine location for %DB::sub (only in debug mode) + // Step 6: Register subroutine location for %DB::sub (only in debug mode) if (DebugState.isDebugMode() && errorUtil != null) { int startLine = errorUtil.getLineNumber(node.getIndex()); // Use start line as end line for now (accurate end would require tracking block end) diff --git a/src/main/java/org/perlonjava/backend/bytecode/BytecodeInterpreter.java b/src/main/java/org/perlonjava/backend/bytecode/BytecodeInterpreter.java index 450849e571..018240bc9e 100644 --- a/src/main/java/org/perlonjava/backend/bytecode/BytecodeInterpreter.java +++ b/src/main/java/org/perlonjava/backend/bytecode/BytecodeInterpreter.java @@ -3,6 +3,7 @@ import java.util.BitSet; import org.perlonjava.runtime.HintHashRegistry; +import org.perlonjava.runtime.NamedCharacterExpansionMap; import org.perlonjava.runtime.WarningBitsRegistry; import org.perlonjava.runtime.debugger.DebugHooks; import org.perlonjava.runtime.operators.CompareOperators; @@ -929,8 +930,6 @@ private static RuntimeList execute(SuspendedInterpreterFrame frame) { if (element instanceof RuntimeScalarReadOnly && element != RuntimeScalarCache.scalarUndef) { element = new ReadOnlyAlias(element); - } else if (element instanceof ScalarSpecialVariable) { - element = ensureMutableScalar(element); } registers[rd] = element; GlobalVariable.aliasForeachGlobalVariable(name, element); @@ -1099,6 +1098,7 @@ private static RuntimeList execute(SuspendedInterpreterFrame frame) { int kindIdx = bytecode[pc++]; int packageIdx = bytecode[pc++]; int sourceIdx = bytecode[pc++]; + boolean uninitializedWarningsEnabled = bytecode[pc++] != 0; if (DEBUG_REGEX) { RuntimeCode callbackCode = (RuntimeCode) registers[codeReg].scalar().value; @@ -1110,7 +1110,8 @@ private static RuntimeList execute(SuspendedInterpreterFrame frame) { } registers[rd] = org.perlonjava.runtime.regex.RuntimeRegexCallback.wrap( registers[codeReg].scalar(), code.stringPool[kindIdx], - code.stringPool[packageIdx], code.stringPool[sourceIdx]); + code.stringPool[packageIdx], code.stringPool[sourceIdx], + uninitializedWarningsEnabled); } case Opcodes.REGEX_TEMPLATE -> { @@ -1318,16 +1319,13 @@ private static RuntimeList execute(SuspendedInterpreterFrame frame) { // mutating opcodes would silently strip), but mutation // attempts still throw "Modification of a read-only // value". Fixes op/ref.t 232-234, op/for.t 130-134. - // ScalarSpecialVariable is unboxed to a mutable copy - // because surrounding interpreter paths can't propagate - // its alias status (and Perl's $&/$1 differ from the - // foreach-loop-alias case anyway). + // Keep ScalarSpecialVariable cells live. Foreach aliases + // to match variables such as $' must observe later matches, + // just like the JVM backend and Perl do. RuntimeScalar elem = iterator.next(); if (elem instanceof RuntimeScalarReadOnly && elem != RuntimeScalarCache.scalarUndef) { elem = new ReadOnlyAlias(elem); - } else if (elem instanceof ScalarSpecialVariable) { - elem = ensureMutableScalar(elem); } registers[rd] = elem; pc = bodyTarget; // ABSOLUTE jump back to body start @@ -2657,6 +2655,11 @@ private static RuntimeList execute(SuspendedInterpreterFrame frame) { case Opcodes.SET_CALL_SITE_HINT_HASH -> HintHashRegistry.setCallSiteHintHashId(bytecode[pc++]); + case Opcodes.SET_CALL_SITE_WARNING_BITS -> { + String warningBits = code.stringPool[bytecode[pc++]]; + WarningBitsRegistry.setRuntimeWarningBits(warningBits); + } + // ================================================================= // DEBUGGER SUPPORT // ================================================================= @@ -3401,6 +3404,12 @@ private static int executeTypeOps(int opcode, int[] bytecode, int pc, int warningState = bytecode[pc++]; int warningBitsIndex = bytecode[pc++]; int quoteConstruction = bytecode[pc++]; + int namedCharacterExpansionIndex = bytecode[pc++]; + NamedCharacterExpansionMap namedCharacterExpansions = + namedCharacterExpansionIndex >= 0 + ? (NamedCharacterExpansionMap) + code.constants[namedCharacterExpansionIndex] + : null; RuntimeScalar flags = registers[flagsReg].scalar(); if (implicitU != 0) { flags = RuntimeRegex.applyUnicodeStringsFeatureToModifiers(flags); @@ -3408,7 +3417,9 @@ private static int executeTypeOps(int opcode, int[] bytecode, int pc, RegexQuoteMeta.setCallSiteWarningState(warningState); RegexQuoteMeta.setCallSiteWarningBits(warningBitsIndex >= 0 ? code.stringPool[warningBitsIndex] : null); - registers[rd] = RuntimeRegex.getQuotedRegex(registers[patternReg].scalar(), flags); + registers[rd] = RuntimeRegex.getQuotedRegex( + registers[patternReg].scalar(), flags, + namedCharacterExpansions); if (quoteConstruction != 0) { registers[rd] = quoteConstruction == 2 ? RuntimeRegex.markSyntacticQuoteConstruction(registers[rd].scalar()) @@ -3425,6 +3436,12 @@ private static int executeTypeOps(int opcode, int[] bytecode, int pc, int warningState = bytecode[pc++]; int warningBitsIndex = bytecode[pc++]; int quoteConstruction = bytecode[pc++]; + int namedCharacterExpansionIndex = bytecode[pc++]; + NamedCharacterExpansionMap namedCharacterExpansions = + namedCharacterExpansionIndex >= 0 + ? (NamedCharacterExpansionMap) + code.constants[namedCharacterExpansionIndex] + : null; RuntimeScalar flags = registers[flagsReg].scalar(); if (implicitU != 0) { flags = RuntimeRegex.applyUnicodeStringsFeatureToModifiers(flags); @@ -3432,7 +3449,9 @@ private static int executeTypeOps(int opcode, int[] bytecode, int pc, RegexQuoteMeta.setCallSiteWarningState(warningState); RegexQuoteMeta.setCallSiteWarningBits(warningBitsIndex >= 0 ? code.stringPool[warningBitsIndex] : null); - registers[rd] = RuntimeRegex.getQuotedRegex(registers[patternReg].scalar(), flags, callsiteId); + registers[rd] = RuntimeRegex.getQuotedRegex( + registers[patternReg].scalar(), flags, callsiteId, + namedCharacterExpansions); if (quoteConstruction != 0) { registers[rd] = quoteConstruction == 2 ? RuntimeRegex.markSyntacticQuoteConstruction(registers[rd].scalar()) diff --git a/src/main/java/org/perlonjava/backend/bytecode/CompileAssignment.java b/src/main/java/org/perlonjava/backend/bytecode/CompileAssignment.java index 3bb4f49e3a..2165eed5ae 100644 --- a/src/main/java/org/perlonjava/backend/bytecode/CompileAssignment.java +++ b/src/main/java/org/perlonjava/backend/bytecode/CompileAssignment.java @@ -78,7 +78,7 @@ private static boolean handleLocalAssignment(BytecodeCompiler bc, BinaryOperator // slot for the localized value without evaluating the index twice. if (binOp.operator.equals("[") && !(binOp.left instanceof OperatorNode op && op.operator.equals("@"))) { - int arrayReg = CompileExistsDelete.compileArrayForExistsDelete(bc, binOp, node.getIndex()); + int arrayReg = CompileExistsDelete.compileArrayForExistsDelete(bc, binOp); int indexReg = CompileExistsDelete.compileArrayIndex(bc, binOp); int discardedReg = bc.allocateRegister(); bc.emit(Opcodes.ARRAY_DELETE_LOCAL); @@ -501,6 +501,7 @@ public static void compileAssignmentOperator(BytecodeCompiler bytecodeCompiler, bytecodeCompiler.emitReg(reg); bytecodeCompiler.emit(nameIdx); bytecodeCompiler.emit(beginId); + bytecodeCompiler.emitActiveLexicalBinding(reg, varName); // Now register contains a reference to the persistent RuntimeScalar // Store the initializer value INTO that RuntimeScalar @@ -540,6 +541,7 @@ public static void compileAssignmentOperator(BytecodeCompiler bytecodeCompiler, bytecodeCompiler.emitReg(valueReg); bytecodeCompiler.emit(nameIdx); bytecodeCompiler.emit(persistId); + bytecodeCompiler.emitActiveLexicalBinding(reg, varName); bytecodeCompiler.registerVariable(varName, reg); @@ -603,6 +605,7 @@ public static void compileAssignmentOperator(BytecodeCompiler bytecodeCompiler, bytecodeCompiler.emitReg(arrayReg); bytecodeCompiler.emit(nameIdx); bytecodeCompiler.emit(beginId); + bytecodeCompiler.emitActiveLexicalBinding(arrayReg, varName); // Compile RHS (should evaluate to a list) bytecodeCompiler.compileNode(node.right, -1, rhsContext); @@ -678,6 +681,7 @@ public static void compileAssignmentOperator(BytecodeCompiler bytecodeCompiler, bytecodeCompiler.emitReg(hashReg); bytecodeCompiler.emit(nameIdx); bytecodeCompiler.emit(beginId); + bytecodeCompiler.emitActiveLexicalBinding(hashReg, varName); // Compile RHS (should evaluate to a list) bytecodeCompiler.compileNode(node.right, -1, rhsContext); @@ -824,6 +828,7 @@ public static void compileAssignmentOperator(BytecodeCompiler bytecodeCompiler, bytecodeCompiler.emit(beginId); } } + bytecodeCompiler.emitActiveLexicalBinding(varReg, varName); bytecodeCompiler.registerVariable(varName, varReg); bytecodeCompiler.emit(Opcodes.REGISTER_MY_VAR); bytecodeCompiler.emitReg(varReg); @@ -1008,6 +1013,15 @@ public static void compileAssignmentOperator(BytecodeCompiler bytecodeCompiler, emitReleaseConsumedRhsTemp(bytecodeCompiler, node.right, valueReg, targetReg); } + // ASSIGN_LEXICAL_SCALAR may replace the RuntimeScalar in + // the register after a temporary runtime-regex closure + // releases its capture. Refresh the live-cell registry so + // later executable runtime source captures the new cell, + // not the value that existed before an eval or callback. + if (bytecodeCompiler.tracksRuntimeRegexLexicals()) { + bytecodeCompiler.emitActiveLexicalBinding(targetReg, varName); + } + bytecodeCompiler.lastResultReg = targetReg; } else { // Global variable @@ -1035,15 +1049,7 @@ public static void compileAssignmentOperator(BytecodeCompiler bytecodeCompiler, String varName = "@" + ((IdentifierNode) leftOp.operand).name; int arrayReg; - if (bytecodeCompiler.currentSubroutineBeginId != 0 && bytecodeCompiler.currentSubroutineClosureVars != null - && bytecodeCompiler.currentSubroutineClosureVars.contains(varName)) { - arrayReg = bytecodeCompiler.allocateRegister(); - int nameIdx = bytecodeCompiler.addToStringPool(varName); - bytecodeCompiler.emitWithToken(Opcodes.RETRIEVE_BEGIN_ARRAY, node.getIndex()); - bytecodeCompiler.emitReg(arrayReg); - bytecodeCompiler.emit(nameIdx); - bytecodeCompiler.emit(bytecodeCompiler.currentSubroutineBeginId); - } else if (bytecodeCompiler.hasVariable(varName)) { + if (bytecodeCompiler.hasVariable(varName)) { arrayReg = bytecodeCompiler.getVariableRegister(varName); } else { arrayReg = bytecodeCompiler.allocateRegister(); @@ -1078,15 +1084,7 @@ public static void compileAssignmentOperator(BytecodeCompiler bytecodeCompiler, String varName = "%" + ((IdentifierNode) leftOp.operand).name; int hashReg; - if (bytecodeCompiler.currentSubroutineBeginId != 0 && bytecodeCompiler.currentSubroutineClosureVars != null - && bytecodeCompiler.currentSubroutineClosureVars.contains(varName)) { - hashReg = bytecodeCompiler.allocateRegister(); - int nameIdx = bytecodeCompiler.addToStringPool(varName); - bytecodeCompiler.emitWithToken(Opcodes.RETRIEVE_BEGIN_HASH, node.getIndex()); - bytecodeCompiler.emitReg(hashReg); - bytecodeCompiler.emit(nameIdx); - bytecodeCompiler.emit(bytecodeCompiler.currentSubroutineBeginId); - } else if (bytecodeCompiler.hasVariable(varName)) { + if (bytecodeCompiler.hasVariable(varName)) { hashReg = bytecodeCompiler.getVariableRegister(varName); } else { hashReg = bytecodeCompiler.allocateRegister(); @@ -1480,15 +1478,7 @@ public static void compileAssignmentOperator(BytecodeCompiler bytecodeCompiler, if (arrayOp.operand instanceof IdentifierNode) { String varName = "@" + ((IdentifierNode) arrayOp.operand).name; - if (bytecodeCompiler.currentSubroutineBeginId != 0 && bytecodeCompiler.currentSubroutineClosureVars != null - && bytecodeCompiler.currentSubroutineClosureVars.contains(varName)) { - arrayReg = bytecodeCompiler.allocateRegister(); - int nameIdx = bytecodeCompiler.addToStringPool(varName); - bytecodeCompiler.emitWithToken(Opcodes.RETRIEVE_BEGIN_ARRAY, node.getIndex()); - bytecodeCompiler.emitReg(arrayReg); - bytecodeCompiler.emit(nameIdx); - bytecodeCompiler.emit(bytecodeCompiler.currentSubroutineBeginId); - } else if (bytecodeCompiler.hasVariable(varName)) { + if (bytecodeCompiler.hasVariable(varName)) { arrayReg = bytecodeCompiler.getVariableRegister(varName); } else { arrayReg = bytecodeCompiler.allocateRegister(); @@ -1577,16 +1567,7 @@ public static void compileAssignmentOperator(BytecodeCompiler bytecodeCompiler, String varName = ((IdentifierNode) arrayOp.operand).name; String arrayVarName = "@" + varName; - if (bytecodeCompiler.currentSubroutineBeginId != 0 && bytecodeCompiler.currentSubroutineClosureVars != null - && bytecodeCompiler.currentSubroutineClosureVars.contains(arrayVarName) - && !bytecodeCompiler.isDynamicOurVariable(arrayVarName)) { - arrayReg = bytecodeCompiler.allocateRegister(); - int nameIdx = bytecodeCompiler.addToStringPool(arrayVarName); - bytecodeCompiler.emitWithToken(Opcodes.RETRIEVE_BEGIN_ARRAY, node.getIndex()); - bytecodeCompiler.emitReg(arrayReg); - bytecodeCompiler.emit(nameIdx); - bytecodeCompiler.emit(bytecodeCompiler.currentSubroutineBeginId); - } else if (bytecodeCompiler.hasVariable(arrayVarName) + if (bytecodeCompiler.hasVariable(arrayVarName) && !bytecodeCompiler.isOurVariable(arrayVarName)) { arrayReg = bytecodeCompiler.getVariableRegister(arrayVarName); } else { @@ -1666,16 +1647,7 @@ public static void compileAssignmentOperator(BytecodeCompiler bytecodeCompiler, String varName = idNode.name; String hashVarName = "%" + varName; - if (bytecodeCompiler.currentSubroutineBeginId != 0 && bytecodeCompiler.currentSubroutineClosureVars != null - && bytecodeCompiler.currentSubroutineClosureVars.contains(hashVarName) - && !bytecodeCompiler.isDynamicOurVariable(hashVarName)) { - hashReg = bytecodeCompiler.allocateRegister(); - int nameIdx = bytecodeCompiler.addToStringPool(hashVarName); - bytecodeCompiler.emitWithToken(Opcodes.RETRIEVE_BEGIN_HASH, node.getIndex()); - bytecodeCompiler.emitReg(hashReg); - bytecodeCompiler.emit(nameIdx); - bytecodeCompiler.emit(bytecodeCompiler.currentSubroutineBeginId); - } else if (bytecodeCompiler.hasVariable(hashVarName) + if (bytecodeCompiler.hasVariable(hashVarName) && !bytecodeCompiler.isOurVariable(hashVarName)) { hashReg = bytecodeCompiler.getVariableRegister(hashVarName); } else { @@ -1775,16 +1747,7 @@ public static void compileAssignmentOperator(BytecodeCompiler bytecodeCompiler, String varName = ((IdentifierNode) hashOp.operand).name; String hashVarName = "%" + varName; - if (bytecodeCompiler.currentSubroutineBeginId != 0 && bytecodeCompiler.currentSubroutineClosureVars != null - && bytecodeCompiler.currentSubroutineClosureVars.contains(hashVarName) - && !bytecodeCompiler.isDynamicOurVariable(hashVarName)) { - hashReg = bytecodeCompiler.allocateRegister(); - int nameIdx = bytecodeCompiler.addToStringPool(hashVarName); - bytecodeCompiler.emitWithToken(Opcodes.RETRIEVE_BEGIN_HASH, node.getIndex()); - bytecodeCompiler.emitReg(hashReg); - bytecodeCompiler.emit(nameIdx); - bytecodeCompiler.emit(bytecodeCompiler.currentSubroutineBeginId); - } else if (bytecodeCompiler.hasVariable(hashVarName) + if (bytecodeCompiler.hasVariable(hashVarName) && !bytecodeCompiler.isOurVariable(hashVarName)) { hashReg = bytecodeCompiler.getVariableRegister(hashVarName); } else { @@ -2102,16 +2065,6 @@ static int resolveArrayForDollarHash(BytecodeCompiler bytecodeCompiler, Operator if (dollarHashOp.operand instanceof OperatorNode operandOp && operandOp.operator.equals("@") && operandOp.operand instanceof IdentifierNode idNode) { String varName = "@" + idNode.name; - if (bytecodeCompiler.currentSubroutineBeginId != 0 && bytecodeCompiler.currentSubroutineClosureVars != null - && bytecodeCompiler.currentSubroutineClosureVars.contains(varName)) { - int arrayReg = bytecodeCompiler.allocateRegister(); - int nameIdx = bytecodeCompiler.addToStringPool(varName); - bytecodeCompiler.emitWithToken(Opcodes.RETRIEVE_BEGIN_ARRAY, dollarHashOp.getIndex()); - bytecodeCompiler.emitReg(arrayReg); - bytecodeCompiler.emit(nameIdx); - bytecodeCompiler.emit(bytecodeCompiler.currentSubroutineBeginId); - return arrayReg; - } if (bytecodeCompiler.hasVariable(varName)) { return bytecodeCompiler.getVariableRegister(varName); } @@ -2124,16 +2077,6 @@ static int resolveArrayForDollarHash(BytecodeCompiler bytecodeCompiler, Operator return arrayReg; } else if (dollarHashOp.operand instanceof IdentifierNode idNode) { String varName = "@" + idNode.name; - if (bytecodeCompiler.currentSubroutineBeginId != 0 && bytecodeCompiler.currentSubroutineClosureVars != null - && bytecodeCompiler.currentSubroutineClosureVars.contains(varName)) { - int arrayReg = bytecodeCompiler.allocateRegister(); - int nameIdx = bytecodeCompiler.addToStringPool(varName); - bytecodeCompiler.emitWithToken(Opcodes.RETRIEVE_BEGIN_ARRAY, dollarHashOp.getIndex()); - bytecodeCompiler.emitReg(arrayReg); - bytecodeCompiler.emit(nameIdx); - bytecodeCompiler.emit(bytecodeCompiler.currentSubroutineBeginId); - return arrayReg; - } if (bytecodeCompiler.hasVariable(varName)) { return bytecodeCompiler.getVariableRegister(varName); } diff --git a/src/main/java/org/perlonjava/backend/bytecode/CompileBinaryOperator.java b/src/main/java/org/perlonjava/backend/bytecode/CompileBinaryOperator.java index e7708e3a01..f94101ef0c 100644 --- a/src/main/java/org/perlonjava/backend/bytecode/CompileBinaryOperator.java +++ b/src/main/java/org/perlonjava/backend/bytecode/CompileBinaryOperator.java @@ -635,10 +635,19 @@ else if (node.right instanceof BinaryOperatorNode rightCall) { // Create a copy of the operand list and add the left side (string) ListNode boundList = new ListNode(new java.util.ArrayList<>(originalList.elements), originalList.tokenIndex); + boundList.handle = originalList.handle; + if (originalList.annotations != null) { + boundList.annotations = new java.util.HashMap<>( + originalList.annotations); + } boundList.elements.add(node.left); // Create a new OperatorNode with the modified operand list OperatorNode boundOp = new OperatorNode(rightOp.operator, boundList, rightOp.tokenIndex); + boundOp.id = rightOp.id; + if (rightOp.annotations != null) { + boundOp.annotations = new java.util.HashMap<>(rightOp.annotations); + } // For !~, we need to negate the result if (node.operator.equals("!~")) { diff --git a/src/main/java/org/perlonjava/backend/bytecode/CompileExistsDelete.java b/src/main/java/org/perlonjava/backend/bytecode/CompileExistsDelete.java index 728a3401d9..75df2c753a 100644 --- a/src/main/java/org/perlonjava/backend/bytecode/CompileExistsDelete.java +++ b/src/main/java/org/perlonjava/backend/bytecode/CompileExistsDelete.java @@ -39,7 +39,7 @@ private static void visitExistsHash(BytecodeCompiler bc, OperatorNode node, Bina } private static void visitExistsArray(BytecodeCompiler bc, OperatorNode node, BinaryOperatorNode arrayAccess) { - int arrayReg = compileArrayForExistsDelete(bc, arrayAccess, node.getIndex()); + int arrayReg = compileArrayForExistsDelete(bc, arrayAccess); int indexReg = compileArrayIndex(bc, arrayAccess); int rd = bc.allocateOutputRegister(); bc.emit(Opcodes.ARRAY_EXISTS); @@ -235,7 +235,7 @@ private static void visitDeleteArray(BytecodeCompiler bc, OperatorNode node, Bin bc.lastResultReg = rd; return; } - int arrayReg = compileArrayForExistsDelete(bc, arrayAccess, node.getIndex()); + int arrayReg = compileArrayForExistsDelete(bc, arrayAccess); int indexReg = compileArrayIndex(bc, arrayAccess); int rd = bc.allocateOutputRegister(); bc.emit(Opcodes.ARRAY_DELETE); @@ -347,7 +347,7 @@ private static void visitDeleteGeneric(BytecodeCompiler bc, Node arg) { private static int resolveHashSliceTarget(BytecodeCompiler bc, OperatorNode node, OperatorNode leftOp, String error) { if (leftOp.operand instanceof IdentifierNode id) { - return loadHashVariable(bc, id.name, node.getIndex()); + return loadHashVariable(bc, id.name); } if (leftOp.operand instanceof OperatorNode || leftOp.operand instanceof BlockNode @@ -361,7 +361,7 @@ private static int resolveHashSliceTarget(BytecodeCompiler bc, OperatorNode node private static int resolveArraySliceTarget(BytecodeCompiler bc, OperatorNode node, OperatorNode leftOp, String error) { if (leftOp.operand instanceof IdentifierNode id) { - return loadArrayVariable(bc, id.name, node.getIndex()); + return loadArrayVariable(bc, id.name); } if (leftOp.operand instanceof OperatorNode || leftOp.operand instanceof BlockNode @@ -373,18 +373,8 @@ private static int resolveArraySliceTarget(BytecodeCompiler bc, OperatorNode nod return -1; } - private static int loadHashVariable(BytecodeCompiler bc, String name, int tokenIndex) { + private static int loadHashVariable(BytecodeCompiler bc, String name) { String hashVarName = "%" + name; - if (bc.currentSubroutineBeginId != 0 && bc.currentSubroutineClosureVars != null - && bc.currentSubroutineClosureVars.contains(hashVarName)) { - int hashReg = bc.allocateRegister(); - int nameIdx = bc.addToStringPool(hashVarName); - bc.emitWithToken(Opcodes.RETRIEVE_BEGIN_HASH, tokenIndex); - bc.emitReg(hashReg); - bc.emit(nameIdx); - bc.emit(bc.currentSubroutineBeginId); - return hashReg; - } if (bc.hasVariable(hashVarName)) { return bc.getVariableRegister(hashVarName); } @@ -397,18 +387,8 @@ private static int loadHashVariable(BytecodeCompiler bc, String name, int tokenI return hashReg; } - private static int loadArrayVariable(BytecodeCompiler bc, String name, int tokenIndex) { + private static int loadArrayVariable(BytecodeCompiler bc, String name) { String arrayVarName = "@" + name; - if (bc.currentSubroutineBeginId != 0 && bc.currentSubroutineClosureVars != null - && bc.currentSubroutineClosureVars.contains(arrayVarName)) { - int arrayReg = bc.allocateRegister(); - int nameIdx = bc.addToStringPool(arrayVarName); - bc.emitWithToken(Opcodes.RETRIEVE_BEGIN_ARRAY, tokenIndex); - bc.emitReg(arrayReg); - bc.emit(nameIdx); - bc.emit(bc.currentSubroutineBeginId); - return arrayReg; - } if (bc.hasVariable(arrayVarName)) { return bc.getVariableRegister(arrayVarName); } @@ -505,7 +485,7 @@ private static int compileHashKey(BytecodeCompiler bc, Node keySpec) { } } - static int compileArrayForExistsDelete(BytecodeCompiler bc, BinaryOperatorNode arrayAccess, int tokenIndex) { + static int compileArrayForExistsDelete(BytecodeCompiler bc, BinaryOperatorNode arrayAccess) { if (!(arrayAccess.left instanceof OperatorNode leftOp) || !leftOp.operator.equals("$") || !(leftOp.operand instanceof IdentifierNode)) { bc.throwCompilerException("Array exists/delete requires simple array variable"); @@ -513,16 +493,7 @@ static int compileArrayForExistsDelete(BytecodeCompiler bc, BinaryOperatorNode a } String varName = ((IdentifierNode) leftOp.operand).name; String arrayVarName = "@" + varName; - if (bc.currentSubroutineBeginId != 0 && bc.currentSubroutineClosureVars != null - && bc.currentSubroutineClosureVars.contains(arrayVarName)) { - int arrayReg = bc.allocateRegister(); - int nameIdx = bc.addToStringPool(arrayVarName); - bc.emitWithToken(Opcodes.RETRIEVE_BEGIN_ARRAY, tokenIndex); - bc.emitReg(arrayReg); - bc.emit(nameIdx); - bc.emit(bc.currentSubroutineBeginId); - return arrayReg; - } else if (bc.hasVariable(arrayVarName)) { + if (bc.hasVariable(arrayVarName)) { return bc.getVariableRegister(arrayVarName); } else { int arrayReg = bc.allocateRegister(); @@ -623,7 +594,7 @@ private static void visitDeleteLocalArray(BytecodeCompiler bc, OperatorNode node visitDeleteLocalArraySlice(bc, node, arrayAccess, leftOp); return; } - int arrayReg = compileArrayForExistsDelete(bc, arrayAccess, node.getIndex()); + int arrayReg = compileArrayForExistsDelete(bc, arrayAccess); int indexReg = compileArrayIndex(bc, arrayAccess); int rd = bc.allocateOutputRegister(); bc.emit(Opcodes.ARRAY_DELETE_LOCAL); diff --git a/src/main/java/org/perlonjava/backend/bytecode/CompileOperator.java b/src/main/java/org/perlonjava/backend/bytecode/CompileOperator.java index a902dffb35..5f45b0bb6b 100644 --- a/src/main/java/org/perlonjava/backend/bytecode/CompileOperator.java +++ b/src/main/java/org/perlonjava/backend/bytecode/CompileOperator.java @@ -2,6 +2,8 @@ import org.perlonjava.frontend.astnode.*; import org.perlonjava.frontend.analysis.RegexLiteralAnalyzer; +import org.perlonjava.frontend.parser.StringParser; +import org.perlonjava.runtime.NamedCharacterExpansionMap; import org.perlonjava.runtime.operators.ScalarGlobOperator; import org.perlonjava.runtime.regex.RuntimeRegex; import org.perlonjava.runtime.runtimetypes.*; @@ -98,16 +100,7 @@ private static int compileArrayForExistsDelete(BytecodeCompiler bc, BinaryOperat } String varName = ((IdentifierNode) leftOp.operand).name; String arrayVarName = "@" + varName; - if (bc.currentSubroutineBeginId != 0 && bc.currentSubroutineClosureVars != null - && bc.currentSubroutineClosureVars.contains(arrayVarName)) { - int arrayReg = bc.allocateRegister(); - int nameIdx = bc.addToStringPool(arrayVarName); - bc.emitWithToken(Opcodes.RETRIEVE_BEGIN_ARRAY, tokenIndex); - bc.emitReg(arrayReg); - bc.emit(nameIdx); - bc.emit(bc.currentSubroutineBeginId); - return arrayReg; - } else if (bc.hasVariable(arrayVarName)) { + if (bc.hasVariable(arrayVarName)) { return bc.getVariableRegister(arrayVarName); } else { int arrayReg = bc.allocateRegister(); @@ -283,6 +276,7 @@ private static int loadDefaultUnderscore(BytecodeCompiler bc) { } private static int regexWarningState(OperatorNode node) { + if (Boolean.TRUE.equals(node.getAnnotation("regexWarningsSuppressed"))) return -1; if (Boolean.TRUE.equals(node.getAnnotation("regexWarningsFatal"))) return 2; return Boolean.TRUE.equals(node.getAnnotation("regexWarningsEnabled")) ? 1 : 0; } @@ -292,6 +286,18 @@ private static int regexWarningBitsIndex(BytecodeCompiler bc, OperatorNode node) return bits instanceof String string ? bc.addToStringPool(string) : -1; } + private static int namedCharacterExpansionIndex( + BytecodeCompiler bc, OperatorNode node, ListNode operand) { + Object expansions = node.getAnnotation( + StringParser.LEXICAL_NAMED_CHARACTER_EXPANSIONS); + if (expansions == null) { + expansions = operand.getAnnotation( + StringParser.LEXICAL_NAMED_CHARACTER_EXPANSIONS); + } + return expansions instanceof NamedCharacterExpansionMap map + ? bc.addToConstantPool(map) : -1; + } + private static int regexTargetNameIndex(BytecodeCompiler bc, Node node) { if (node instanceof OperatorNode operator && operator.operator.equals("$") @@ -328,6 +334,7 @@ private static void visitMatchRegex(BytecodeCompiler bc, OperatorNode node) { bc.emit(regexWarningState(node)); bc.emit(regexWarningBitsIndex(bc, node)); bc.emit(0); + bc.emit(namedCharacterExpansionIndex(bc, node, args)); } else { bc.emit(Opcodes.QUOTE_REGEX); bc.emitReg(regexReg); @@ -337,6 +344,7 @@ private static void visitMatchRegex(BytecodeCompiler bc, OperatorNode node) { bc.emit(regexWarningState(node)); bc.emit(regexWarningBitsIndex(bc, node)); bc.emit(0); + bc.emit(namedCharacterExpansionIndex(bc, node, args)); } int stringReg; if (args.elements.size() > 2) { @@ -853,6 +861,8 @@ public static void visitOperator(BytecodeCompiler bytecodeCompiler, OperatorNode (String) node.getAnnotation("regexCallbackPackage"))); bytecodeCompiler.emit(bytecodeCompiler.addToStringPool( (String) node.getAnnotation("regexCallbackSource"))); + bytecodeCompiler.emit(Boolean.TRUE.equals(node.getAnnotation( + "regexCallbackUninitializedWarningsEnabled")) ? 1 : 0); bytecodeCompiler.lastResultReg = rd; } case "regexTemplate" -> { @@ -1119,7 +1129,8 @@ public static void visitOperator(BytecodeCompiler bytecodeCompiler, OperatorNode if (operand.elements.size() < 2) { bytecodeCompiler.throwCompilerException("quoteRegex requires pattern and flags"); } - String literalPattern = RegexLiteralAnalyzer.constantString(operand.elements.get(0)); + String literalPattern = node.getBooleanAnnotation("literalSyntaxValidated") + ? null : RegexLiteralAnalyzer.constantString(operand.elements.get(0)); if (literalPattern != null && operand.elements.get(1) instanceof StringNode literalFlags && !RuntimeRegex.requiresRuntimeUnicodePropertyResolution(literalPattern)) { @@ -1129,7 +1140,19 @@ public static void visitOperator(BytecodeCompiler bytecodeCompiler, OperatorNode modifiers += "u"; } try { - RuntimeRegex.validateLiteralSyntax(literalPattern, modifiers); + String diagnosticPattern = RegexLiteralAnalyzer.constantSourceString( + operand.elements.get(0)); + StringParser.validateLiteralNamedCharacters( + operand, literalPattern, modifiers, + diagnosticPattern == null + ? literalPattern : diagnosticPattern); + Object expansions = operand.getAnnotation( + StringParser.LEXICAL_NAMED_CHARACTER_EXPANSIONS); + if (expansions != null) { + node.setAnnotation( + StringParser.LEXICAL_NAMED_CHARACTER_EXPANSIONS, + expansions); + } } catch (PerlCompilerException exception) { throw PerlCompilerException.withSourceLocation( node.tokenIndex, exception.getMessage(), @@ -1158,6 +1181,8 @@ public static void visitOperator(BytecodeCompiler bytecodeCompiler, OperatorNode bytecodeCompiler.emit(regexWarningState(node)); bytecodeCompiler.emit(regexWarningBitsIndex(bytecodeCompiler, node)); bytecodeCompiler.emit(node.getBooleanAnnotation("syntacticQuoteRegex") ? 2 : 1); + bytecodeCompiler.emit(namedCharacterExpansionIndex( + bytecodeCompiler, node, operand)); } else { bytecodeCompiler.emit(Opcodes.QUOTE_REGEX); bytecodeCompiler.emitReg(rd); @@ -1167,6 +1192,8 @@ public static void visitOperator(BytecodeCompiler bytecodeCompiler, OperatorNode bytecodeCompiler.emit(regexWarningState(node)); bytecodeCompiler.emit(regexWarningBitsIndex(bytecodeCompiler, node)); bytecodeCompiler.emit(node.getBooleanAnnotation("syntacticQuoteRegex") ? 2 : 1); + bytecodeCompiler.emit(namedCharacterExpansionIndex( + bytecodeCompiler, node, operand)); } bytecodeCompiler.lastResultReg = rd; } diff --git a/src/main/java/org/perlonjava/backend/bytecode/Disassemble.java b/src/main/java/org/perlonjava/backend/bytecode/Disassemble.java index c48ab13583..df1a4c25ba 100644 --- a/src/main/java/org/perlonjava/backend/bytecode/Disassemble.java +++ b/src/main/java/org/perlonjava/backend/bytecode/Disassemble.java @@ -1260,6 +1260,7 @@ public static String disassemble(InterpretedCode interpretedCode) { int callbackKindIdx = interpretedCode.bytecode[pc++]; int callbackPackageIdx = interpretedCode.bytecode[pc++]; int callbackSourceIdx = interpretedCode.bytecode[pc++]; + int callbackUninitializedWarnings = interpretedCode.bytecode[pc++]; sb.append("REGEX_CALLBACK r").append(rd) .append(" = callback(r").append(rs) .append(", kind=") @@ -1268,6 +1269,8 @@ public static String disassemble(InterpretedCode interpretedCode) { .append(interpretedCode.stringPool[callbackPackageIdx]) .append(", source=") .append(interpretedCode.stringPool[callbackSourceIdx]) + .append(", uninitializedWarnings=") + .append(callbackUninitializedWarnings != 0) .append(")\n"); break; case Opcodes.REGEX_TEMPLATE: @@ -1344,11 +1347,14 @@ public static String disassemble(InterpretedCode interpretedCode) { int warningState = interpretedCode.bytecode[pc++]; int warningBitsIndex = interpretedCode.bytecode[pc++]; int quoteConstruction = interpretedCode.bytecode[pc++]; + int namedCharacterExpansionIndex = interpretedCode.bytecode[pc++]; sb.append("QUOTE_REGEX r").append(rd).append(" = qr{r").append(patternReg) .append("}r").append(flagsReg).append(" implicitU=").append(implicitU) .append(" warningState=").append(warningState) .append(" warningBits=").append(warningBitsIndex) - .append(" quoteConstruction=").append(quoteConstruction).append("\n"); + .append(" quoteConstruction=").append(quoteConstruction) + .append(" namedCharacters=") + .append(namedCharacterExpansionIndex).append("\n"); break; case Opcodes.QUOTE_REGEX_O: rd = interpretedCode.bytecode[pc++]; @@ -1359,12 +1365,15 @@ public static String disassemble(InterpretedCode interpretedCode) { warningState = interpretedCode.bytecode[pc++]; warningBitsIndex = interpretedCode.bytecode[pc++]; quoteConstruction = interpretedCode.bytecode[pc++]; + namedCharacterExpansionIndex = interpretedCode.bytecode[pc++]; sb.append("QUOTE_REGEX_O r").append(rd).append(" = qr{r").append(patternReg) .append("}r").append(flagsReg).append(" callsite=").append(callsiteId) .append(" implicitU=").append(implicitU) .append(" warningState=").append(warningState) .append(" warningBits=").append(warningBitsIndex) - .append(" quoteConstruction=").append(quoteConstruction).append("\n"); + .append(" quoteConstruction=").append(quoteConstruction) + .append(" namedCharacters=") + .append(namedCharacterExpansionIndex).append("\n"); break; case Opcodes.ITERATOR_CREATE: rd = interpretedCode.bytecode[pc++]; @@ -1847,6 +1856,10 @@ public static String disassemble(InterpretedCode interpretedCode) { sb.append("SET_CALL_SITE_HINT_HASH id=") .append(interpretedCode.bytecode[pc++]).append("\n"); break; + case Opcodes.SET_CALL_SITE_WARNING_BITS: + sb.append("SET_CALL_SITE_WARNING_BITS bits=") + .append(interpretedCode.bytecode[pc++]).append("\n"); + break; case Opcodes.PUSH_LABELED_BLOCK: { int labelIdx = interpretedCode.bytecode[pc++]; int exitPc = interpretedCode.bytecode[pc++]; diff --git a/src/main/java/org/perlonjava/backend/bytecode/EvalStringHandler.java b/src/main/java/org/perlonjava/backend/bytecode/EvalStringHandler.java index 130106ec35..ff2066ceb9 100644 --- a/src/main/java/org/perlonjava/backend/bytecode/EvalStringHandler.java +++ b/src/main/java/org/perlonjava/backend/bytecode/EvalStringHandler.java @@ -12,6 +12,7 @@ import org.perlonjava.frontend.parser.SpecialBlockParser; import org.perlonjava.frontend.semantic.ScopedSymbolTable; import org.perlonjava.runtime.HintHashRegistry; +import org.perlonjava.runtime.regex.RegexQuoteMeta; import org.perlonjava.runtime.operators.WarnDie; import org.perlonjava.runtime.perlmodule.BHooksEndOfScope; import org.perlonjava.runtime.perlmodule.Strict; @@ -460,9 +461,12 @@ private static RuntimeList evalStringList(String perlCode, parser.parsingEvalString = true; Node ast; BHooksEndOfScope.beginFileLoad(evalFileName); + String savedRegexWarningBits = RegexQuoteMeta.getParserWarningBits(); + RegexQuoteMeta.setParserWarningBits(siteWarningBits); try { ast = parser.parse(); } finally { + RegexQuoteMeta.setParserWarningBits(savedRegexWarningBits); BHooksEndOfScope.endFileLoad(evalFileName); } diff --git a/src/main/java/org/perlonjava/backend/bytecode/InterpretedCode.java b/src/main/java/org/perlonjava/backend/bytecode/InterpretedCode.java index b49ceaaa95..ca722e8d73 100644 --- a/src/main/java/org/perlonjava/backend/bytecode/InterpretedCode.java +++ b/src/main/java/org/perlonjava/backend/bytecode/InterpretedCode.java @@ -492,6 +492,7 @@ public InterpretedCode withCapturedVars(RuntimeBase[] capturedVars) { copy.inheritsSelfReference = this.inheritsSelfReference; copy.isRegexCallbackPseudoBlock = this.isRegexCallbackPseudoBlock; copy.isQuotedRegexCallback = this.isQuotedRegexCallback; + copy.tracksRuntimeRegexLexicals = this.tracksRuntimeRegexLexicals; copy.attributesDispatchedAtCompileTime = this.attributesDispatchedAtCompileTime; copy.deferredConstAttribute = this.deferredConstAttribute; copy.cvStartFile = this.cvStartFile; diff --git a/src/main/java/org/perlonjava/backend/bytecode/Opcodes.java b/src/main/java/org/perlonjava/backend/bytecode/Opcodes.java index 7a8217ee8c..46d117ed1b 100644 --- a/src/main/java/org/perlonjava/backend/bytecode/Opcodes.java +++ b/src/main/java/org/perlonjava/backend/bytecode/Opcodes.java @@ -935,7 +935,7 @@ public class Opcodes { /** * Quote regex operator: rd = RuntimeRegex.getQuotedRegex(pattern_reg, flags_reg) - * Format: QUOTE_REGEX rd pattern_reg flags_reg implicit_unicode_strings_u warning_state warning_bits_index quote_construction + * Format: QUOTE_REGEX rd pattern_reg flags_reg implicit_unicode_strings_u warning_state warning_bits_index quote_construction named_character_metadata_index * quote_construction: 0 = match, 1 = scalar coercion, 2 = syntactic qr//. */ public static final short QUOTE_REGEX = 159; @@ -1835,7 +1835,7 @@ public class Opcodes { /** * Quote regex with /o modifier support: rd = RuntimeRegex.getQuotedRegex(pattern_reg, flags_reg, callsite_id) - * Format: QUOTE_REGEX_O rd pattern_reg flags_reg callsite_id implicit_unicode_strings_u warning_state warning_bits_index quote_construction + * Format: QUOTE_REGEX_O rd pattern_reg flags_reg callsite_id implicit_unicode_strings_u warning_state warning_bits_index quote_construction named_character_metadata_index * quote_construction: 0 = match, 1 = scalar coercion, 2 = syntactic qr//. */ public static final short QUOTE_REGEX_O = 374; @@ -2491,6 +2491,9 @@ public class Opcodes { /** Restore lexical %^H after leaving a nested block. Format: SET_CALL_SITE_HINT_HASH id. */ public static final short SET_CALL_SITE_HINT_HASH = 527; + /** Restore lexical warning bits after leaving a nested block. Format: SET_CALL_SITE_WARNING_BITS bitsIdx. */ + public static final short SET_CALL_SITE_WARNING_BITS = 528; + /** Return the mutable {@code $#array} cell. Format: ARRAY_LAST_INDEX_LVALUE rd arrayReg. */ public static final short ARRAY_LAST_INDEX_LVALUE = 518; diff --git a/src/main/java/org/perlonjava/backend/bytecode/SlowOpcodeHandler.java b/src/main/java/org/perlonjava/backend/bytecode/SlowOpcodeHandler.java index 178720ae9b..61e5a89b87 100644 --- a/src/main/java/org/perlonjava/backend/bytecode/SlowOpcodeHandler.java +++ b/src/main/java/org/perlonjava/backend/bytecode/SlowOpcodeHandler.java @@ -315,6 +315,12 @@ public static int executeEvalString( } evalTrace("EVAL_STRING opcode enter rd=r" + rd + " strReg=r" + stringReg + " ctx=" + evalCallContext + " evalSite=" + evalSiteIndex + + " warnUninitialized=" + (siteWarningBits != null + && org.perlonjava.runtime.runtimetypes.WarningFlags.isEnabledInBits( + siteWarningBits, "uninitialized")) + + " fatalUninitialized=" + (siteWarningBits != null + && org.perlonjava.runtime.runtimetypes.WarningFlags.isFatalInBits( + siteWarningBits, "uninitialized")) + " codeType=" + codeScalar.type + " codeLen=" + codeScalar.toString().length() + " src=" + (code != null ? code.sourceName : "null")); diff --git a/src/main/java/org/perlonjava/backend/bytecode/VariableCollectorVisitor.java b/src/main/java/org/perlonjava/backend/bytecode/VariableCollectorVisitor.java index 10eee85b62..d7efeee859 100644 --- a/src/main/java/org/perlonjava/backend/bytecode/VariableCollectorVisitor.java +++ b/src/main/java/org/perlonjava/backend/bytecode/VariableCollectorVisitor.java @@ -24,6 +24,7 @@ public class VariableCollectorVisitor implements Visitor { private final Set declaredVariables; private final Map declaredOurVariables; private boolean hasEvalString = false; + private boolean requiresAllRuntimeLexicals = false; private final Deque> localScopes = new ArrayDeque<>(); private int subroutineDepth = 0; @@ -57,6 +58,16 @@ public boolean hasEvalString() { return hasEvalString; } + /** + * Returns true when runtime-generated source can reference any visible + * lexical, rather than only the variable nodes present in the static AST. + * This includes eval STRING and executable regex interpolation whose + * string overload can produce callback source at match time. + */ + public boolean requiresAllRuntimeLexicals() { + return requiresAllRuntimeLexicals; + } + private boolean isDeclarationOperator(String op) { return op.equals("my") || op.equals("state") || op.equals("our"); } @@ -65,6 +76,14 @@ private boolean isVariableOperator(String op) { return op.equals("$") || op.equals("@") || op.equals("%") || op.equals("&"); } + private boolean hasDynamicRegexPattern(OperatorNode node) { + if (!(node.operand instanceof ListNode operands) + || operands.elements == null || operands.elements.isEmpty()) { + return false; + } + return !(operands.elements.getFirst() instanceof StringNode); + } + private boolean isDeclaredLocal(String varName) { for (Set scope : localScopes) { if (scope.contains(varName)) return true; @@ -162,6 +181,14 @@ public void visit(OperatorNode node) { // at runtime, so we must capture all visible variables. if (op.equals("eval") || op.equals("evalbytes")) { hasEvalString = true; + requiresAllRuntimeLexicals = true; + } else if (op.equals("regexTemplate")) { + requiresAllRuntimeLexicals = true; + } else if ((op.equals("quoteRegex") || op.equals("matchRegex")) + && hasDynamicRegexPattern(node)) { + // A blessed interpolation can turn an otherwise ordinary dynamic + // pattern into executable callback source through dot overload. + requiresAllRuntimeLexicals = true; } // Check if this is a variable reference (sigil + identifier) diff --git a/src/main/java/org/perlonjava/backend/jvm/EmitBlock.java b/src/main/java/org/perlonjava/backend/jvm/EmitBlock.java index 1359878a9d..82eadb78b4 100644 --- a/src/main/java/org/perlonjava/backend/jvm/EmitBlock.java +++ b/src/main/java/org/perlonjava/backend/jvm/EmitBlock.java @@ -311,10 +311,11 @@ public static void emitBlock(EmitterVisitor emitterVisitor, BlockNode node) { list.get(0) instanceof OperatorNode localOp && localOp.operator.equals("local") && list.get(1) instanceof For1Node forNode && forNode.needsArrayOfAlias) { - // Pre-evaluate the For1Node's list to array of aliases before localizing $_ + // Pre-evaluate the For1Node's list before localizing $_. Keep an + // actual array live; foreachAliasIterator snapshots other list + // expressions when the loop is emitted. int tempArrayIndex = emitterVisitor.ctx.symbolTable.allocateLocalVariable(); forNode.list.accept(emitterVisitor.with(RuntimeContextType.LIST)); - mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "org/perlonjava/runtime/runtimetypes/RuntimeBase", "getArrayOfAlias", "()Lorg/perlonjava/runtime/runtimetypes/RuntimeArray;", false); mv.visitVarInsn(Opcodes.ASTORE, tempArrayIndex); // Mark the For1Node to use the pre-evaluated array diff --git a/src/main/java/org/perlonjava/backend/jvm/EmitForeach.java b/src/main/java/org/perlonjava/backend/jvm/EmitForeach.java index 0ea749e00e..89ff0f79b3 100644 --- a/src/main/java/org/perlonjava/backend/jvm/EmitForeach.java +++ b/src/main/java/org/perlonjava/backend/jvm/EmitForeach.java @@ -376,8 +376,11 @@ public static void emitFor1(EmitterVisitor emitterVisitor, For1Node node) { mv.visitInsn(Opcodes.POP); // Discard the returned scalar } - // Get iterator from the pre-evaluated array - mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "org/perlonjava/runtime/runtimetypes/RuntimeArray", "iterator", "()Ljava/util/Iterator;", false); + // Preserve live membership for an array while retaining snapshot + // iteration for non-array list expressions and tied arrays. + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, + "org/perlonjava/runtime/runtimetypes/RuntimeBase", + "foreachAliasIterator", "()Ljava/util/Iterator;", false); mv.visitVarInsn(Opcodes.ASTORE, iteratorIndex); } else if (isGlobalUnderscore) { // Global $_ as loop variable: use pre-evaluated list (evaluated in enclosing scope) @@ -410,10 +413,11 @@ public static void emitFor1(EmitterVisitor emitterVisitor, For1Node node) { mv.visitVarInsn(Opcodes.ASTORE, iteratorIndex); mv.visitJumpInsn(Opcodes.GOTO, afterIterLabel); - // Non-range: preserve aliasing semantics by iterating an array-of-alias. + // Non-range: preserve aliases and live membership for an actual array. mv.visitLabel(notRangeLabel); - mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "org/perlonjava/runtime/runtimetypes/RuntimeBase", "getArrayOfAlias", "()Lorg/perlonjava/runtime/runtimetypes/RuntimeArray;", false); - mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "org/perlonjava/runtime/runtimetypes/RuntimeArray", "iterator", "()Ljava/util/Iterator;", false); + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, + "org/perlonjava/runtime/runtimetypes/RuntimeBase", + "foreachAliasIterator", "()Ljava/util/Iterator;", false); mv.visitVarInsn(Opcodes.ASTORE, iteratorIndex); mv.visitLabel(afterIterLabel); diff --git a/src/main/java/org/perlonjava/backend/jvm/EmitRegex.java b/src/main/java/org/perlonjava/backend/jvm/EmitRegex.java index a3e4fb6b9a..0492004254 100644 --- a/src/main/java/org/perlonjava/backend/jvm/EmitRegex.java +++ b/src/main/java/org/perlonjava/backend/jvm/EmitRegex.java @@ -8,6 +8,10 @@ import org.perlonjava.runtime.regex.RuntimeRegex; import org.perlonjava.runtime.runtimetypes.PerlCompilerException; import org.perlonjava.runtime.runtimetypes.RuntimeContextType; +import org.perlonjava.runtime.runtimetypes.RuntimeScalar; +import org.perlonjava.frontend.parser.StringParser; +import org.perlonjava.runtime.NamedCharacterExpansion; +import org.perlonjava.runtime.NamedCharacterExpansionMap; import java.util.ArrayList; import java.util.HashMap; @@ -25,9 +29,12 @@ static void handleRegexCallback(EmitterVisitor emitterVisitor, OperatorNode node emitterVisitor.ctx.mv.visitLdcInsn((String) node.getAnnotation("regexCallbackKind")); emitterVisitor.ctx.mv.visitLdcInsn((String) node.getAnnotation("regexCallbackPackage")); emitterVisitor.ctx.mv.visitLdcInsn((String) node.getAnnotation("regexCallbackSource")); + emitterVisitor.ctx.mv.visitInsn(Boolean.TRUE.equals(node.getAnnotation( + "regexCallbackUninitializedWarningsEnabled")) + ? Opcodes.ICONST_1 : Opcodes.ICONST_0); emitterVisitor.ctx.mv.visitMethodInsn(Opcodes.INVOKESTATIC, "org/perlonjava/runtime/regex/RuntimeRegexCallback", "wrap", - "(Lorg/perlonjava/runtime/runtimetypes/RuntimeScalar;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lorg/perlonjava/runtime/runtimetypes/RuntimeScalar;", + "(Lorg/perlonjava/runtime/runtimetypes/RuntimeScalar;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)Lorg/perlonjava/runtime/runtimetypes/RuntimeScalar;", false); } @@ -64,7 +71,10 @@ private static void maybeApplyUnicodeStringsRegexModifiers(EmitterVisitor emitte private static void emitRegexWarningState(EmitterVisitor emitterVisitor, OperatorNode node) { boolean enabled = Boolean.TRUE.equals(node.getAnnotation("regexWarningsEnabled")); boolean fatal = Boolean.TRUE.equals(node.getAnnotation("regexWarningsFatal")); - emitterVisitor.ctx.mv.visitInsn(fatal ? Opcodes.ICONST_2 + boolean suppressed = Boolean.TRUE.equals( + node.getAnnotation("regexWarningsSuppressed")); + emitterVisitor.ctx.mv.visitInsn(suppressed ? Opcodes.ICONST_M1 + : fatal ? Opcodes.ICONST_2 : enabled ? Opcodes.ICONST_1 : Opcodes.ICONST_0); emitterVisitor.ctx.mv.visitMethodInsn(Opcodes.INVOKESTATIC, "org/perlonjava/runtime/regex/RegexQuoteMeta", @@ -80,6 +90,50 @@ private static void emitRegexWarningState(EmitterVisitor emitterVisitor, Operato "setCallSiteWarningBits", "(Ljava/lang/String;)V", false); } + /** Stack: pattern -> pattern carrying this literal's immutable lexical results. */ + private static void attachNamedCharacterExpansions( + EmitterVisitor emitterVisitor, OperatorNode node, ListNode operand) { + Object annotated = node.getAnnotation( + StringParser.LEXICAL_NAMED_CHARACTER_EXPANSIONS); + if (annotated == null) { + annotated = operand.getAnnotation( + StringParser.LEXICAL_NAMED_CHARACTER_EXPANSIONS); + } + if (!(annotated instanceof NamedCharacterExpansionMap metadata)) return; + + emitterVisitor.ctx.mv.visitLdcInsn(metadata.literalIdentity().value()); + emitterVisitor.ctx.mv.visitLdcInsn(metadata.callableIdentity().value()); + emitterVisitor.ctx.mv.visitLdcInsn(metadata.expansions().size() * 7); + emitterVisitor.ctx.mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/String"); + int index = 0; + for (var entry : metadata.expansions().entrySet()) { + NamedCharacterExpansionMap.Key key = entry.getKey(); + NamedCharacterExpansion expansion = entry.getValue(); + String[] fields = { + key.sourceSpelling(), key.sourceMode().name(), + expansion.sequence(), expansion.sourceMode().name(), + Boolean.toString(expansion.promotesUnicode()), + expansion.status().name(), expansion.diagnostic() + }; + for (String field : fields) { + emitterVisitor.ctx.mv.visitInsn(Opcodes.DUP); + emitterVisitor.ctx.mv.visitLdcInsn(index++); + if (field == null) emitterVisitor.ctx.mv.visitInsn(Opcodes.ACONST_NULL); + else emitterVisitor.ctx.mv.visitLdcInsn(field); + emitterVisitor.ctx.mv.visitInsn(Opcodes.AASTORE); + } + } + emitterVisitor.ctx.mv.visitMethodInsn(Opcodes.INVOKESTATIC, + "org/perlonjava/runtime/NamedCharacterExpansionMap", "fromFlat", + "(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)Lorg/perlonjava/runtime/NamedCharacterExpansionMap;", + false); + emitterVisitor.ctx.mv.visitMethodInsn(Opcodes.INVOKESTATIC, + "org/perlonjava/runtime/regex/RuntimeRegex", + "attachNamedCharacterExpansions", + "(Lorg/perlonjava/runtime/runtimetypes/RuntimeScalar;Lorg/perlonjava/runtime/NamedCharacterExpansionMap;)Lorg/perlonjava/runtime/runtimetypes/RuntimeScalar;", + false); + } + /** * Handles the binding regex operation where a variable is bound to a regex operation. * This method processes the binary operator node representing the binding operation. @@ -99,6 +153,9 @@ static void handleBindRegex(EmitterVisitor emitterVisitor, BinaryOperatorNode no // Do not mutate the original AST: create a local copy of the operator and its operand list. ListNode boundListNode = new ListNode(new ArrayList<>(listNode.elements), listNode.tokenIndex); boundListNode.handle = listNode.handle; + if (listNode.annotations != null) { + boundListNode.annotations = new HashMap<>(listNode.annotations); + } boundListNode.elements.add(node.left); OperatorNode boundRight = new OperatorNode(right.operator, boundListNode, right.tokenIndex); @@ -311,6 +368,7 @@ static void handleQuoteRegex(EmitterVisitor emitterVisitor, OperatorNode node) { // Process pattern and flags operand.elements.get(0).accept(scalarVisitor); // Pattern + attachNamedCharacterExpansions(emitterVisitor, node, operand); operand.elements.get(1).accept(scalarVisitor); // Flags maybeApplyUnicodeStringsRegexModifiers(emitterVisitor); emitRegexWarningState(emitterVisitor, node); @@ -334,18 +392,29 @@ static void handleQuoteRegex(EmitterVisitor emitterVisitor, OperatorNode node) { /** Validate non-interpolated qr// at CV compilation, as Perl does. */ private static void validateLiteralRegex(EmitterVisitor emitterVisitor, OperatorNode node, ListNode operand) { + if (node.getBooleanAnnotation("literalSyntaxValidated")) return; if (operand.elements.size() < 2 || !(operand.elements.get(1) instanceof StringNode flags)) { return; } String pattern = RegexLiteralAnalyzer.constantString(operand.elements.get(0)); if (pattern == null || RuntimeRegex.requiresRuntimeUnicodePropertyResolution(pattern)) return; + String diagnosticPattern = RegexLiteralAnalyzer.constantSourceString( + operand.elements.get(0)); String modifiers = flags.value; if (unicodeStringsEnabled(emitterVisitor) && !modifiers.contains("u")) { modifiers += "u"; } try { - RuntimeRegex.validateLiteralSyntax(pattern, modifiers); + StringParser.validateLiteralNamedCharacters( + operand, pattern, modifiers, + diagnosticPattern == null ? pattern : diagnosticPattern); + Object expansions = operand.getAnnotation( + StringParser.LEXICAL_NAMED_CHARACTER_EXPANSIONS); + if (expansions != null) { + node.setAnnotation(StringParser.LEXICAL_NAMED_CHARACTER_EXPANSIONS, + expansions); + } } catch (PerlCompilerException exception) { throw PerlCompilerException.withSourceLocation(node.tokenIndex, exception.getMessage(), emitterVisitor.ctx.errorUtil); @@ -373,6 +442,7 @@ static void handleMatchRegex(EmitterVisitor emitterVisitor, OperatorNode node) { // Process pattern and flags operand.elements.get(0).accept(scalarVisitor); // Pattern + attachNamedCharacterExpansions(emitterVisitor, node, operand); flagsNode.accept(scalarVisitor); // Flags maybeApplyUnicodeStringsRegexModifiers(emitterVisitor); emitRegexWarningState(emitterVisitor, node); diff --git a/src/main/java/org/perlonjava/backend/jvm/EmitSubroutine.java b/src/main/java/org/perlonjava/backend/jvm/EmitSubroutine.java index 1250216780..2271ec5773 100644 --- a/src/main/java/org/perlonjava/backend/jvm/EmitSubroutine.java +++ b/src/main/java/org/perlonjava/backend/jvm/EmitSubroutine.java @@ -108,9 +108,12 @@ public static void emitSubroutine(EmitterContext ctx, SubroutineNode node) { MethodVisitor mv = ctx.mv; Set declaredLexicalNames = new LinkedHashSet<>(); + boolean tracksRuntimeRegexLexicals = false; if (node.block != null) { - node.block.accept(new VariableCollectorVisitor( - new HashSet<>(), declaredLexicalNames)); + VariableCollectorVisitor metadataCollector = new VariableCollectorVisitor( + new HashSet<>(), declaredLexicalNames); + node.block.accept(metadataCollector); + tracksRuntimeRegexLexicals = metadataCollector.requiresAllRuntimeLexicals(); } // Retrieve closure variable list (copy to avoid corrupting the cache) @@ -145,7 +148,7 @@ public static void emitSubroutine(EmitterContext ctx, SubroutineNode node) { Set usedVars = new HashSet<>(); VariableCollectorVisitor collector = new VariableCollectorVisitor(usedVars); node.block.accept(collector); - if (!collector.hasEvalString()) { + if (!collector.requiresAllRuntimeLexicals()) { int skip = EmitterMethodCreator.skipVariables; int pos = 0; Iterator> it = @@ -696,6 +699,15 @@ public static void emitSubroutine(EmitterContext ctx, SubroutineNode node) { + "Lorg/perlonjava/runtime/runtimetypes/RuntimeScalar;", false); + if (tracksRuntimeRegexLexicals) { + mv.visitMethodInsn(Opcodes.INVOKESTATIC, + "org/perlonjava/runtime/runtimetypes/RuntimeCode", + "markRuntimeRegexLexicals", + "(Lorg/perlonjava/runtime/runtimetypes/RuntimeScalar;)" + + "Lorg/perlonjava/runtime/runtimetypes/RuntimeScalar;", + false); + } + // 6. Clean up the stack if context is VOID if (ctx.contextType == RuntimeContextType.VOID) { mv.visitInsn(Opcodes.POP); // Remove the RuntimeScalar object from the stack diff --git a/src/main/java/org/perlonjava/frontend/analysis/ConstantFoldingVisitor.java b/src/main/java/org/perlonjava/frontend/analysis/ConstantFoldingVisitor.java index 0db3f3ff0f..ddf191584e 100644 --- a/src/main/java/org/perlonjava/frontend/analysis/ConstantFoldingVisitor.java +++ b/src/main/java/org/perlonjava/frontend/analysis/ConstantFoldingVisitor.java @@ -450,6 +450,9 @@ public void visit(OperatorNode node) { if (foldedOperand != node.operand) { OperatorNode newNode = new OperatorNode(node.operator, foldedOperand, node.tokenIndex); newNode.id = node.id; + if (node.annotations != null) { + newNode.annotations = new java.util.HashMap<>(node.annotations); + } result = newNode; } else { result = node; @@ -524,7 +527,12 @@ public void visit(ListNode node) { } if (changed) { - result = new ListNode(foldedElements, node.tokenIndex); + ListNode folded = new ListNode(foldedElements, node.tokenIndex); + folded.handle = node.handle; + if (node.annotations != null) { + folded.annotations = new java.util.HashMap<>(node.annotations); + } + result = folded; } else { result = node; } diff --git a/src/main/java/org/perlonjava/frontend/analysis/RegexLiteralAnalyzer.java b/src/main/java/org/perlonjava/frontend/analysis/RegexLiteralAnalyzer.java index b0cce40e01..3e20852bda 100644 --- a/src/main/java/org/perlonjava/frontend/analysis/RegexLiteralAnalyzer.java +++ b/src/main/java/org/perlonjava/frontend/analysis/RegexLiteralAnalyzer.java @@ -36,4 +36,51 @@ public static String constantString(Node node) { } return null; } + + /** + * Return a syntax-equivalent literal source, or {@code null} when runtime + * interpolation is required. Parser-created callbacks are replaced by + * same-width neutral constructs so later diagnostic offsets remain in the + * original literal coordinate space. + */ + public static String constantSyntaxString(Node node) { + return constantTemplateString(node, true); + } + + /** Return the complete literal source, including parser-created callbacks. */ + public static String constantSourceString(Node node) { + return constantTemplateString(node, false); + } + + private static String constantTemplateString(Node node, boolean maskCallbacks) { + String constant = constantString(node); + if (constant != null) return constant; + if (node instanceof BinaryOperatorNode binary && ".".equals(binary.operator)) { + String left = constantTemplateString(binary.left, maskCallbacks); + String right = constantTemplateString(binary.right, maskCallbacks); + return left == null || right == null ? null : left + right; + } + if (node instanceof OperatorNode operator && "regexTemplate".equals(operator.operator) + && operator.operand instanceof ListNode parts) { + StringBuilder source = new StringBuilder(); + for (Node part : parts.elements) { + String value = constantTemplateString(part, maskCallbacks); + if (value == null) return null; + source.append(value); + } + return source.toString(); + } + if (node instanceof OperatorNode operator && "regexCallback".equals(operator.operator)) { + Object callbackSource = operator.getAnnotation("regexCallbackSource"); + if (!(callbackSource instanceof String source)) return null; + if (!maskCallbacks) return source; + Object kind = operator.getAnnotation("regexCallbackKind"); + String skeleton = "CONDITION".equals(kind) ? "?=)" : "(?:)"; + if (source.length() < skeleton.length()) return null; + return skeleton.substring(0, skeleton.length() - 1) + + " ".repeat(source.length() - skeleton.length()) + + skeleton.charAt(skeleton.length() - 1); + } + return null; + } } diff --git a/src/main/java/org/perlonjava/frontend/parser/ParseBlock.java b/src/main/java/org/perlonjava/frontend/parser/ParseBlock.java index 3828f30474..f737d38546 100644 --- a/src/main/java/org/perlonjava/frontend/parser/ParseBlock.java +++ b/src/main/java/org/perlonjava/frontend/parser/ParseBlock.java @@ -123,6 +123,7 @@ public static BlockWithScope parseBlock(Parser parser, boolean exitScope) { } Integer postBlockStrictOptions = null; + String postBlockWarningBits = null; // Run compile-time end-of-scope callbacks while this block is still // the innermost parser scope. This must happen before returning to @@ -134,6 +135,7 @@ public static BlockWithScope parseBlock(Parser parser, boolean exitScope) { if (exitScope) { parser.ctx.symbolTable.exitScope(scopeIndex); postBlockStrictOptions = parser.ctx.symbolTable.getStrictOptions(); + postBlockWarningBits = parser.ctx.symbolTable.getWarningBitsString(); } // Create and return the block node with all parsed statements @@ -141,6 +143,7 @@ public static BlockWithScope parseBlock(Parser parser, boolean exitScope) { blockNode.labels = blockLabels; // Set the collected labels in the BlockNode if (postBlockStrictOptions != null) { blockNode.setAnnotation("postBlockStrictOptions", postBlockStrictOptions); + blockNode.setAnnotation("postBlockWarningBits", postBlockWarningBits); } return new BlockWithScope(blockNode, scopeIndex); } diff --git a/src/main/java/org/perlonjava/frontend/parser/ParseInfix.java b/src/main/java/org/perlonjava/frontend/parser/ParseInfix.java index b7eff890e7..780e0d2ae4 100644 --- a/src/main/java/org/perlonjava/frontend/parser/ParseInfix.java +++ b/src/main/java/org/perlonjava/frontend/parser/ParseInfix.java @@ -195,10 +195,13 @@ public static Node parseInfixOperation(Parser parser, Node left, int precedence) if ((operator.equals("=~") || operator.equals("!~")) && !isRegexOperator(right)) { String flags = StringParser.addLexicalRegexContext(parser.ctx, ""); - right = new OperatorNode("quoteRegex", - new ListNode(List.of(right, - new StringNode(flags, right.getIndex())), right.getIndex()), - right.getIndex()); + ListNode regexOperand = new ListNode(new ArrayList<>(List.of(right, + new StringNode(flags, right.getIndex()))), right.getIndex()); + if (right instanceof StringNode) { + StringParser.captureLexicalNamedCharacterTranslator( + regexOperand, right.getIndex(), parser.ctx); + } + right = new OperatorNode("quoteRegex", regexOperand, right.getIndex()); } BinaryOperatorNode node = new BinaryOperatorNode(operator, left, right, parser.tokenIndex); diff --git a/src/main/java/org/perlonjava/frontend/parser/SpecialBlockParser.java b/src/main/java/org/perlonjava/frontend/parser/SpecialBlockParser.java index d3fc5b6ea5..29d1b66f29 100644 --- a/src/main/java/org/perlonjava/frontend/parser/SpecialBlockParser.java +++ b/src/main/java/org/perlonjava/frontend/parser/SpecialBlockParser.java @@ -259,7 +259,7 @@ static RuntimeList runSpecialBlock(Parser parser, String blockPhase, Node block, Set usedVars = new HashSet<>(); VariableCollectorVisitor collector = new VariableCollectorVisitor(usedVars); block.accept(collector); - boolean captureAllVisibleVariables = collector.hasEvalString(); + boolean captureAllVisibleVariables = collector.requiresAllRuntimeLexicals(); for (SymbolTable.SymbolEntry entry : outerVars.values()) { if (!entry.name().equals("@_") && !entry.decl().isEmpty()) { // Skip lexical subs (entries starting with &) - they are stored as hidden variables diff --git a/src/main/java/org/perlonjava/frontend/parser/StatementParser.java b/src/main/java/org/perlonjava/frontend/parser/StatementParser.java index ff00716971..e958e26295 100644 --- a/src/main/java/org/perlonjava/frontend/parser/StatementParser.java +++ b/src/main/java/org/perlonjava/frontend/parser/StatementParser.java @@ -1053,6 +1053,18 @@ public static Node parseUseDeclaration(Parser parser, LexerToken token) { } } + // Source decoding after use/no utf8 belongs to the + // enclosing parser scope. An interpreter-backed + // synthetic import frame restores its own pragma + // state on return, so retain the public hint here. + if ("utf8".equals(packageName)) { + if (isNoDeclaration) { + parser.ctx.symbolTable.disableStrictOption(Strict.HINT_UTF8); + } else { + parser.ctx.symbolTable.enableStrictOption(Strict.HINT_UTF8); + } + } + // Check if a source filter was installed during import() // If so, we need to rejoin remaining tokens, apply the filter, and re-tokenize if (FilterUtilCall.wasFilterInstalled()) { diff --git a/src/main/java/org/perlonjava/frontend/parser/StringDoubleQuoted.java b/src/main/java/org/perlonjava/frontend/parser/StringDoubleQuoted.java index d351bfa197..7ee46f3c07 100644 --- a/src/main/java/org/perlonjava/frontend/parser/StringDoubleQuoted.java +++ b/src/main/java/org/perlonjava/frontend/parser/StringDoubleQuoted.java @@ -9,6 +9,7 @@ import org.perlonjava.frontend.lexer.LexerTokenType; import org.perlonjava.runtime.operators.WarnDie; import org.perlonjava.runtime.perlmodule.Warnings; +import org.perlonjava.runtime.regex.RegexMarkers; import org.perlonjava.runtime.runtimetypes.PerlCompilerException; import org.perlonjava.runtime.runtimetypes.RuntimeScalar; @@ -65,7 +66,7 @@ protected boolean regexCodeBlocksAreActive() { // transformed before it becomes regex source. Perl therefore treats an // executable-looking group there as runtime-generated source, not as a // literal callback visible to the quote lexer. - return caseModifiers.isEmpty(); + return caseModifiers.isEmpty() && super.regexCodeBlocksAreActive(); } /** @@ -80,8 +81,15 @@ protected boolean regexCodeBlocksAreActive() { * @param isRegex True if parsing regex pattern (affects interpolation) * @param parseEscapes True to process escape sequences, false to preserve them */ - private StringDoubleQuoted(EmitterContext ctx, List tokens, Parser parser, int tokenIndex, boolean isRegex, boolean parseEscapes, boolean interpolateVariable, boolean isRegexReplacement, boolean isRegexQuoteConstruction) { - super(ctx, tokens, parser, tokenIndex, isRegex, parseEscapes, interpolateVariable, isRegexReplacement, isRegexQuoteConstruction); + private StringDoubleQuoted(EmitterContext ctx, List tokens, + Parser parser, int tokenIndex, boolean isRegex, + boolean parseEscapes, boolean interpolateVariable, + boolean isRegexReplacement, + boolean isRegexQuoteConstruction, + boolean deferNamedCharacterDiagnosticsToRegex) { + super(ctx, tokens, parser, tokenIndex, isRegex, parseEscapes, + interpolateVariable, isRegexReplacement, + isRegexQuoteConstruction, deferNamedCharacterDiagnosticsToRegex); } /** @@ -150,6 +158,34 @@ static Node parseDoubleQuotedString(EmitterContext ctx, StringParser.ParsedStrin } static Node parseDoubleQuotedString(EmitterContext ctx, StringParser.ParsedString rawStr, boolean parseEscapes, boolean interpolateVariable, boolean isRegexReplacement, List sharedHeredocNodes, Parser originalParser, boolean preprocessBracedBackslashQuotes, boolean isRegexQuoteConstruction) { + return parseDoubleQuotedString(ctx, rawStr, parseEscapes, interpolateVariable, + isRegexReplacement, sharedHeredocNodes, originalParser, + preprocessBracedBackslashQuotes, isRegexQuoteConstruction, false); + } + + static Node parseDoubleQuotedString(EmitterContext ctx, StringParser.ParsedString rawStr, + boolean parseEscapes, boolean interpolateVariable, + boolean isRegexReplacement, + List sharedHeredocNodes, + Parser originalParser, + boolean preprocessBracedBackslashQuotes, + boolean isRegexQuoteConstruction, + boolean regexExtended) { + return parseDoubleQuotedString(ctx, rawStr, parseEscapes, + interpolateVariable, isRegexReplacement, sharedHeredocNodes, + originalParser, preprocessBracedBackslashQuotes, + isRegexQuoteConstruction, regexExtended, false); + } + + static Node parseDoubleQuotedString(EmitterContext ctx, StringParser.ParsedString rawStr, + boolean parseEscapes, boolean interpolateVariable, + boolean isRegexReplacement, + List sharedHeredocNodes, + Parser originalParser, + boolean preprocessBracedBackslashQuotes, + boolean isRegexQuoteConstruction, + boolean regexExtended, + boolean deferNamedCharacterDiagnosticsToRegex) { // Extract the first buffer (double-quoted strings don't have multiple parts like here-docs) var input = rawStr.buffers.getFirst(); var tokenIndex = rawStr.next; @@ -205,7 +241,11 @@ static Node parseDoubleQuotedString(EmitterContext ctx, StringParser.ParsedStrin parser.baseLineNumber = rawStr.sourceLine; // Create and run the double-quoted string parser with original token offset tracking - var doubleQuotedParser = new StringDoubleQuoted(ctx, tokens, parser, tokenIndex, isRegex, parseEscapes, interpolateVariable, isRegexReplacement, isRegexQuoteConstruction); + var doubleQuotedParser = new StringDoubleQuoted(ctx, tokens, parser, + tokenIndex, isRegex, parseEscapes, interpolateVariable, + isRegexReplacement, isRegexQuoteConstruction, + deferNamedCharacterDiagnosticsToRegex); + doubleQuotedParser.setRegexExtended(regexExtended); // Set up offset tracking and original string content for proper error reporting doubleQuotedParser.setOriginalTokenOffset(tokenIndex); @@ -486,6 +526,8 @@ private void parseDoubleQuotedEscapesRegex() { // Pop and apply the most recent case modifier if (!caseModifiers.isEmpty()) { applyCaseModifier(caseModifiers.pop()); + } else { + appendToCurrentSegment(RegexMarkers.LITERAL_USELESS_CASE_ESCAPE); } } @@ -519,7 +561,7 @@ private void parseDoubleQuotedEscapesRegex() { case "p", "P" -> preserveUnicodePropertyEscape(escape); // Unknown escape - treat as literal character - default -> appendToCurrentSegment("\\" + escape); + default -> appendLiteralToCurrentSegment("\\" + escape); } } @@ -630,17 +672,7 @@ private void parseDoubleQuotedEscapes() { // Control character: \cX case "c" -> { var controlChar = TokenUtils.consumeChar(parser); - if (controlChar.isEmpty()) { - throw new PerlCompilerException(parser.tokenIndex, "Missing control char name in \\c", parser.ctx.errorUtil); - } - var c = controlChar.charAt(0); - var result = (c >= 'A' && c <= 'Z') ? String.valueOf((char) (c - 'A' + 1)) - : (c >= 'a' && c <= 'z') ? String.valueOf((char) (c - 'a' + 1)) - : c == '@' ? String.valueOf((char) 0) - : (c >= '[' && c <= '_') ? String.valueOf((char) (c - '[' + 27)) - : c == '?' ? String.valueOf((char) 127) - : String.valueOf(c); - appendToCurrentSegment(result); + appendToCurrentSegment(controlCharacterValue(controlChar)); } // Case modification end marker diff --git a/src/main/java/org/perlonjava/frontend/parser/StringParser.java b/src/main/java/org/perlonjava/frontend/parser/StringParser.java index 9706ddebc2..b7f07bb2d4 100644 --- a/src/main/java/org/perlonjava/frontend/parser/StringParser.java +++ b/src/main/java/org/perlonjava/frontend/parser/StringParser.java @@ -4,19 +4,25 @@ import org.perlonjava.backend.jvm.EmitterContext; import org.perlonjava.frontend.astnode.*; +import org.perlonjava.frontend.analysis.RegexLiteralAnalyzer; import org.perlonjava.frontend.lexer.Lexer; import org.perlonjava.frontend.lexer.LexerToken; import org.perlonjava.frontend.lexer.LexerTokenType; import org.perlonjava.runtime.operators.PerlUtfString; +import org.perlonjava.runtime.HintHashRegistry; +import org.perlonjava.runtime.NamedCharacterExpansion; +import org.perlonjava.runtime.NamedCharacterExpansionMap; import org.perlonjava.runtime.runtimetypes.PerlCompilerException; import org.perlonjava.runtime.runtimetypes.GlobalVariable; import org.perlonjava.runtime.runtimetypes.RuntimeScalar; import org.perlonjava.runtime.runtimetypes.RuntimeCode; import org.perlonjava.runtime.regex.RuntimeRegex; +import org.perlonjava.runtime.regex.RegexMarkers; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.concurrent.atomic.AtomicLong; import static org.perlonjava.runtime.perlmodule.Strict.HINT_UTF8; import static org.perlonjava.runtime.perlmodule.Strict.HINT_RE_ASCII; @@ -40,6 +46,18 @@ */ public class StringParser { + public static final String LEXICAL_NAMED_CHARACTER_TRANSLATOR = + "lexicalNamedCharacterTranslator"; + public static final String LEXICAL_NAMED_CHARACTER_SOURCE_MODE = + "lexicalNamedCharacterSourceMode"; + public static final String LEXICAL_NAMED_CHARACTER_EXPANSIONS = + "lexicalNamedCharacterExpansions"; + private static final String LEXICAL_NAMED_CHARACTER_LITERAL_IDENTITY = + "lexicalNamedCharacterLiteralIdentity"; + private static final String LEXICAL_NAMED_CHARACTER_CALLABLE_IDENTITY = + "lexicalNamedCharacterCallableIdentity"; + private static final AtomicLong NEXT_LEXICAL_REGEX_IDENTITY = new AtomicLong(); + /** Historical HINT_NEW_RE bit used by old regex interpolation parsing. */ private static final int HINT_NEW_RE = 0x00010000; @@ -90,7 +108,7 @@ public static ParsedString parseRawStringWithDelimiter(EmitterContext ctx, List< while (state != END_TOKEN) { LexerToken currentToken = tokens.get(tokPos); if (currentToken.type == LexerTokenType.EOF) { - String errorMsg = endDelim == '/' + String errorMsg = isRegex ? "Search pattern not terminated" : "Can't find string terminator " + (markerDelimiter != null ? "\".\"" : endDelim) @@ -358,17 +376,19 @@ public static ParsedString parseRawStrings(Parser parser, EmitterContext ctx, Li } // fetch the last string: s/aaa/bbb/LAST - String modifier = ""; - if (tokens.get(pos).type == LexerTokenType.IDENTIFIER) { - modifier = tokens.get(pos).text; - ast.next = pos + 1; + StringBuilder modifier = new StringBuilder(); + while (tokens.get(pos).type == LexerTokenType.IDENTIFIER + || tokens.get(pos).type == LexerTokenType.NUMBER) { + modifier.append(tokens.get(pos).text); + pos++; + ast.next = pos; } ArrayList buffers = ast.buffers; if (buffers == null) { buffers = new ArrayList<>(); ast.buffers = buffers; } - buffers.add(modifier); + buffers.add(modifier.toString()); return ast; } @@ -378,6 +398,7 @@ static Node parseRegexString(EmitterContext ctx, ParsedString rawStr, Parser par static Node parseRegexString(EmitterContext ctx, ParsedString rawStr, Parser parser, String modifiers, boolean isRegexQuoteConstruction) { Node parsed; + boolean hasXModifier = modifiers != null && modifiers.contains("x"); if (rawStr.startDelim == '\'') { // An apostrophe delimiter suppresses ordinary interpolation, but @@ -387,11 +408,8 @@ static Node parseRegexString(EmitterContext ctx, ParsedString rawStr, Parser par parsed = StringDoubleQuoted.parseDoubleQuotedString( ctx, rawStr, false, false, true, parser != null ? parser.getHeredocNodes() : null, - null, true, isRegexQuoteConstruction); + null, true, isRegexQuoteConstruction, hasXModifier, true); } else { - // Check if /x modifier is present - boolean hasXModifier = modifiers != null && modifiers.contains("x"); - String patternStr = rawStr.buffers.getFirst(); if (hasXModifier && mayInterpolateRegex(patternStr)) { // With /x modifier, strip comments before variable interpolation @@ -410,7 +428,8 @@ static Node parseRegexString(EmitterContext ctx, ParsedString rawStr, Parser par // interpolate variables, but ignore the escapes, keep `\$` if present // Pass shared heredoc nodes to handle heredocs inside regex patterns parsed = StringDoubleQuoted.parseDoubleQuotedString(ctx, rawStr, false, true, true, - parser != null ? parser.getHeredocNodes() : null, null, true, isRegexQuoteConstruction); + parser != null ? parser.getHeredocNodes() : null, null, true, + isRegexQuoteConstruction, hasXModifier); } return parsed; } @@ -620,11 +639,14 @@ public static OperatorNode parseRegexReplace(EmitterContext ctx, ParsedString ra elements.add(replace); elements.add(modifiers); ListNode list = new ListNode(elements, rawStr.index); + captureLexicalNamedCharacterTranslator(list, rawStr.index, ctx); OperatorNode node = new OperatorNode(operator, list, rawStr.index); node.setAnnotation("regexWarningsEnabled", ctx.symbolTable != null && ctx.symbolTable.isWarningCategoryEnabled("regexp")); node.setAnnotation("regexWarningsFatal", ctx.symbolTable != null && ctx.symbolTable.isFatalWarningCategory("regexp")); + node.setAnnotation("regexWarningsSuppressed", + ctx.symbolTable != null && ctx.symbolTable.isWarningCategoryDisabled("regexp")); node.setAnnotation("regexWarningBits", ctx.symbolTable == null ? null : ctx.symbolTable.getWarningBitsString()); return node; @@ -647,27 +669,119 @@ public static OperatorNode parseRegexMatch(EmitterContext ctx, String operator, modStr = addLexicalRegexContext(ctx, modStr); Node parsed = parseRegexString(ctx, rawStr, parser, modStr, isQuoteRegex); + List elements = new ArrayList<>(); + elements.add(parsed); + ListNode list = new ListNode(elements, rawStr.index); + captureLexicalNamedCharacterTranslator(list, rawStr.index, ctx); + parsed = elements.getFirst(); + boolean literalSyntaxValidated = false; + if (isQuoteRegex || list.getAnnotation( + LEXICAL_NAMED_CHARACTER_TRANSLATOR) instanceof RuntimeScalar) { + String literalSyntax = RegexLiteralAnalyzer.constantSyntaxString(parsed); + String literalSource = RegexLiteralAnalyzer.constantSourceString(parsed); + if (literalSyntax != null + && literalSource != null + && !RuntimeRegex.requiresRuntimeUnicodePropertyResolution(literalSyntax)) { + String validationModifiers = modStr; + if (ctx.symbolTable != null + && ctx.symbolTable.isFeatureCategoryEnabled("unicode_strings") + && !validationModifiers.contains("u")) { + validationModifiers += "u"; + } + try { + validateLiteralNamedCharacters(list, literalSyntax, + validationModifiers, literalSource); + literalSyntaxValidated = true; + } catch (PerlCompilerException exception) { + String message = exception.getMessage(); + throw PerlCompilerException.withSourceLocation( + rawStr.index, message, ctx.errorUtil); + } + } + } if (rawStr.startDelim == '?') { // `m?PAT?` matches exactly once // save the internal flag in the modifier string modStr += '?'; } Node modifiers = new StringNode(modStr, rawStr.index); - List elements = new ArrayList<>(); - elements.add(parsed); elements.add(modifiers); - ListNode list = new ListNode(elements, rawStr.index); OperatorNode node = new OperatorNode(operator, list, rawStr.index); + Object namedCharacterExpansions = list.getAnnotation( + LEXICAL_NAMED_CHARACTER_EXPANSIONS); + if (namedCharacterExpansions != null) { + node.setAnnotation(LEXICAL_NAMED_CHARACTER_EXPANSIONS, + namedCharacterExpansions); + } node.setAnnotation("syntacticQuoteRegex", isQuoteRegex); + node.setAnnotation("literalSyntaxValidated", literalSyntaxValidated); node.setAnnotation("regexWarningsEnabled", ctx.symbolTable != null && ctx.symbolTable.isWarningCategoryEnabled("regexp")); node.setAnnotation("regexWarningsFatal", ctx.symbolTable != null && ctx.symbolTable.isFatalWarningCategory("regexp")); + node.setAnnotation("regexWarningsSuppressed", + ctx.symbolTable != null && ctx.symbolTable.isWarningCategoryDisabled("regexp")); node.setAnnotation("regexWarningBits", ctx.symbolTable == null ? null : ctx.symbolTable.getWarningBitsString()); return node; } + static void captureLexicalNamedCharacterTranslator( + ListNode operand, int sourceTokenIndex, EmitterContext ctx) { + RuntimeScalar translator = HintHashRegistry.getCompileTimeHint("charnames"); + operand.setAnnotation(LEXICAL_NAMED_CHARACTER_SOURCE_MODE, + ctx.symbolTable != null + && ctx.symbolTable.isStrictOptionEnabled(HINT_UTF8) + ? NamedCharacterExpansion.SourceMode.UNICODE + : NamedCharacterExpansion.SourceMode.BYTE); + if (NamedCharacterExpansion.usesCustomTranslator(translator)) { + operand.setAnnotation(LEXICAL_NAMED_CHARACTER_TRANSLATOR, + new RuntimeScalar(translator)); + Node pattern = operand.elements.get(0); + String identity = RegexMarkers.literalIdentity( + NEXT_LEXICAL_REGEX_IDENTITY.incrementAndGet()); + operand.setAnnotation(LEXICAL_NAMED_CHARACTER_LITERAL_IDENTITY, + new NamedCharacterExpansionMap.LiteralIdentity(identity)); + operand.setAnnotation(LEXICAL_NAMED_CHARACTER_CALLABLE_IDENTITY, + new NamedCharacterExpansionMap.CallableIdentity(translator.toString())); + if (pattern instanceof StringNode string) { + operand.elements.set(0, new StringNode( + string.value + identity, string.isVString, + string.forceByteString, string.tokenIndex)); + } else { + operand.elements.set(0, new BinaryOperatorNode(".", pattern, + new StringNode(identity, sourceTokenIndex), sourceTokenIndex)); + } + } + } + + /** Validate a constant regex operand and retain any custom lexical results on its AST. */ + public static void validateLiteralNamedCharacters( + ListNode operand, String pattern, String modifiers, String diagnosticPattern) { + Object capturedTranslator = operand.getAnnotation( + LEXICAL_NAMED_CHARACTER_TRANSLATOR); + if (capturedTranslator instanceof RuntimeScalar translator) { + NamedCharacterExpansionMap expansions = + RuntimeRegex.validateLiteralSyntaxAndCapture( + pattern, modifiers, translator, + (NamedCharacterExpansion.SourceMode) operand.getAnnotation( + LEXICAL_NAMED_CHARACTER_SOURCE_MODE), + (NamedCharacterExpansionMap.LiteralIdentity) operand.getAnnotation( + LEXICAL_NAMED_CHARACTER_LITERAL_IDENTITY), + (NamedCharacterExpansionMap.CallableIdentity) operand.getAnnotation( + LEXICAL_NAMED_CHARACTER_CALLABLE_IDENTITY), + diagnosticPattern); + operand.setAnnotation(LEXICAL_NAMED_CHARACTER_EXPANSIONS, expansions); + } else { + RuntimeRegex.validateLiteralSyntax( + pattern, modifiers, + HintHashRegistry.getCompileTimeHint("charnames"), + (NamedCharacterExpansion.SourceMode) operand.getAnnotation( + LEXICAL_NAMED_CHARACTER_SOURCE_MODE), + diagnosticPattern); + } + } + /** * Carries lexical re-debug state through the existing flags operand. The * private markers are stripped before public modifier validation and never diff --git a/src/main/java/org/perlonjava/frontend/parser/StringSegmentParser.java b/src/main/java/org/perlonjava/frontend/parser/StringSegmentParser.java index 7686c5479d..db0bce340d 100644 --- a/src/main/java/org/perlonjava/frontend/parser/StringSegmentParser.java +++ b/src/main/java/org/perlonjava/frontend/parser/StringSegmentParser.java @@ -9,9 +9,12 @@ import org.perlonjava.runtime.operators.PerlUtfString; import org.perlonjava.runtime.HintHashRegistry; import org.perlonjava.runtime.NamedCharacterExpansion; +import org.perlonjava.runtime.regex.RegexMarkers; +import org.perlonjava.runtime.regex.RegexQuoteMeta; import org.perlonjava.runtime.runtimetypes.PerlCompilerException; import org.perlonjava.runtime.runtimetypes.PerlParserException; import org.perlonjava.runtime.runtimetypes.ScalarUtils; +import org.perlonjava.runtime.runtimetypes.WarningFlags; import java.math.BigInteger; import java.util.ArrayList; @@ -19,6 +22,7 @@ import static org.perlonjava.frontend.parser.ParseBlock.parseBlock; import static org.perlonjava.frontend.parser.Variable.parseArrayHashAccess; +import static org.perlonjava.runtime.perlmodule.Strict.HINT_RE_STRICT; import static org.perlonjava.runtime.perlmodule.Strict.HINT_UTF8; /** @@ -77,6 +81,12 @@ public abstract class StringSegmentParser { private boolean currentSegmentHasSourceNonAscii = false; private boolean inRegexCharClass = false; private boolean regexCharClassFirst = false; + private boolean regexCharClassEscape = false; + private boolean regexOutsideEscape = false; + private boolean inRegexComment = false; + private boolean regexCommentEscape = false; + private boolean inRegexLineComment = false; + private boolean regexExtended = false; /** * List of AST nodes representing string segments (literals and interpolated expressions) */ @@ -85,6 +95,7 @@ public abstract class StringSegmentParser { protected boolean hasRuntimeInterpolation; protected final boolean interpolateVariable; protected final boolean parseEscapes; + protected final boolean deferNamedCharacterDiagnosticsToRegex; /** * Original token offset for mapping string positions back to source */ @@ -109,6 +120,17 @@ public StringSegmentParser(EmitterContext ctx, List tokens, Parser p } public StringSegmentParser(EmitterContext ctx, List tokens, Parser parser, int tokenIndex, boolean isRegex, boolean parseEscapes, boolean interpolateVariable, boolean isRegexReplacement, boolean isRegexQuoteConstruction) { + this(ctx, tokens, parser, tokenIndex, isRegex, parseEscapes, + interpolateVariable, isRegexReplacement, + isRegexQuoteConstruction, false); + } + + public StringSegmentParser(EmitterContext ctx, List tokens, + Parser parser, int tokenIndex, boolean isRegex, + boolean parseEscapes, boolean interpolateVariable, + boolean isRegexReplacement, + boolean isRegexQuoteConstruction, + boolean deferNamedCharacterDiagnosticsToRegex) { this.ctx = ctx; this.tokens = tokens; this.parser = parser; @@ -120,6 +142,8 @@ public StringSegmentParser(EmitterContext ctx, List tokens, Parser p this.interpolateVariable = interpolateVariable; this.isRegexReplacement = isRegexReplacement; this.isRegexQuoteConstruction = isRegexQuoteConstruction; + this.deferNamedCharacterDiagnosticsToRegex = + deferNamedCharacterDiagnosticsToRegex; } /** @@ -158,23 +182,65 @@ protected boolean isInsideRegexCharClass() { * Subclasses may suppress them while parsing a quoting region such as {@code \Q...\E}. */ protected boolean regexCodeBlocksAreActive() { - return true; + return !inRegexCharClass && !inRegexComment && !inRegexLineComment; + } + + void setRegexExtended(boolean regexExtended) { + this.regexExtended = regexExtended; } private void updateRegexCharClassState(char c) { if (!isRegex) { return; } - if (c == '[' && !inRegexCharClass) { + if (inRegexLineComment) { + if (c == '\n') { + inRegexLineComment = false; + } + return; + } + if (inRegexComment) { + if (regexCommentEscape) { + regexCommentEscape = false; + } else if (c == '\\') { + regexCommentEscape = true; + } else if (c == ')') { + inRegexComment = false; + } + return; + } + if (inRegexCharClass) { + if (regexCharClassEscape) { + regexCharClassEscape = false; + if (regexCharClassFirst) { + regexCharClassFirst = false; + } + } else if (c == '\\') { + regexCharClassEscape = true; + } else if (c == ']' && !regexCharClassFirst) { + inRegexCharClass = false; + } else if (regexCharClassFirst && c != '^') { + regexCharClassFirst = false; + } + } else if (regexOutsideEscape) { + regexOutsideEscape = false; + } else if (c == '\\') { + regexOutsideEscape = true; + } else if (c == '[') { inRegexCharClass = true; regexCharClassFirst = true; - } else if (c == ']' && inRegexCharClass && !regexCharClassFirst) { - inRegexCharClass = false; - } else if (inRegexCharClass && regexCharClassFirst && c != '^') { - regexCharClassFirst = false; + } else if (c == '#' && regexExtended) { + inRegexLineComment = true; } } + private boolean startsRegexComment() { + int currentPos = parser.tokenIndex; + return currentPos + 1 < parser.tokens.size() + && "?".equals(parser.tokens.get(currentPos).text) + && "#".equals(parser.tokens.get(currentPos + 1).text); + } + /** * Adds a string segment node to the segments list. * @@ -798,6 +864,9 @@ public Node parse() { * @return true if the token was handled specially, false if it should be treated as literal text */ protected boolean handleSpecialToken(String text) { + if (isRegex && (inRegexComment || inRegexLineComment)) { + return false; + } return switch (text) { case "\\" -> { parseEscapeSequence(); @@ -811,6 +880,10 @@ protected boolean handleSpecialToken(String text) { yield false; } case "(" -> { + if (isRegex && regexCodeBlocksAreActive() && startsRegexComment()) { + inRegexComment = true; + yield false; + } // Check for (?{...}) and (??{...}) regex code blocks - only in regex context if (isRegex && regexCodeBlocksAreActive() && isRegexCallbackCondition()) { parseRegexCallbackCondition(); @@ -935,7 +1008,7 @@ private boolean isRegexRecursiveBlock() { * real-world use cases, with pack.t and most Perl code using literal patterns.

* *

Future enhancement: To support interpolated patterns, this processing would need to be - * moved to RegexPreprocessor.preProcessRegex() which sees the final pattern string regardless + * moved to native regex compilation, which sees the final pattern string regardless * of how it was constructed.

* *

Only called when isRegex=true.

@@ -957,21 +1030,87 @@ private void parseRegexCodeBlock(boolean isRecursive) { // Consume the "{" token TokenUtils.consume(parser, LexerTokenType.OPERATOR, "{"); - - // Parse the block content using the Block parser - this handles heredocs properly - Node block = parseBlock(parser); - - // Consume the closing "}" - TokenUtils.consume(parser, LexerTokenType.OPERATOR, "}"); - - // Consume the closing ")" that completes the (?{...}) construct - TokenUtils.consume(parser, LexerTokenType.OPERATOR, ")"); + int codeBodyStart = parser.tokenIndex; + Node block; + try { + // Parse the block content using the Block parser - this handles heredocs properly + block = parseBlock(parser); + + // Consume the closing "}" + TokenUtils.consume(parser, LexerTokenType.OPERATOR, "}"); + + // Consume the closing ")" that completes the (?{...}) construct + TokenUtils.consume(parser, LexerTokenType.OPERATOR, ")"); + } catch (RuntimeException original) { + int closingBrace = findRegexCodeBlockClosingBrace(codeBodyStart); + if (closingBrace < 0) { + int failureIndex = Whitespace.skipWhitespace( + parser, parser.tokenIndex, parser.tokens); + if (failureIndex >= parser.tokens.size() + || parser.tokens.get(failureIndex).type == LexerTokenType.EOF) { + throw PerlCompilerException.withSourceLocation( + savedTokenIndex, + "Missing right curly or square bracket", + ctx.errorUtil); + } + // Perl reports an earlier expression syntax error before the + // structural EOF diagnostic when the callback parser stopped + // on a concrete bad token (for example `(?{(^{})`). + throw original; + } + int afterBrace = Whitespace.skipWhitespace( + parser, closingBrace + 1, parser.tokens); + if (afterBrace >= parser.tokens.size() + || !")".equals(parser.tokens.get(afterBrace).text)) { + throw PerlCompilerException.withSourceLocation( + savedTokenIndex, + "Sequence (?{...}) not terminated with ')'", + ctx.errorUtil); + } + throw original; + } String kind = isRecursive ? "DYNAMIC" : "BLOCK"; segments.add(regexCallback(block, kind, savedTokenIndex, sourceLine, "(" + regexSourceTokens(callbackSourceStart, parser.tokenIndex))); } + /** + * Finds the structural brace that closes a Perl regex callback. Braces in + * ordinary quoted strings do not affect callback depth. This scanner is + * used only after the full Perl block parser rejects the source, so valid + * heredocs and quote-like operators continue to be owned by that parser. + */ + private int findRegexCodeBlockClosingBrace(int codeBodyStart) { + int depth = 1; + String quote = null; + for (int i = codeBodyStart; i < parser.tokens.size(); i++) { + LexerToken token = parser.tokens.get(i); + if (token.type == LexerTokenType.EOF) { + return -1; + } + String text = token.text; + if ("\\".equals(text) && i + 1 < parser.tokens.size()) { + i++; + continue; + } + if (quote != null) { + if (quote.equals(text)) { + quote = null; + } + continue; + } + if ("'".equals(text) || "\"".equals(text)) { + quote = text; + } else if ("{".equals(text)) { + depth++; + } else if ("}".equals(text) && --depth == 0) { + return i; + } + } + return -1; + } + private String regexSourceTokens(int start, int end) { StringBuilder source = new StringBuilder(); for (int i = start; i < end && i < parser.tokens.size(); i++) { @@ -1000,6 +1139,12 @@ private Node regexCallback(Node block, String kind, int index, int sourceLine, callback.setAnnotation("regexCallbackPackage", closure.getAnnotation("regexCallbackPackage")); callback.setAnnotation("regexCallbackSource", source); + String callbackWarningBits = RegexQuoteMeta.getParserWarningBits(); + if (callbackWarningBits == null) { + callbackWarningBits = parser.ctx.symbolTable.getWarningBitsString(); + } + callback.setAnnotation("regexCallbackUninitializedWarningsEnabled", + WarningFlags.isEnabledInBits(callbackWarningBits, "uninitialized")); hasExecutableRegexCallbacks = true; return callback; } @@ -1265,29 +1410,38 @@ private boolean isNonInterpolatingCharacter(String text) { /** * Handles control character escape sequences like \cA, \cZ. * - *

Control characters are represented as \c followed by a letter. - * The letter is converted to its corresponding control character: + *

Control characters are represented as \c followed by one printable + * ASCII character. The operand is uppercased and XORed with {@code 0x40}: *

    *
  • \cA becomes ASCII 1 (Ctrl-A)
  • *
  • \cZ becomes ASCII 26 (Ctrl-Z)
  • - *
  • Both uppercase and lowercase letters are supported
  • + *
  • \c# becomes {@code c}
  • + *
  • \c? becomes DEL
  • *

* - *

If the character following \c is not a letter, it's used as-is.

+ *

Perl reserves \c{ and reports a dedicated compile-time diagnostic.

*/ void handleControlCharacter() { var controlChar = TokenUtils.consumeChar(parser); + appendToCurrentSegment(controlCharacterValue(controlChar)); + } + + protected String controlCharacterValue(String controlChar) { if (controlChar.isEmpty()) { throw new PerlCompilerException(parser.tokenIndex, "Missing control char name in \\c", parser.ctx.errorUtil); } var c = controlChar.charAt(0); - var result = (c >= 'A' && c <= 'Z') ? String.valueOf((char) (c - 'A' + 1)) - : (c >= 'a' && c <= 'z') ? String.valueOf((char) (c - 'a' + 1)) - : c == '@' ? String.valueOf((char) 0) - : (c >= '[' && c <= '_') ? String.valueOf((char) (c - '[' + 27)) - : c == '?' ? String.valueOf((char) 127) - : String.valueOf(c); - appendToCurrentSegment(result); + if (c == '{') { + throw new PerlCompilerException(parser.tokenIndex, + "Use \";\" instead of \"\\c{\"", parser.ctx.errorUtil); + } + if (c < 0x20 || c > 0x7e) { + return String.valueOf(c); + } + if (c >= 'a' && c <= 'z') { + c = (char) (c - ('a' - 'A')); + } + return String.valueOf((char) (c ^ 0x40)); } /** @@ -1499,6 +1653,11 @@ void handleUnicodeNameEscape() { if ("}".equals(chr)) { TokenUtils.consumeChar(parser); // consume '}' var name = nameBuilder.toString(); + if (isRegex && deferNamedCharacterDiagnosticsToRegex + && !name.regionMatches(true, 0, "U+", 0, 2)) { + appendToCurrentSegment("\\N{" + name + "}"); + return; + } if (isRegex && isPlainNonNewlineInterval(name)) { // A brace immediately following plain \N can be its quantifier, // not a named character. Leave both pieces for the regex lexer. @@ -1518,14 +1677,15 @@ void handleUnicodeNameEscape() { // any following capture groups disappear from the pattern. boolean customTranslator = NamedCharacterExpansion.usesCustomTranslator( HintHashRegistry.getCompileTimeHint("charnames")); - if (!customTranslator || currentSegment.toString().endsWith("(?[")) { + if (!customTranslator) { NamedCharacterExpansion expansion = NamedCharacterExpansion.resolve(name, sourceMode); - if (isIncompleteExtendedClassNamedSequence(expansion)) { + if (namedSequenceRequiresSingleCharacter(expansion)) { throwNamedSequenceExtendedClassDiagnostic(expansion.sequence()); } if (!expansion.resolved()) { - throwNamedCharacterDiagnostic(expansion.diagnostic()); + appendToCurrentSegment(RegexMarkers.literalDiagnostic( + namedCharacterDiagnostic(expansion.diagnostic()))); } } appendToCurrentSegment("\\N{" + name + "}"); @@ -1548,15 +1708,20 @@ void handleUnicodeNameEscape() { } private boolean isPlainNonNewlineInterval(String contents) { - return contents.matches("(?:[0-9]+(?:,[0-9]*)?|,[0-9]+)"); + return contents.replaceAll("\\s+", "") + .matches("(?:[0-9]+(?:,[0-9]*)?|,[0-9]+)"); } private void throwNamedCharacterDiagnostic(String diagnostic) { + throw new PerlParserException(namedCharacterDiagnostic(diagnostic) + "\n"); + } + + private String namedCharacterDiagnostic(String diagnostic) { int errorIndex = this.tokenIndex; var location = ctx.errorUtil.getSourceLocationAccurate(errorIndex); - throw new PerlParserException(diagnostic + return diagnostic + " at " + location.fileName() + " line " + location.lineNumber() - + ", within " + (isRegex ? "pattern" : "string") + "\n"); + + ", within " + (isRegex ? "pattern" : "string"); } private void throwMissingNamedCharacterBraceDiagnostic() { @@ -1569,10 +1734,89 @@ private void throwMissingNamedCharacterBraceDiagnostic() { + ", within " + (isRegex ? "pattern" : "string") + "\n"); } - private boolean isIncompleteExtendedClassNamedSequence( + private boolean namedSequenceRequiresSingleCharacter( NamedCharacterExpansion expansion) { - return expansion.sequence().codePointCount(0, expansion.sequence().length()) > 1 - && currentSegment.toString().endsWith("(?["); + if (expansion.sequence().codePointCount(0, expansion.sequence().length()) <= 1) { + return false; + } + if (isInsideExtendedCharacterClass()) { + return true; + } + if (!ctx.symbolTable.isStrictOptionEnabled(HINT_RE_STRICT)) { + return false; + } + int classStart = activeOrdinaryCharacterClassStart(); + if (classStart < 0) { + return false; + } + String classPrefix = currentSegment.substring(classStart + 1); + return classPrefix.startsWith("^") + || endsWithUnescapedHyphen(currentSegment) + || "-".equals(TokenUtils.peekChar(parser)); + } + + private boolean isInsideExtendedCharacterClass() { + return scanRegexClassContext().extendedDepth() > 0; + } + + private int activeOrdinaryCharacterClassStart() { + return scanRegexClassContext().ordinaryClassStart(); + } + + private RegexClassContext scanRegexClassContext() { + String source = currentSegment.toString(); + int extendedDepth = 0; + int ordinaryClassStart = -1; + boolean escaped = false; + for (int i = 0; i < source.length(); i++) { + char c = source.charAt(i); + if (escaped) { + escaped = false; + continue; + } + if (c == '\\') { + escaped = true; + continue; + } + if (ordinaryClassStart >= 0) { + if (c == ']') { + ordinaryClassStart = -1; + } + continue; + } + if (i + 2 < source.length() + && c == '(' && source.charAt(i + 1) == '?' + && source.charAt(i + 2) == '[') { + extendedDepth++; + i += 2; + continue; + } + if (extendedDepth > 0 && c == ']' + && i + 1 < source.length() && source.charAt(i + 1) == ')') { + extendedDepth--; + i++; + continue; + } + if (c == '[') { + ordinaryClassStart = i; + } + } + return new RegexClassContext(extendedDepth, ordinaryClassStart); + } + + private boolean endsWithUnescapedHyphen(CharSequence source) { + int end = source.length() - 1; + if (end < 0 || source.charAt(end) != '-') { + return false; + } + int backslashes = 0; + for (int i = end - 1; i >= 0 && source.charAt(i) == '\\'; i--) { + backslashes++; + } + return (backslashes & 1) == 0; + } + + private record RegexClassContext(int extendedDepth, int ordinaryClassStart) { } private String namedSequenceExtendedClassDiagnostic(String sequence) { @@ -1583,7 +1827,20 @@ private String namedSequenceExtendedClassDiagnostic(String sequence) { }); return "\\N{} here is restricted to one character in regex; " + "marked by <-- HERE in m/" + currentSegment - + "\\N{U+" + canonical + " <-- HERE }/"; + + "\\N{U+" + canonical + " <-- HERE }" + + remainingRegexSource() + "/"; + } + + private String remainingRegexSource() { + StringBuilder remaining = new StringBuilder(); + for (int i = parser.tokenIndex; i < parser.tokens.size(); i++) { + LexerToken token = parser.tokens.get(i); + if (token.type == LexerTokenType.EOF) { + break; + } + remaining.append(token.text); + } + return remaining.toString(); } private void throwNamedSequenceExtendedClassDiagnostic(String sequence) { diff --git a/src/main/java/org/perlonjava/frontend/parser/SubroutineParser.java b/src/main/java/org/perlonjava/frontend/parser/SubroutineParser.java index fd54f733ad..d48dcc126d 100644 --- a/src/main/java/org/perlonjava/frontend/parser/SubroutineParser.java +++ b/src/main/java/org/perlonjava/frontend/parser/SubroutineParser.java @@ -1466,9 +1466,11 @@ public static ListNode handleNamedSubWithFilter(Parser parser, String subName, S placeholder.ourVariableRegistry = declaredOurVarMap.isEmpty() ? null : declaredOurVarMap; explicitlyUsedVars = usedVarSet; - if (!collector.hasEvalString()) { + if (!collector.requiresAllRuntimeLexicals()) { usedVars = usedVarSet; } + placeholder.tracksRuntimeRegexLexicals = + collector.requiresAllRuntimeLexicals(); } ArrayList classList = new ArrayList<>(); diff --git a/src/main/java/org/perlonjava/frontend/semantic/ScopedSymbolTable.java b/src/main/java/org/perlonjava/frontend/semantic/ScopedSymbolTable.java index 7cae9c63fb..03e3eb29a6 100644 --- a/src/main/java/org/perlonjava/frontend/semantic/ScopedSymbolTable.java +++ b/src/main/java/org/perlonjava/frontend/semantic/ScopedSymbolTable.java @@ -907,6 +907,10 @@ public void disableWarningCategory(String category) { Integer bitPosition = warningBitPositions.get(category); if (bitPosition != null) { warningFlagsStack.peek().clear(bitPosition); + // A disabled category cannot remain fatal. Keeping the fatal bit + // made warning-mask serialization re-enable the category when an + // eval STRING inherited its caller's lexical warning state. + warningFatalStack.peek().clear(bitPosition); // Mark as explicitly disabled (for proper $^W interaction) warningDisabledStack.peek().set(bitPosition); } diff --git a/src/main/java/org/perlonjava/runtime/NamedCharacterExpansionMap.java b/src/main/java/org/perlonjava/runtime/NamedCharacterExpansionMap.java new file mode 100644 index 0000000000..0cecfaa6fe --- /dev/null +++ b/src/main/java/org/perlonjava/runtime/NamedCharacterExpansionMap.java @@ -0,0 +1,68 @@ +package org.perlonjava.runtime; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Immutable lexical results for the named-character escapes in one regex literal. + * + *

The parser attaches this value to the literal AST after executing a custom + * {@code %^H{charnames}} translator. Backends carry the same typed value into + * the compiled CV, allowing an ithread child to compile the literal without + * executing or sharing the parent's lexical callable.

+ */ +public record NamedCharacterExpansionMap( + LiteralIdentity literalIdentity, + CallableIdentity callableIdentity, + Map expansions) { + + public record LiteralIdentity(String value) {} + + public record CallableIdentity(String value) {} + + public record Key( + String sourceSpelling, + NamedCharacterExpansion.SourceMode sourceMode) {} + + public NamedCharacterExpansionMap { + expansions = Collections.unmodifiableMap(new LinkedHashMap<>(expansions)); + } + + public NamedCharacterExpansion get( + String sourceSpelling, NamedCharacterExpansion.SourceMode sourceMode) { + return expansions.get(new Key(sourceSpelling, sourceMode)); + } + + public boolean isEmpty() { + return expansions.isEmpty(); + } + + /** Lexical source mode captured before literal scalar materialization. */ + public NamedCharacterExpansion.SourceMode sourceMode() { + return expansions.isEmpty() ? null + : expansions.keySet().iterator().next().sourceMode(); + } + + /** Rebuild a typed value from constants carried by generated JVM bytecode. */ + public static NamedCharacterExpansionMap fromFlat( + String literalIdentity, String callableIdentity, String[] flat) { + if (flat.length % 7 != 0) { + throw new IllegalArgumentException("invalid named-character metadata"); + } + Map entries = new LinkedHashMap<>(); + for (int index = 0; index < flat.length; index += 7) { + NamedCharacterExpansion.SourceMode keyMode = + NamedCharacterExpansion.SourceMode.valueOf(flat[index + 1]); + entries.put(new Key(flat[index], keyMode), new NamedCharacterExpansion( + flat[index + 2], + NamedCharacterExpansion.SourceMode.valueOf(flat[index + 3]), + Boolean.parseBoolean(flat[index + 4]), + NamedCharacterExpansion.Status.valueOf(flat[index + 5]), + flat[index + 6])); + } + return new NamedCharacterExpansionMap( + new LiteralIdentity(literalIdentity), + new CallableIdentity(callableIdentity), entries); + } +} diff --git a/src/main/java/org/perlonjava/runtime/operators/FileTestOperator.java b/src/main/java/org/perlonjava/runtime/operators/FileTestOperator.java index a115a18f3c..e4bc1458b4 100644 --- a/src/main/java/org/perlonjava/runtime/operators/FileTestOperator.java +++ b/src/main/java/org/perlonjava/runtime/operators/FileTestOperator.java @@ -688,6 +688,13 @@ public static RuntimeScalar fileTest(String operator, RuntimeScalar fileHandle) yield scalarUndef; } getGlobalVariable("main::!").set(0); // Clear error + if (isPerlOnJavaExecutable(path)) { + // $^X names the logical interpreter executable. The + // development/package launcher may be a text script, + // but Perl's file-test contract observes the active + // interpreter as a binary executable. + yield getScalarBoolean(operator.equals("-B")); + } yield isTextOrBinary(path, operator.equals("-T")); } case "-M", "-A", "-C" -> { @@ -797,6 +804,17 @@ private static RuntimeScalar isTextOrBinary(Path path, boolean checkForText) thr return analyzeTextBinary(buffer, bytesRead, checkForText); } + private static boolean isPerlOnJavaExecutable(Path path) { + String executable = System.getenv("PERLONJAVA_EXECUTABLE"); + if (executable == null || executable.isEmpty()) return false; + try { + Path executablePath = Path.of(executable); + return Files.exists(executablePath) && Files.isSameFile(path, executablePath); + } catch (IOException | InvalidPathException exception) { + return false; + } + } + /** * Determines if a filehandle's content from the current position is text or binary. * Used for -T/-B on filehandles where we need to read from the current position, diff --git a/src/main/java/org/perlonjava/runtime/operators/PerlUtfString.java b/src/main/java/org/perlonjava/runtime/operators/PerlUtfString.java index 47839cd661..3bf15104f0 100644 --- a/src/main/java/org/perlonjava/runtime/operators/PerlUtfString.java +++ b/src/main/java/org/perlonjava/runtime/operators/PerlUtfString.java @@ -147,6 +147,22 @@ public static int nextJavaBoundary(String s, int javaIndex) { return readOnePerlLogical(s, javaIndex).nextJavaIndex(); } + /** Java UTF-16 index where the final Perl logical character begins. */ + public static int lastLogicalCharacterStart(String s) { + if (s.isEmpty()) return 0; + PerlIndexMap indexMap = cachedIndexMap(s); + if (indexMap != null) { + return indexMap.javaBoundaries[indexMap.javaBoundaries.length - 2]; + } + int previous = 0; + int current = 0; + while (current < s.length()) { + previous = current; + current = readOnePerlLogical(s, current).nextJavaIndex(); + } + return previous; + } + public static int offsetByPerlCodePoints(String s, int startJava, int perlOffset) { if (perlOffset <= 0) { return startJava; diff --git a/src/main/java/org/perlonjava/runtime/operators/StringOperators.java b/src/main/java/org/perlonjava/runtime/operators/StringOperators.java index ded787298c..097a35b1a0 100644 --- a/src/main/java/org/perlonjava/runtime/operators/StringOperators.java +++ b/src/main/java/org/perlonjava/runtime/operators/StringOperators.java @@ -549,7 +549,11 @@ private static RuntimeScalar stringConcat(RuntimeScalar runtimeScalar, RuntimeSc // enclosing call site was compiled, so retain a cheap undef-only // runtime guard here as well. WarnDie performs the lexical category // check and dispatches a localized __WARN__ handler when applicable. - if (warnUninitialized + String callSiteWarningBits = WarningBitsRegistry.getCallSiteBits(); + boolean callSiteWarnsUninitialized = callSiteWarningBits == null + || WarningFlags.areWarningsForcedOn() + || WarningFlags.isEnabledInBits(callSiteWarningBits, "uninitialized"); + if (warnUninitialized && callSiteWarnsUninitialized && (!aResolved.getDefinedBoolean() || !bResolved.getDefinedBoolean())) { WarnDie.warnWithCategory( new RuntimeScalar("Use of uninitialized value in concatenation (.)"), @@ -742,12 +746,9 @@ public static RuntimeScalar chopScalar(RuntimeScalar runtimeScalar) { return new RuntimeScalar(); } - // Handle Unicode properly by using code points instead of char units - int lastCodePoint = str.codePointBefore(str.length()); - int lastCharSize = Character.charCount(lastCodePoint); - - String lastChar = str.substring(str.length() - lastCharSize); - String remainingStr = str.substring(0, str.length() - lastCharSize); + int lastStart = PerlUtfString.lastLogicalCharacterStart(str); + String lastChar = str.substring(lastStart); + String remainingStr = str.substring(0, lastStart); boolean wasByteString = runtimeScalar.type == RuntimeScalarType.BYTE_STRING; runtimeScalar.set(remainingStr); diff --git a/src/main/java/org/perlonjava/runtime/operators/SystemOperator.java b/src/main/java/org/perlonjava/runtime/operators/SystemOperator.java index d89533a30f..2c7d531208 100644 --- a/src/main/java/org/perlonjava/runtime/operators/SystemOperator.java +++ b/src/main/java/org/perlonjava/runtime/operators/SystemOperator.java @@ -45,59 +45,9 @@ public class SystemOperator { private static final Pattern TAINTED_ENV_METACHARACTERS = Pattern.compile("[^A-Za-z0-9_./-]"); private static String decodeSubprocessOutput(byte[] bytes) { - StringBuilder decoded = new StringBuilder(bytes.length); - for (int i = 0; i < bytes.length; ) { - int first = bytes[i] & 0xff; - if (first < 0x80) { - decoded.append((char) first); - i++; - continue; - } - - int length; - int codePoint; - if (first >= 0xc2 && first <= 0xdf) { - length = 2; - codePoint = first & 0x1f; - } else if (first >= 0xe0 && first <= 0xef) { - length = 3; - codePoint = first & 0x0f; - } else if (first >= 0xf0 && first <= 0xf4) { - length = 4; - codePoint = first & 0x07; - } else { - decoded.append((char) first); - i++; - continue; - } - - boolean valid = i + length <= bytes.length; - for (int j = 1; valid && j < length; j++) { - int continuation = bytes[i + j] & 0xff; - valid = (continuation & 0xc0) == 0x80; - if (valid) codePoint = (codePoint << 6) | (continuation & 0x3f); - } - if (valid && length == 3) { - int second = bytes[i + 1] & 0xff; - valid = (first != 0xe0 || second >= 0xa0) - && (first != 0xed || second <= 0x9f); - } else if (valid && length == 4) { - int second = bytes[i + 1] & 0xff; - valid = (first != 0xf0 || second >= 0x90) - && (first != 0xf4 || second <= 0x8f); - } - - if (valid) { - decoded.appendCodePoint(codePoint); - i += length; - } else { - // Preserve an invalid octet one-for-one instead of replacing - // it with U+FFFD, so qx// remains binary-safe. - decoded.append((char) first); - i++; - } - } - return decoded.toString(); + // qx// has no implicit decoding layer: Perl returns subprocess stdout + // as an SvUTF8-off byte string even when the octets form valid UTF-8. + return new String(bytes, StandardCharsets.ISO_8859_1); } /** @@ -1054,25 +1004,30 @@ private static RuntimeBase processOutput(String output, int ctx) { int separatorLength = separator.length(); if (separatorLength == 0) { - result.add(new RuntimeScalar(output).taintFromExternalInput()); + result.add(subprocessOutputScalar(output)); } else { while (index < output.length()) { int nextIndex = output.indexOf(separator, index); if (nextIndex == -1) { - result.add(new RuntimeScalar(output.substring(index)).taintFromExternalInput()); + result.add(subprocessOutputScalar(output.substring(index))); break; } - result.add(new RuntimeScalar(output.substring(index, nextIndex + separatorLength)) - .taintFromExternalInput()); + result.add(subprocessOutputScalar( + output.substring(index, nextIndex + separatorLength))); index = nextIndex + separatorLength; } } return list; } else { - return new RuntimeScalar(output).taintFromExternalInput(); + return subprocessOutputScalar(output); } } + private static RuntimeScalar subprocessOutputScalar(String output) { + return new RuntimeScalar(output.getBytes(StandardCharsets.ISO_8859_1)) + .taintFromExternalInput(); + } + /** * Executes a command and attempts to replace the current process. * This implements Perl's exec() function. diff --git a/src/main/java/org/perlonjava/runtime/operators/TieOperators.java b/src/main/java/org/perlonjava/runtime/operators/TieOperators.java index 43782a17d2..923a1966e9 100644 --- a/src/main/java/org/perlonjava/runtime/operators/TieOperators.java +++ b/src/main/java/org/perlonjava/runtime/operators/TieOperators.java @@ -2,6 +2,7 @@ import org.perlonjava.runtime.mro.InheritanceResolver; import org.perlonjava.runtime.runtimetypes.*; +import org.perlonjava.runtime.perlmodule.TieHashNamedCapture; import java.util.Arrays; @@ -284,6 +285,10 @@ public static RuntimeScalar tied(int ctx, RuntimeBase... scalars) { } case HASHREFERENCE -> { RuntimeHash hash = variable.hashDeref(); + if (hash.elements instanceof HashSpecialVariable special + && special.captureMode() != null) { + return TieHashNamedCapture.tiedObject(special.captureMode()); + } if (hash.type == TIED_HASH && hash.elements instanceof TieHash) { return ((TieHash) hash.elements).getSelf(); } diff --git a/src/main/java/org/perlonjava/runtime/perlmodule/Re.java b/src/main/java/org/perlonjava/runtime/perlmodule/Re.java index 3ea47f5096..9e22438afb 100644 --- a/src/main/java/org/perlonjava/runtime/perlmodule/Re.java +++ b/src/main/java/org/perlonjava/runtime/perlmodule/Re.java @@ -5,6 +5,7 @@ import org.perlonjava.runtime.runtimetypes.RuntimeArray; import org.perlonjava.runtime.runtimetypes.RuntimeCode; import org.perlonjava.runtime.runtimetypes.RuntimeContextType; +import org.perlonjava.runtime.runtimetypes.RuntimeHash; import org.perlonjava.runtime.runtimetypes.RuntimeList; import org.perlonjava.runtime.runtimetypes.RuntimeScalar; import org.perlonjava.runtime.runtimetypes.RuntimeScalarType; @@ -26,6 +27,7 @@ *
  • {@code use re 'debugcolor'} - Enables colorized lexical regex tracing
  • *
  • {@code re::is_regexp($ref)} - Check if reference is a compiled regex
  • *
  • {@code re::regexp_pattern($ref)} - Return pattern and modifiers from qr//
  • + *
  • {@code re::optimization($ref)} - Inspect optimizer-selected regex facts
  • * * *

    TODO: Features not yet implemented (see {@code perldoc re}): @@ -77,6 +79,7 @@ public static void initialize() { try { re.registerMethod("is_regexp", "isRegexp", "$"); re.registerMethod("regexp_pattern", "regexpPattern", "$"); + re.registerMethod("optimization", "optimization", "$"); re.registerMethod("import", "importRe", null); re.registerMethod("unimport", "unimportRe", null); } catch (NoSuchMethodException e) { @@ -153,6 +156,66 @@ public static RuntimeList regexpPattern(RuntimeArray args, int ctx) { } } + /** Implements re::optimization($regex) using facts selected by Joni itself. */ + public static RuntimeList optimization(RuntimeArray args, int ctx) { + if (args.size() != 1) { + throw new IllegalStateException("Bad number of arguments for optimization() method"); + } + + RuntimeScalar arg = args.get(0); + if (arg.type == RuntimeScalarType.REFERENCE && arg.value instanceof RuntimeScalar deref) { + arg = deref; + } + if (arg.type != RuntimeScalarType.REGEX) { + return new RuntimeList(RuntimeScalar.undef()); + } + + RuntimeRegex regex = (RuntimeRegex) arg.value; + org.joni.Regex.OptimizationInfo info = regex.getOptimizationInfo(); + if (info == null) { + return new RuntimeList(RuntimeScalar.undef()); + } + + RuntimeHash result = new RuntimeHash(); + result.put("minlen", new RuntimeScalar(info.minimumLength())); + result.put("minlenret", new RuntimeScalar(info.minimumLength())); + result.put("gofs", new RuntimeScalar(0)); + result.put("noscan", perlBoolean( + info.beginBufferAnchored() || info.beginPositionAnchored())); + result.put("isall", perlBoolean(false)); + result.put("skip", perlBoolean(false)); + result.put("implicit", perlBoolean( + info.implicitSingleLineAnchor() || info.implicitMultiLineAnchor())); + result.put("anchor SBOL", perlBoolean(info.implicitMultiLineAnchor())); + result.put("anchor MBOL", perlBoolean(info.implicitSingleLineAnchor())); + result.put("anchor GPOS", perlBoolean(info.beginPositionAnchored())); + result.put("joni search", new RuntimeScalar(info.searchAlgorithm())); + + String exact = info.exact(); + if (exact == null) { + result.put("checking", new RuntimeScalar("none")); + } else { + boolean anchored = info.minimumOffset() == 0 + && info.maximumOffset() != null && info.maximumOffset() == 0; + String kind = anchored ? "anchored" : "floating"; + result.put(kind, new RuntimeScalar(exact)); + result.put(kind + " min offset", new RuntimeScalar(info.minimumOffset())); + if (info.maximumOffset() != null) { + result.put(kind + " max offset", new RuntimeScalar(info.maximumOffset())); + } + result.put("checking", new RuntimeScalar(kind)); + boolean isAll = anchored && info.minimumOffset() == 0 + && info.exactReachEnd() && !info.hasCaptures() + && exact.codePointCount(0, exact.length()) == info.minimumLength(); + result.put("isall", perlBoolean(isAll)); + } + return new RuntimeList(result.createReferenceWithTrackedElements()); + } + + private static RuntimeScalar perlBoolean(boolean value) { + return new RuntimeScalar(value ? 1 : 0); + } + /** * Handle `use re ...` import. Recognizes: 'strict', 'eval', '/a', '/u', '/aa'. * Enables appropriate experimental warning categories so our regex preprocessor can emit them. @@ -190,9 +253,9 @@ public static RuntimeList importRe(RuntimeArray args, int ctx) { symbolTable.enableStrictOption(Strict.HINT_RE_EVAL); } else if (opt.equalsIgnoreCase("taint")) { symbolTable.enableStrictOption(Strict.HINT_RE_TAINT); - } else if (opt.equals("debug")) { + } else if (opt.equalsIgnoreCase("debug")) { symbolTable.enableStrictOption(Strict.HINT_RE_DEBUG); - } else if (opt.equals("debugcolor")) { + } else if (opt.equalsIgnoreCase("debugcolor")) { symbolTable.enableStrictOption(Strict.HINT_RE_DEBUG | Strict.HINT_RE_DEBUGCOLOR); } else if (opt.equals("/a")) { // use re '/a' - ASCII-restrict regex character classes @@ -236,9 +299,9 @@ public static RuntimeList unimportRe(RuntimeArray args, int ctx) { symbolTable.disableStrictOption(Strict.HINT_RE_EVAL); } else if (opt.equalsIgnoreCase("taint")) { symbolTable.disableStrictOption(Strict.HINT_RE_TAINT); - } else if (opt.equals("debug")) { + } else if (opt.equalsIgnoreCase("debug")) { symbolTable.disableStrictOption(Strict.HINT_RE_DEBUG | Strict.HINT_RE_DEBUGCOLOR); - } else if (opt.equals("debugcolor")) { + } else if (opt.equalsIgnoreCase("debugcolor")) { symbolTable.disableStrictOption(Strict.HINT_RE_DEBUGCOLOR); } else if (opt.equals("/a") || opt.equals("/aa")) { symbolTable.disableStrictOption(Strict.HINT_RE_ASCII | Strict.HINT_RE_ASCII_AA); diff --git a/src/main/java/org/perlonjava/runtime/perlmodule/TieHashNamedCapture.java b/src/main/java/org/perlonjava/runtime/perlmodule/TieHashNamedCapture.java new file mode 100644 index 0000000000..fa0c34c8a7 --- /dev/null +++ b/src/main/java/org/perlonjava/runtime/perlmodule/TieHashNamedCapture.java @@ -0,0 +1,131 @@ +package org.perlonjava.runtime.perlmodule; + +import org.perlonjava.runtime.operators.ReferenceOperators; +import org.perlonjava.runtime.runtimetypes.HashSpecialVariable; +import org.perlonjava.runtime.runtimetypes.GlobalVariable; +import org.perlonjava.runtime.runtimetypes.PerlCompilerException; +import org.perlonjava.runtime.runtimetypes.RuntimeArray; +import org.perlonjava.runtime.runtimetypes.RuntimeHash; +import org.perlonjava.runtime.runtimetypes.RuntimeList; +import org.perlonjava.runtime.runtimetypes.RuntimeScalar; +import org.perlonjava.runtime.runtimetypes.RuntimeScalarType; + +import java.util.ArrayList; +import java.util.List; + +/** Native implementation of Perl's built-in Tie::Hash::NamedCapture API. */ +public final class TieHashNamedCapture extends PerlModuleBase { + private static final int CAPTURE = 256; + private static final int CAPTURE_ALL = 512; + + private TieHashNamedCapture() { + super("Tie::Hash::NamedCapture", false); + } + + public static void initialize() { + TieHashNamedCapture module = new TieHashNamedCapture(); + try { + module.registerMethod("FETCH", null); + module.registerMethod("STORE", null); + module.registerMethod("DELETE", null); + module.registerMethod("CLEAR", null); + module.registerMethod("EXISTS", null); + module.registerMethod("FIRSTKEY", null); + module.registerMethod("NEXTKEY", null); + module.registerMethod("SCALAR", null); + } catch (NoSuchMethodException e) { + throw new IllegalStateException("Cannot register Tie::Hash::NamedCapture", e); + } + } + + public static RuntimeScalar tiedObject(HashSpecialVariable.Id mode) { + int value = mode == HashSpecialVariable.Id.CAPTURE_ALL ? CAPTURE_ALL : CAPTURE; + RuntimeScalar reference = new RuntimeScalar(value).createReference(); + ReferenceOperators.bless(reference, new RuntimeScalar("Tie::Hash::NamedCapture")); + return reference; + } + + private static HashSpecialVariable.Id mode(RuntimeScalar self) { + if (self == null || self.type == RuntimeScalarType.UNDEF) return null; + RuntimeScalar value = self; + if (value.type == RuntimeScalarType.REFERENCE) value = value.scalarDeref(); + return value.getInt() == CAPTURE_ALL + ? HashSpecialVariable.Id.CAPTURE_ALL + : HashSpecialVariable.Id.CAPTURE; + } + + private static RuntimeHash captureHash(HashSpecialVariable.Id mode) { + return GlobalVariable.getGlobalHash( + mode == HashSpecialVariable.Id.CAPTURE_ALL ? "main::-" : "main::+"); + } + + private static void arity(RuntimeArray args, int expected, String method, String signature) { + if (args.size() != expected) { + throw new PerlCompilerException( + "Usage: Tie::Hash::NamedCapture::" + method + "(" + signature + ")"); + } + } + + private static RuntimeList undef() { + return new RuntimeScalar().getList(); + } + + public static RuntimeList FETCH(RuntimeArray args, int ctx) { + arity(args, 2, "FETCH", "$key"); + HashSpecialVariable.Id mode = mode(args.get(0)); + if (mode == null) return undef(); + return new RuntimeScalar(captureHash(mode).get(args.get(1))).getList(); + } + + public static RuntimeList STORE(RuntimeArray args, int ctx) { + arity(args, 3, "STORE", "$key, $value"); + throw new PerlCompilerException("Modification of a read-only value attempted"); + } + + public static RuntimeList DELETE(RuntimeArray args, int ctx) { + arity(args, 2, "DELETE", "$key"); + throw new PerlCompilerException("Modification of a read-only value attempted"); + } + + public static RuntimeList CLEAR(RuntimeArray args, int ctx) { + arity(args, 1, "CLEAR", ""); + throw new PerlCompilerException("Modification of a read-only value attempted"); + } + + public static RuntimeList EXISTS(RuntimeArray args, int ctx) { + arity(args, 2, "EXISTS", "$key"); + HashSpecialVariable.Id mode = mode(args.get(0)); + if (mode == null) return undef(); + return new RuntimeScalar(captureHash(mode).exists(args.get(1))).getList(); + } + + private static List keys(HashSpecialVariable.Id mode) { + return new ArrayList<>(captureHash(mode).elements.keySet()); + } + + public static RuntimeList FIRSTKEY(RuntimeArray args, int ctx) { + arity(args, 1, "FIRSTKEY", ""); + HashSpecialVariable.Id mode = mode(args.get(0)); + if (mode == null) return undef(); + List keys = keys(mode); + return keys.isEmpty() ? undef() : new RuntimeScalar(keys.get(0)).getList(); + } + + public static RuntimeList NEXTKEY(RuntimeArray args, int ctx) { + arity(args, 2, "NEXTKEY", "$lastkey"); + HashSpecialVariable.Id mode = mode(args.get(0)); + if (mode == null) return undef(); + List keys = keys(mode); + int index = keys.indexOf(args.get(1).toString()) + 1; + return index <= 0 || index >= keys.size() + ? undef() + : new RuntimeScalar(keys.get(index)).getList(); + } + + public static RuntimeList SCALAR(RuntimeArray args, int ctx) { + arity(args, 1, "SCALAR", ""); + HashSpecialVariable.Id mode = mode(args.get(0)); + if (mode == null) return undef(); + return new RuntimeScalar(captureHash(mode).size()).getList(); + } +} diff --git a/src/main/java/org/perlonjava/runtime/perlmodule/Utf8.java b/src/main/java/org/perlonjava/runtime/perlmodule/Utf8.java index 1a871fe9b7..9f6ce336a7 100644 --- a/src/main/java/org/perlonjava/runtime/perlmodule/Utf8.java +++ b/src/main/java/org/perlonjava/runtime/perlmodule/Utf8.java @@ -26,7 +26,10 @@ public class Utf8 extends PerlModuleBase { * Initializes the module with the name "utf8". */ public Utf8() { - super("utf8"); + // Register core utf8:: functions eagerly without claiming that the + // pragma file was required. Perl leaves %INC untouched until an + // explicit require/use, and regex case folding must not load it. + super("utf8", false); } /** diff --git a/src/main/java/org/perlonjava/runtime/regex/CaptureNameEncoder.java b/src/main/java/org/perlonjava/runtime/regex/CaptureNameEncoder.java index 736a92c589..588c886ade 100644 --- a/src/main/java/org/perlonjava/runtime/regex/CaptureNameEncoder.java +++ b/src/main/java/org/perlonjava/runtime/regex/CaptureNameEncoder.java @@ -5,14 +5,14 @@ import org.perlonjava.runtime.runtimetypes.RuntimeScalarType; /** - * Utility class for encoding/decoding capture group names to work around Java regex limitations. + * Utility class for encoding and decoding internal capture-group metadata. * *

    Purpose

    - * Java's regex engine has several limitations compared to Perl: + * The frontend and native matcher exchange metadata through capture names for: *
      - *
    • No support for executing code in regex ((?{...}) blocks)
    • - *
    • Named captures cannot contain underscores
    • - *
    • Duplicate capture group names not supported
    • + *
    • constant code-block results used by the callback adapter
    • + *
    • capture names containing underscores
    • + *
    • duplicate capture names that need stable publication identities
    • *
    * *

    Solution: In-Place Encoding

    @@ -51,21 +51,21 @@ *
  • Self-contained: pattern carries its own metadata
  • *
  • No static state accumulation
  • *
  • Works with regex caching
  • - *
  • Reusable pattern for multiple Java limitations
  • + *
  • Independent of the production matcher implementation
  • * */ public class CaptureNameEncoder { /** - * Maximum length for a Java capture group name. - * Longer names may cause pattern compilation issues. + * Maximum length for an encoded capture group name. + * Longer names may cause native pattern compilation issues. */ public static final int MAX_CAPTURE_NAME_LENGTH = 200; /** * Marker appended to capture group names that appear more than once in the * same pattern, e.g. {@code (?a)|(?b)}. Perl accepts duplicate names - * in alternation; Java rejects them. RegexPreprocessor appends + * in alternation; the native compilation adapter appends * "{@value #DUPLICATE_MARKER}" to the second and later occurrences, and * {@link #decodeGroupName} strips the suffix back off so user code sees * the original name. @@ -78,7 +78,7 @@ public class CaptureNameEncoder { /** * Compiled pattern that matches the duplicate-name marker followed by its - * counter at the end of a Java group name. Used by {@link #decodeGroupName} + * counter at the end of an encoded group name. Used by {@link #decodeGroupName} * and {@link #stripDuplicateMarker} to recover the original Perl name. */ private static final java.util.regex.Pattern DUPLICATE_MARKER_PATTERN = @@ -185,7 +185,7 @@ public static boolean isCodeBlockCapture(String captureName) { // UNDERSCORE ENCODING: // - // Java regex doesn't allow underscores in group names (only [a-zA-Z][a-zA-Z0-9]*). + // The internal capture-name transport uses an alphanumeric alphabet. // Perl allows \w+ (letters, digits, underscores) for group names. // // Encoding: Replace each underscore with "U95" (ASCII code 95 for '_') @@ -193,16 +193,16 @@ public static boolean isCodeBlockCapture(String captureName) { // (?<_>) → (?) // (?<_foo>) → (?) // - // Names starting with underscore need a letter prefix for Java, so U95 works + // Names starting with underscore need a letter prefix, so U95 works // since it starts with 'U'. To avoid ambiguity, literal "U95" sequences in // names are escaped as "UU95" (the 'U' itself is escaped). /** - * Encodes a Perl capture group name for use in Java regex. + * Encodes a Perl capture group name for the internal matcher transport. * Replaces underscores with "U95" and escapes literal "U95" sequences. * * @param perlName The original Perl capture group name - * @return The encoded name safe for Java regex, or the original if no encoding needed + * @return The transport-safe name, or the original if no encoding is needed */ public static String encodeGroupName(String perlName) { if (perlName == null || (!perlName.contains("_") && !perlName.contains("U95"))) { @@ -216,20 +216,20 @@ public static String encodeGroupName(String perlName) { } /** - * Decodes a Java regex capture group name back to the original Perl name. + * Decodes an internal capture group name back to the original Perl name. * Reverses the encoding done by encodeGroupName, and also strips any - * duplicate-name marker added by {@link RegexPreprocessor#handleNamedCapture} + * duplicate-name marker carried by the native capture-name adapter * for patterns like {@code (?a)|(?b)}. * - * @param javaName The encoded Java group name + * @param javaName The encoded internal group name * @return The original Perl capture group name */ public static String decodeGroupName(String javaName) { if (javaName == null) { return javaName; } - // First strip any duplicate-name marker (preprocessor adds this for - // names that appear more than once in alternation branches). + // First strip any duplicate-name marker (the native compilation adapter + // adds this for names that appear more than once in alternation branches). javaName = stripDuplicateMarker(javaName); if (!javaName.contains("U95")) { return javaName; diff --git a/src/main/java/org/perlonjava/runtime/regex/ExtendedCharClass.java b/src/main/java/org/perlonjava/runtime/regex/ExtendedCharClass.java deleted file mode 100644 index a409e810cd..0000000000 --- a/src/main/java/org/perlonjava/runtime/regex/ExtendedCharClass.java +++ /dev/null @@ -1,1367 +0,0 @@ -package org.perlonjava.runtime.regex; - -import com.ibm.icu.lang.UCharacter; - -import java.util.ArrayList; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; - -/** - * ExtendedCharClass handles Perl's Extended Bracketed Character Classes (?[...]) - *

    - * Extended character classes allow set operations on character classes: - * - Union: (?[ [a] + [b] ]) or (?[ [a] | [b] ]) - * - Intersection: (?[ [a-z] & [aeiou] ]) - * - Subtraction: (?[ [a-z] - [aeiou] ]) - * - Symmetric difference: (?[ [a-z] ^ [aeiou] ]) - * - Complement: (?[ ! [a-z] ]) - *

    - * Features: - * - Automatic /xx mode (whitespace ignored) - * - Comments with # and (?#...) - * - Nested expressions with parentheses - * - Unicode properties (\p{...}, \pN) - * - POSIX classes ([:word:], etc.) - * - Escape sequences (\t, \cX, etc.) - * - Regex interpolation (qr// patterns) - *

    - * The implementation tokenizes the content, parses it into an expression tree, - * and transforms it into Java's character class syntax using intersection (&&) - * and negation (^) operators. - */ -public class ExtendedCharClass { - // Thread-local flag to communicate case-insensitivity to nested processing - private static final ThreadLocal caseInsensitive = ThreadLocal.withInitial(() -> false); - - /** - * Handles Perl's Extended Bracketed Character Class (?[...]) - * Transforms it into Java-compatible character class syntax. - * - * @param s The regex string - * @param offset Current position (at '(') - * @param sb StringBuilder for output - * @param regexFlags Current regex flags - * @return Position after the closing ]) - */ - static int handleExtendedCharacterClass(String s, int offset, StringBuilder sb, RegexFlags regexFlags) { - int start = offset + 3; // Skip past '(?[' - - // First, check if this is an empty extended character class - int i = start; - while (i < s.length() && Character.isWhitespace(s.charAt(i))) { - i++; - } - - if (i < s.length() && s.charAt(i) == ']' && i + 1 < s.length() && s.charAt(i + 1) == ')') { - // This is an empty extended character class - RegexPreprocessor.regexError(s, start, "Incomplete expression within '(?[ ])'"); - } - - // Now find the end - int end; - try { - end = findExtendedClassEnd(s, start); - } catch (IllegalStateException e) { - // Convert validation errors to regex errors - // This handles "Unexpected ]" and other structural errors - RegexPreprocessor.regexError(s, offset, e.getMessage()); - return -1; // Never reached - } - - if (end == -1) { - // Extended class never properly closed - this is a syntax error - RegexPreprocessor.regexError(s, offset, "Syntax error in (?[...])"); - } - - String content = s.substring(start, end); - - // System.err.println("DEBUG: ExtendedCharClass content: '" + content + "'"); - - // Check for empty or whitespace-only content - if (content.trim().isEmpty()) { - RegexPreprocessor.regexError(s, start, "Incomplete expression within '(?[ ])'"); - } - - // try { - // Parse and transform the extended character class - // Set case-insensitivity flag for nested processing - boolean isCaseInsensitive = regexFlags.isCaseInsensitive(); - caseInsensitive.set(isCaseInsensitive); - try { - String transformed = transformExtendedClass(content, s, start); - // Wrap in (?-i:...) to disable Java's /i flag for the extended character class. - // We handle case-folding manually for literals within the extended char class, - // but /i should NOT affect Unicode properties like \p{Blk=ASCII}. - // Wrapping ensures the character class uses only our manual case expansions. - sb.append("(?-i:").append(transformed).append(")"); - } finally { - caseInsensitive.set(false); - } - - // Skip past the '])' - return end + 1; -// } catch (Exception e) { -// RegexPreprocessor.regexError(s, start, e.getMessage()); -// return -1; // Never reached due to exception -// } - } - - /** - * Find the end of the extended character class, handling nested brackets. - *

    - * This method tracks bracket depth to handle nested character classes like [a[b]c]. - * It also handles escape sequences, especially \c which consumes two characters. - *

    - * The extended character class ends when we find ]) at depth 0. - * - * @param s The regex string - * @param start Position after the opening (?[ - * @return Position of the closing ], or -1 if not found - */ - private static int findExtendedClassEnd(String s, int start) { - int depth = 1; // Track bracket nesting depth - int i = start; - boolean inEscape = false; - - while (i < s.length() && depth > 0) { - char c = s.charAt(i); - - if (inEscape) { - inEscape = false; - // Special case: \c consumes two characters (c and the control char) - // This is critical for patterns like \c[ where [ is the control char - // However, if we're inside nested structures (depth > 1) and \c is followed - // by ] or ), those should close the structure, not be consumed by \c - if (c == 'c' && i + 1 < s.length()) { - char nextChar = s.charAt(i + 1); - // At depth 1, \c] or \c) are valid (] closes extended class, ) is the outer paren) - // At depth > 1, \c] or \c) leave \c incomplete - don't consume the ] or ) - if (depth > 1 && (nextChar == ']' || nextChar == ')')) { - // Don't consume the ] or ) - let them be processed as structure - i++; // Just skip the 'c' - } else { - i += 2; // Skip both 'c' and the next character - } - } else { - i++; - } - continue; - } - - // Check for nested (?[...]) - if (c == '(' && i + 2 < s.length() && s.charAt(i + 1) == '?' && s.charAt(i + 2) == '[') { - // System.err.println("DEBUG: Found nested (?[ at position " + i); - // We found a nested extended character class - // We need to skip over it entirely - int nestedEnd = findExtendedClassEnd(s, i + 3); - if (nestedEnd == -1) { - // The nested one is unterminated, but we should continue - // The error will be caught when that nested one is processed - return -1; - } - // Skip to after the "])'" of the nested extended class - i = nestedEnd + 2; // +2 for "])" - continue; - } - - switch (c) { - case '\\': - inEscape = true; - break; - case '[': - depth++; - break; - case ']': - depth--; - if (depth == 0) { - // Check if this ends the extended character class - int j = i + 1; - while (j < s.length() && Character.isWhitespace(s.charAt(j))) { - j++; - } - if (j < s.length() && s.charAt(j) == ')') { - // System.err.println("DEBUG: Found end of extended class at position " + i); - return i; - } - // Found ] at depth 0 but not followed by ) - // This is "Unexpected ]" not "Unterminated" - throw new IllegalStateException("Unexpected ']' with no following ')' in (?[..."); - } - break; - } - i++; - } - - return -1; - } - - /** - * Transform the extended character class content into Java syntax - */ - private static String transformExtendedClass(String content, String originalRegex, int contentStart) { - // Before tokenizing, scan for nested regex constructs and process them - // This allows us to catch errors in nested patterns - scanForNestedConstructs(content, originalRegex, contentStart); - - // Tokenize the expression - List tokens = tokenizeExtendedClass(content, originalRegex, contentStart); - - // Parse into expression tree - ExprNode tree = parseExtendedClass(tokens, originalRegex, contentStart); - - // Transform to Java syntax - return evaluateExtendedClass(tree); - } - - private static void scanForNestedConstructs(String content, String originalRegex, int contentStart) { - int i = 0; - while (i < content.length()) { - char c = content.charAt(i); - - // Look for (?...) constructs - if (c == '(' && i + 1 < content.length() && content.charAt(i + 1) == '?') { - // System.err.println("DEBUG: Found nested (? at position " + i + " in extended char class content"); - - // Check what type of construct this is - if (i + 2 < content.length()) { - char nextChar = content.charAt(i + 2); - - if (nextChar == '[') { - // Nested extended character class - process it recursively - // System.err.println("DEBUG: Found nested (?[ at position " + i); - // Call handleExtendedCharacterClass recursively - StringBuilder dummySb = new StringBuilder(); - ExtendedCharClass.handleExtendedCharacterClass(originalRegex, contentStart + i, dummySb, RegexFlags.fromModifiers("", "")); - } else if (nextChar == 'x' && i + 3 < content.length() && content.charAt(i + 3) == ':') { - // (?x:...) construct - scan inside it - // System.err.println("DEBUG: Found (?x: at position " + i); - // Find the matching closing paren - int closePos = findMatchingParen(content, i); - if (closePos > i + 4) { - String innerContent = content.substring(i + 4, closePos); - scanForNestedConstructs(innerContent, originalRegex, contentStart + i + 4); - } - } - } - } - i++; - } - } - - private static int findMatchingParen(String s, int start) { - int depth = 1; - int i = start + 1; - while (i < s.length() && depth > 0) { - char c = s.charAt(i); - if (c == '(') depth++; - else if (c == ')') depth--; - i++; - } - return depth == 0 ? i - 1 : -1; - } - - /** - * Tokenize the extended character class content - * Automatically handles whitespace (xx mode) - */ - private static List tokenizeExtendedClass(String content, String originalRegex, int contentStart) { - List tokens = new ArrayList<>(); - int i = 0; - - while (i < content.length()) { - // Skip whitespace (automatic /xx mode) - // In extended character classes, Pattern_White_Space includes NEL (U+0085) - while (i < content.length()) { - char ch = content.charAt(i); - if (Character.isWhitespace(ch) || ch == '\u0085') { // NEL - i++; - } else { - break; - } - } - - if (i >= content.length()) break; - - char c = content.charAt(i); - - // Handle comments (# to end of line) - if (c == '#') { - // Skip to end of line - while (i < content.length() && content.charAt(i) != '\n') { - i++; - } - continue; - } - - int tokenStart = contentStart + i; - - switch (c) { - case '&': - case '+': - case '|': - case '-': - case '^': - tokens.add(new Token(TokenType.OPERATOR, String.valueOf(c), tokenStart)); - i++; - break; - - case '!': - tokens.add(new Token(TokenType.OPERATOR, "!", tokenStart)); - i++; - break; - - case '(': - // Check for inline comment (?#...) - if (i + 2 < content.length() && content.charAt(i + 1) == '?' && content.charAt(i + 2) == '#') { - // Skip to closing ) - int closePos = content.indexOf(')', i + 3); - if (closePos != -1) { - i = closePos + 1; - } else { - // Unterminated comment, skip to end - i = content.length(); - } - } else if (i + 6 < content.length() && content.charAt(i + 1) == '?') { - // Check for interpolated regex pattern: (?FLAGS:(?[ ... ])) - // When a qr// pattern containing (?[...]) is interpolated, it becomes: - // (?^:(?[ ... ])) or (?^i:(?[ ... ])) etc. - // We need to extract just the inner (?[ ... ]) part AND preserve any /i flag - - // Find the : after the flags (e.g., (?^: or (?^i:) - int colonPos = i + 2; - while (colonPos < content.length() && content.charAt(colonPos) != ':' && content.charAt(colonPos) != ')') { - colonPos++; - } - - // Extract and parse flags from this construct - String outerFlags = content.substring(i + 2, colonPos); - boolean hasInnerCaseInsensitive = outerFlags.contains("i"); - - // Check if this is followed by (?[ or another (?FLAGS: - if (colonPos < content.length() && content.charAt(colonPos) == ':' && - colonPos + 1 < content.length() && content.charAt(colonPos + 1) == '(') { - - int searchPos = colonPos + 1; - // Skip nested (?FLAGS: groups to find the actual (?[, collecting all flags - while (searchPos < content.length() && content.charAt(searchPos) == '(' && - searchPos + 2 < content.length() && content.charAt(searchPos + 1) == '?') { - // Find the : after these flags - int nextColon = searchPos + 2; - while (nextColon < content.length() && content.charAt(nextColon) != ':' && - content.charAt(nextColon) != ')') { - nextColon++; - } - // Collect flags from this nested construct too - String nestedFlags = content.substring(searchPos + 2, nextColon); - if (nestedFlags.contains("i")) { - hasInnerCaseInsensitive = true; - } - if (nextColon < content.length() && content.charAt(nextColon) == ':') { - if (nextColon + 3 < content.length() && content.charAt(nextColon + 1) == '(' && - content.charAt(nextColon + 2) == '?' && content.charAt(nextColon + 3) == '[') { - // Found (?[! - searchPos = nextColon + 1; - break; - } - // Another (?FLAGS: group, continue searching - searchPos = nextColon + 1; - } else { - break; - } - } - - // Check if we found (?[ - if (searchPos < content.length() && content.charAt(searchPos) == '(' && - searchPos + 2 < content.length() && content.charAt(searchPos + 1) == '?' && - content.charAt(searchPos + 2) == '[') { - // Found (?FLAGS:...(?[ ... ])) - this is an interpolated extended char class - int innerStart = searchPos; // Position of inner '(?[' - int innerEnd = findMatchingParen(content, innerStart); - if (innerEnd != -1) { - // Extract just the content between (?[ and ]) - String innerContent = content.substring(innerStart + 3, innerEnd - 1); - - // If the interpolated pattern has /i flag, process with case-insensitivity - String processedContent; - if (hasInnerCaseInsensitive) { - // Temporarily enable case-insensitivity for this nested content - boolean savedCaseSensitive = caseInsensitive.get(); - caseInsensitive.set(true); - try { - processedContent = transformExtendedClass(innerContent, content, innerStart + 3); - } finally { - caseInsensitive.set(savedCaseSensitive); - } - } else { - processedContent = "(?[" + innerContent + "])"; - } - - // Add as a character class token (already processed if had /i) - tokens.add(new Token(TokenType.CHAR_CLASS, processedContent, tokenStart)); - // Skip past the entire (?FLAGS:...(?[ ... ])) construct - // We need to skip all the closing ) for the nested flag groups - i = innerEnd + 1; // After the closing ) of (?[...) - // Skip closing ) for each nested flag group - while (i < content.length() && content.charAt(i) == ')') { - i++; - } - } else { - // Malformed, treat as regular paren - tokens.add(new Token(TokenType.LPAREN, "(", tokenStart)); - i++; - } - } else { - tokens.add(new Token(TokenType.LPAREN, "(", tokenStart)); - i++; - } - } else { - tokens.add(new Token(TokenType.LPAREN, "(", tokenStart)); - i++; - } - } else { - tokens.add(new Token(TokenType.LPAREN, "(", tokenStart)); - i++; - } - break; - - case ')': - tokens.add(new Token(TokenType.RPAREN, ")", tokenStart)); - i++; - break; - - case '[': - // Parse a character class element - int classEnd = findCharClassEnd(content, i); - if (classEnd == -1) { - RegexPreprocessor.regexError(originalRegex, tokenStart, "Unterminated character class"); - } - String classContent = content.substring(i, classEnd + 1); - - // Validate character ranges in the class - validateCharacterRanges(classContent, originalRegex, tokenStart); - - tokens.add(new Token(TokenType.CHAR_CLASS, classContent, tokenStart)); - i = classEnd + 1; - break; - - case ':': - // Check for POSIX class - if (i + 1 < content.length() && content.charAt(i + 1) == ':') { - int posixEnd = content.indexOf("::", i + 2); - if (posixEnd != -1) { - String posixClass = content.substring(i, posixEnd + 2); - tokens.add(new Token(TokenType.CHAR_CLASS, posixClass, tokenStart)); - i = posixEnd + 2; - break; - } - } - // Fall through to error - - case '\\': - // Parse escape sequence as a character class element - int escapeEnd = parseEscapeInExtendedClass(content, i); - String escapeSeq = content.substring(i, escapeEnd); - // Wrap escape sequences in brackets to make them character class elements - tokens.add(new Token(TokenType.CHAR_CLASS, "[" + escapeSeq + "]", tokenStart)); - i = escapeEnd; - break; - - default: - // Single character must be wrapped in brackets - RegexPreprocessor.regexError(originalRegex, tokenStart, - "Bare character '" + c + "' not allowed in (?[...]). Use [" + c + "] instead"); - } - } - - tokens.add(new Token(TokenType.EOF, "", contentStart + content.length())); - - // Check if we have any meaningful tokens - if (tokens.size() == 1 && tokens.get(0).type == TokenType.EOF) { - RegexPreprocessor.regexError(originalRegex, contentStart, "Incomplete expression within '(?[ ])'"); - } - - return tokens; - } - - private static void validateCharacterRanges(String charClass, String originalRegex, int classStart) { - if (!charClass.startsWith("[") || !charClass.endsWith("]")) { - return; - } - - String content = charClass.substring(1, charClass.length() - 1); - int i = 0; - int lastChar = -1; - boolean inEscape = false; - - while (i < content.length()) { - char c = content.charAt(i); - - // Skip whitespace in extended character class - if (Character.isWhitespace(c)) { - i++; - continue; - } - - if (inEscape) { - inEscape = false; - lastChar = -1; - i++; - continue; - } - - if (c == '\\') { - inEscape = true; - } else if (c == '-' && lastChar != -1 && i + 1 < content.length()) { - char nextChar = content.charAt(i + 1); - if (!Character.isWhitespace(nextChar) && nextChar != ']' && nextChar != '\\') { - if (nextChar < lastChar) { - RegexPreprocessor.regexError(originalRegex, classStart + i + 3, - String.format("Invalid [] range \"%c-%c\" in regex", lastChar, nextChar)); - } - // Valid range: skip over the end character and reset lastChar - // so the next '-' will be treated as literal or start a new range - i++; // Skip the range end character - lastChar = -1; - } - } else if (c != '-' && c != '^' && c != '[' && c != ':') { - lastChar = c; - } - - i++; - } - } - - /** - * Find the end of a character class [...] - */ - private static int findCharClassEnd(String content, int start) { - int i = start + 1; // Skip opening [ - boolean inEscape = false; - boolean first = true; - boolean afterCaret = false; - - while (i < content.length()) { - char c = content.charAt(i); - - if (inEscape) { - inEscape = false; - first = false; - afterCaret = false; - i++; - continue; - } - - // In extended character classes, skip whitespace - if (Character.isWhitespace(c)) { - i++; - continue; - } - - if (c == '\\') { - inEscape = true; - first = false; - afterCaret = false; - } else if (c == ']') { - // Special case: ] immediately after [ or [^ is a literal ] - if (first || afterCaret) { - // This is a literal ], not the closing bracket - first = false; - afterCaret = false; - } else { - // This closes the character class - return i; - } - } else if (c == '^' && first) { - afterCaret = true; - first = false; - } else { - // Any non-whitespace character resets the flags - first = false; - afterCaret = false; - } - - i++; - } - - return -1; - } - - /** - * Parse an escape sequence in extended class - */ - private static int parseEscapeInExtendedClass(String content, int start) { - if (start + 1 >= content.length()) { - return start + 1; - } - - char next = content.charAt(start + 1); - - // Handle special escape sequences - if (next == 'p' || next == 'P') { - // Unicode property: \p{Name} or \pL (single letter) - if (start + 2 < content.length() && content.charAt(start + 2) == '{') { - int end = content.indexOf('}', start + 3); - return end != -1 ? end + 1 : start + 2; - } - // Single-letter property like \pN, \pL - return start + 3; - } else if (next == 'N') { - // Named character - if (start + 2 < content.length() && content.charAt(start + 2) == '{') { - int end = content.indexOf('}', start + 3); - return end != -1 ? end + 1 : start + 2; - } - } else if (next == 'x') { - // Hex escape - if (start + 2 < content.length() && content.charAt(start + 2) == '{') { - int end = content.indexOf('}', start + 3); - return end != -1 ? end + 1 : start + 4; // \xHH - } - return start + 4; // \xHH - } else if (next == 'o') { - // Octal escape - if (start + 2 < content.length() && content.charAt(start + 2) == '{') { - int end = content.indexOf('}', start + 3); - return end != -1 ? end + 1 : start + 2; - } - } else if (next == 'c') { - // Control character: \cX consumes the backslash, 'c', and the next character - // Check if we have a character after \c - if (start + 2 < content.length()) { - return start + 3; - } - // Incomplete \c at end of string - return start + 2; - } - - // Default: single character escape - return start + 2; - } - - /** - * Parse tokens into expression tree - * Precedence: ! > & > (+|-|^|) - * Binary ops are left-associative, unary is right-associative - */ - private static ExprNode parseExtendedClass(List tokens, String originalRegex, int contentStart) { - return new ExtendedClassParser(tokens, originalRegex, contentStart).parse(); - } - - /** - * Process a character class element from extended syntax. - *

    - * This handles: - * - Nested extended character classes (?[...]) from interpolation - * - POSIX classes ([:word:], [:digit:], etc.) - * - Regular character classes ([a-z], [abc], etc.) - * - Escape sequences (\d, \w, \s, etc.) - * - * @param charClass The character class string to process - * @return Java-compatible character class syntax - */ - private static String processCharacterClass(String charClass) { - // Handle nested extended character class (?[...]) - // This occurs when a qr/(?[...])/ pattern is interpolated - if (charClass.startsWith("(?[") && charClass.endsWith("])")) { - // Recursively process the nested extended character class - String nestedContent = charClass.substring(3, charClass.length() - 2); - return transformExtendedClass(nestedContent, charClass, 0); - } - - // Handle POSIX classes - if (charClass.startsWith("::") && charClass.endsWith("::")) { - // Transform ::word:: to [:word:] - String posixClass = "[" + charClass.substring(1, charClass.length() - 1) + "]"; - String mapped = CharacterClassMapper.getMappedClass(posixClass); - if (mapped != null) { - return mapped; - } - } else if (charClass.startsWith("[:") && charClass.endsWith(":]") && charClass.length() > 4) { - // Valid POSIX class must have at least one character between [: and :] - // e.g., [:word:] is valid, but [:] is not - String mapped = CharacterClassMapper.getMappedClass(charClass); - if (mapped != null) { - return mapped; - } - } - - // Handle bracketed content - if (charClass.startsWith("[") && charClass.endsWith("]")) { - String content = charClass.substring(1, charClass.length() - 1); - StringBuilder result = new StringBuilder(); - - // Process the content - in extended character classes, spaces are ignored (xx mode) - int i = 0; - int lastChar = -1; // Track last character for range validation - boolean atStart = true; // Track if we're at the start (for ^ negation detection) - - while (i < content.length()) { - char c = content.charAt(i); - - // Skip whitespace in extended character class (automatic /xx mode) - if (Character.isWhitespace(c)) { - i++; - continue; - } - - // Check for invalid range - if (c == '-' && lastChar != -1 && i + 1 < content.length()) { - char nextChar = content.charAt(i + 1); - if (!Character.isWhitespace(nextChar) && nextChar != ']' && nextChar != '\\' && nextChar < lastChar) { - throw new IllegalArgumentException( - String.format("Invalid [] range \"%c-%c\"", lastChar, nextChar) - ); - } - } - - if (c == '\\') { - // Handle escape sequences - if (i + 1 < content.length()) { - char next = content.charAt(i + 1); - - // Skip whitespace after backslash too - if (Character.isWhitespace(next)) { - // Literal whitespace needs to be escaped, but in extended mode it's ignored - i += 2; - continue; - } - - if (next == 'c' && i + 2 < content.length()) { - // Convert Perl's control-character escape before - // Joni can mistake targets such as \\, [, or ] for - // character-class syntax. - int ctrl = content.codePointAt(i + 2); - if (ctrl >= 'a' && ctrl <= 'z') { - ctrl = ctrl - 'a' + 'A'; - } - int value = (ctrl ^ 0x40) & 0xFF; - result.append(String.format("\\x{%X}", value)); - i += 3; - lastChar = value; - continue; - } else if (next == 'p' || next == 'P') { - // Unicode property - int start = i; - if (i + 2 < content.length() && content.charAt(i + 2) == '{') { - int end = content.indexOf('}', i + 3); - if (end != -1) { - String property = content.substring(i + 3, end); - boolean negated = (next == 'P'); - String translated = UnicodeResolver.translateUnicodeProperty( - property, negated); - - // Unwrap if necessary - if (translated.startsWith("[") && translated.endsWith("]")) { - result.append(translated, 1, translated.length() - 1); - } else { - result.append(translated); - } - i = end + 1; - continue; - } - } - } else if (next == 'N' && i + 2 < content.length() && content.charAt(i + 2) == '{') { - // Named character - int end = content.indexOf('}', i + 3); - if (end != -1) { - String name = content.substring(i + 3, end).trim(); - try { - int codePoint = UnicodeResolver.getCodePointFromName(name); - // Check if case-insensitive and needs case expansion - if (caseInsensitive.get()) { - // First check for special folds - String expansion = expandCaseFoldInCharClass(codePoint); - if (expansion != null) { - result.append(expansion); - i = end + 1; - continue; - } - // Add upper/lower case variants - int lower = UCharacter.toLowerCase(codePoint); - int upper = UCharacter.toUpperCase(codePoint); - if (lower != upper) { - appendCharClassChar(result, codePoint); - if (lower != codePoint) { - appendCharClassChar(result, lower); - } - if (upper != codePoint) { - appendCharClassChar(result, upper); - } - i = end + 1; - continue; - } - } - result.append(String.format("\\x{%X}", codePoint)); - i = end + 1; - continue; - } catch (IllegalArgumentException e) { - // Let it fall through to be handled as regular escape - } - } - } else if (next == 'x' && i + 2 < content.length() && content.charAt(i + 2) == '{') { - // Hex escape \x{...} - int end = content.indexOf('}', i + 3); - if (end != -1) { - String hex = content.substring(i + 3, end).trim(); - try { - int codePoint = Integer.parseInt(hex, 16); - // Check if case-insensitive and needs case expansion - if (caseInsensitive.get()) { - // First check for special folds - String expansion = expandCaseFoldInCharClass(codePoint); - if (expansion != null) { - result.append(expansion); - i = end + 1; - continue; - } - // Add upper/lower case variants - int lower = UCharacter.toLowerCase(codePoint); - int upper = UCharacter.toUpperCase(codePoint); - if (lower != upper) { - appendCharClassChar(result, codePoint); - if (lower != codePoint) { - appendCharClassChar(result, lower); - } - if (upper != codePoint) { - appendCharClassChar(result, upper); - } - i = end + 1; - continue; - } - } - result.append(String.format("\\x{%X}", codePoint)); - i = end + 1; - continue; - } catch (NumberFormatException e) { - // Let it fall through to be handled as regular escape - } - } - } else if ((next == 'b' || next == 'B') && i + 2 < content.length() && content.charAt(i + 2) == '{') { - // Boundary assertions not allowed in character class - RegexPreprocessor.regexError("", i, "Boundary assertion \\" + next + "{...} not allowed in character class"); - } - } - - // Regular escape sequence - result.append(c); - if (i + 1 < content.length()) { - result.append(content.charAt(i + 1)); - i += 2; - } else { - i++; - } - lastChar = -1; // Reset after escape - } else if (c == '[' && i + 1 < content.length() && content.charAt(i + 1) == ':') { - // POSIX class - int end = content.indexOf(":]", i + 2); - if (end != -1) { - String posixClass = content.substring(i, end + 2); - String mapped = CharacterClassMapper.getMappedClass(posixClass); - if (mapped != null) { - // Unwrap the mapped class - if (mapped.startsWith("\\p{") && mapped.endsWith("}")) { - result.append(mapped); - } else if (mapped.startsWith("\\P{") && mapped.endsWith("}")) { - result.append(mapped); - } else { - result.append(mapped); - } - i = end + 2; - continue; - } - } - result.append(c); - i++; - lastChar = -1; // Reset after POSIX class - } else { - // Regular character - handle case variants if case-insensitive - int codePoint = content.codePointAt(i); - int charLen = Character.charCount(codePoint); - - // Handle ^ at start as negation metacharacter (not a range start) - if (codePoint == '^' && atStart) { - result.append('^'); - i += charLen; - atStart = false; - // Note: don't set lastChar - ^ is a metacharacter, not a character in the class - // Also, afterCaret means the next char is right after ^, so - should be literal - continue; - } - - // Check if - is at the start position (literal hyphen) - // In [^-b], - is a literal because it's right after ^ (or at position 0) - // atStart is true if we haven't seen any non-whitespace non-^ character yet - boolean hyphenIsLiteral = (codePoint == '-' && (atStart || lastChar == -1)); - - // After any non-whitespace, we're no longer at start - atStart = false; - - // Check if this is the start of a range (followed by - and another char) - // Skip whitespace when looking for the dash (extended char class syntax) - boolean isRangeStart = false; - int rangeEndCodePoint = -1; - int rangeEndPos = -1; - int dashPos = i + charLen; - // Skip whitespace before dash - while (dashPos < content.length() && Character.isWhitespace(content.charAt(dashPos))) { - dashPos++; - } - if (dashPos < content.length() && content.charAt(dashPos) == '-') { - int afterDashPos = dashPos + 1; - // Skip whitespace after dash - while (afterDashPos < content.length() && Character.isWhitespace(content.charAt(afterDashPos))) { - afterDashPos++; - } - if (afterDashPos < content.length()) { - char afterDash = content.charAt(afterDashPos); - if (afterDash != ']' && afterDash != '-') { - isRangeStart = true; - rangeEndCodePoint = content.codePointAt(afterDashPos); - rangeEndPos = afterDashPos; - } - } - } - - if (caseInsensitive.get() && !isRangeStart) { - // Not a range start - expand individual character - // First check for special folds (KELVIN SIGN, etc.) - String expansion = expandCaseFoldInCharClass(codePoint); - if (expansion != null) { - result.append(expansion); - i += charLen; - lastChar = -1; // Reset after expansion - continue; - } - // For regular characters, add upper and lower case variants - int lower = UCharacter.toLowerCase(codePoint); - int upper = UCharacter.toUpperCase(codePoint); - if (lower != upper) { - // Has case variants - add both - appendCharClassChar(result, codePoint); - if (lower != codePoint) { - appendCharClassChar(result, lower); - } - if (upper != codePoint) { - appendCharClassChar(result, upper); - } - i += charLen; - lastChar = -1; // Reset after expansion - continue; - } - } else if (caseInsensitive.get() && isRangeStart) { - // Handle range with case-insensitivity - // Keep original range, then add case-folded range - int rangeEndCharLen = Character.charCount(rangeEndCodePoint); - - // Append original range: start-end - appendCharClassChar(result, codePoint); - result.append('-'); - appendCharClassChar(result, rangeEndCodePoint); - - // Add case-folded range if different - int startLower = UCharacter.toLowerCase(codePoint); - int startUpper = UCharacter.toUpperCase(codePoint); - int endLower = UCharacter.toLowerCase(rangeEndCodePoint); - int endUpper = UCharacter.toUpperCase(rangeEndCodePoint); - - // Add uppercase range if the original was lowercase - if (startLower == codePoint && startUpper != codePoint) { - appendCharClassChar(result, startUpper); - result.append('-'); - appendCharClassChar(result, endUpper); - } - // Add lowercase range if the original was uppercase - else if (startUpper == codePoint && startLower != codePoint) { - appendCharClassChar(result, startLower); - result.append('-'); - appendCharClassChar(result, endLower); - } - - // Add special Unicode case folds for characters in the range - // Check if any character in the range (or its case-folded equivalent) - // has a special reverse fold mapping - for (Map.Entry entry : SPECIAL_SINGLE_CHAR_REVERSE_FOLDS.entrySet()) { - int baseChar = entry.getKey(); - int specialChar = entry.getValue(); - // Check if baseChar (or its upper/lower) falls within the range - int baseLower = UCharacter.toLowerCase(baseChar); - int baseUpper = UCharacter.toUpperCase(baseChar); - int rangeLower = Math.min(codePoint, rangeEndCodePoint); - int rangeUpper = Math.max(codePoint, rangeEndCodePoint); - int rangeLowerFolded = Math.min(startLower, endLower); - int rangeUpperFolded = Math.max(startUpper, endUpper); - - if ((baseChar >= rangeLower && baseChar <= rangeUpper) || - (baseLower >= rangeLowerFolded && baseLower <= rangeUpperFolded) || - (baseUpper >= rangeLower && baseUpper <= rangeUpper)) { - // Add the special character - appendCharClassChar(result, specialChar); - } - } - - // Skip past the entire range (including any whitespace) - i = rangeEndPos + rangeEndCharLen; - lastChar = -1; - continue; - } - - result.append(c); - if (c != '-' && c != '^') { - lastChar = c; // Remember this character - } - i++; - } - } - - return "[" + result + "]"; - } - - // Should not reach here - return charClass; - } - - /** - * Unwrap outer brackets from a character class if present - */ - private static String unwrapBrackets(String charClass) { - if (charClass.startsWith("[") && charClass.endsWith("]")) { - // But don't unwrap if it's a complex expression with operators - String inner = charClass.substring(1, charClass.length() - 1); - if (!inner.contains("&&")) { - return inner; - } - } - return charClass; - } - - /** - * Evaluate the expression tree to produce Java regex syntax - */ - private static String evaluateExtendedClass(ExprNode tree) { - return tree.evaluate(); - } - - // Token types for the parser - private enum TokenType { - CHAR_CLASS, OPERATOR, LPAREN, RPAREN, EOF - } - - private static class Token { - TokenType type; - String value; - int position; - - Token(TokenType type, String value, int position) { - this.type = type; - this.value = value; - this.position = position; - } - } - - // Expression tree nodes - private static abstract class ExprNode { - abstract String evaluate(); - } - - private static class CharClassNode extends ExprNode { - String content; - - CharClassNode(String content) { - this.content = content; - } - - @Override - String evaluate() { - // Process the character class content - return processCharacterClass(content); - } - } - - /** - * Binary operation node (union, intersection, subtraction, symmetric difference) - *

    - * Operators: - * - + or | : Union (A or B) - * - & : Intersection (A and B) - * - - : Subtraction (A but not B) - * - ^ : Symmetric difference (A or B but not both) - */ - private static class BinaryOpNode extends ExprNode { - String operator; - ExprNode left; - ExprNode right; - - BinaryOpNode(String operator, ExprNode left, ExprNode right) { - this.operator = operator; - this.left = left; - this.right = right; - } - - @Override - String evaluate() { - String leftEval = left.evaluate(); - String rightEval = right.evaluate(); - - // Unwrap outer brackets if present - leftEval = unwrapBrackets(leftEval); - rightEval = unwrapBrackets(rightEval); - - switch (operator) { - case "+": - case "|": - // Union: [A[B]] - return "[" + leftEval + rightEval + "]"; - - case "&": - // Intersection: [A&&[B]] - return "[" + leftEval + "&&[" + rightEval + "]]"; - - case "-": - // Subtraction: [A&&[^B]] - return "[" + leftEval + "&&[^" + rightEval + "]]"; - - case "^": - // Symmetric difference: [[A&&[^B]][B&&[^A]]] - return "[[" + leftEval + "&&[^" + rightEval + "]][" + - rightEval + "&&[^" + leftEval + "]]]"; - - default: - throw new IllegalStateException("Unknown operator: " + operator); - } - } - } - - /** - * Unary operation node (complement) - *

    - * The ! operator complements a character class. - * Important: Double negation is handled specially: - * - ! [^A] becomes [A] (NOT NOT A = A) - * - This prevents invalid Java regex like [^^A] - */ - private static class UnaryOpNode extends ExprNode { - String operator; - ExprNode operand; - - UnaryOpNode(String operator, ExprNode operand) { - this.operator = operator; - this.operand = operand; - } - - @Override - String evaluate() { - String operandEval = operand.evaluate(); - - if (operator.equals("!")) { - // Complement: [^A] - operandEval = unwrapBrackets(operandEval); - - // Check if already negated (starts with ^) - // This handles double negation: ! [^A] = [A] - if (operandEval.startsWith("^")) { - // Double negation: remove the ^ - return "[" + operandEval.substring(1) + "]"; - } else { - return "[^" + operandEval + "]"; - } - } - - throw new IllegalStateException("Unknown unary operator: " + operator); - } - } - - private static class ExtendedClassParser { - private final List tokens; - private final String originalRegex; - private final int contentStart; - private int current = 0; - - ExtendedClassParser(List tokens, String originalRegex, int contentStart) { - this.tokens = tokens; - this.originalRegex = originalRegex; - this.contentStart = contentStart; - } - - ExprNode parse() { - ExprNode expr = parseExpression(); - if (!isAtEnd()) { - error("Unexpected token: " + peek().value); - } - return expr; - } - - private ExprNode parseExpression() { - return parseUnion(); - } - - private ExprNode parseUnion() { - ExprNode expr = parseIntersection(); - - while (match("+", "|", "-", "^")) { - String op = previous().value; - ExprNode right = parseIntersection(); - expr = new BinaryOpNode(op, expr, right); - } - - return expr; - } - - private ExprNode parseIntersection() { - ExprNode expr = parseUnary(); - - while (match("&")) { - String op = previous().value; - ExprNode right = parseUnary(); - expr = new BinaryOpNode(op, expr, right); - } - - return expr; - } - - private ExprNode parseUnary() { - if (match("!")) { - ExprNode operand = parseUnary(); - return new UnaryOpNode("!", operand); - } - - return parsePrimary(); - } - - private ExprNode parsePrimary() { - if (match("(")) { - ExprNode expr = parseExpression(); - consume(")", "Expected ')' after expression"); - return expr; - } - - if (check(TokenType.CHAR_CLASS)) { - return new CharClassNode(advance().value); - } - - error("Expected character class or '('"); - return null; // Never reached - } - - private boolean match(String... values) { - for (String value : values) { - if (check(value)) { - advance(); - return true; - } - } - return false; - } - - private boolean check(String value) { - return !isAtEnd() && peek().value.equals(value); - } - - private boolean check(TokenType type) { - return !isAtEnd() && peek().type == type; - } - - private Token advance() { - if (!isAtEnd()) current++; - return previous(); - } - - private boolean isAtEnd() { - return peek().type == TokenType.EOF; - } - - private Token peek() { - return tokens.get(current); - } - - private Token previous() { - return tokens.get(current - 1); - } - - private void consume(String value, String message) { - if (check(value)) { - advance(); - return; - } - error(message); - } - - private void error(String message) { - Token token = peek(); - RegexPreprocessor.regexError(originalRegex, token.position, message); - } - } - - // Special characters with unusual case folding (same as in RegexPreprocessor) - private static final Map SPECIAL_SINGLE_CHAR_FOLDS = Map.of( - 0x00B5, 0x03BC, // MICRO SIGN -> GREEK SMALL LETTER MU - 0x212A, 0x006B, // KELVIN SIGN -> k - 0x212B, 0x00E5, // ANGSTROM SIGN -> å - 0x017F, 0x0073 // LATIN SMALL LETTER LONG S -> s - ); - private static final Map SPECIAL_SINGLE_CHAR_REVERSE_FOLDS = Map.of( - 0x03BC, 0x00B5, // GREEK SMALL LETTER MU -> MICRO SIGN - 0x006B, 0x212A, // k -> KELVIN SIGN - 0x00E5, 0x212B, // å -> ANGSTROM SIGN - 0x0073, 0x017F // s -> LATIN SMALL LETTER LONG S - ); - - /** - * Expand a code point to include its case variants for case-insensitive matching. - * Only expands special characters that have unusual case folding. - * Returns null if no expansion is needed. - */ - private static String expandCaseFoldInCharClass(int codePoint) { - int folded = UCharacter.foldCase(codePoint, true); - - // Only expand if this is a known special fold character - if (!SPECIAL_SINGLE_CHAR_FOLDS.containsKey(codePoint) - && !SPECIAL_SINGLE_CHAR_REVERSE_FOLDS.containsKey(folded) - && !SPECIAL_SINGLE_CHAR_REVERSE_FOLDS.containsKey(codePoint)) { - return null; - } - - LinkedHashSet variants = new LinkedHashSet<>(); - variants.add(codePoint); - variants.add(folded); - - Integer reverse = SPECIAL_SINGLE_CHAR_REVERSE_FOLDS.get(folded); - if (reverse != null) { - variants.add(reverse); - } - Integer reverse2 = SPECIAL_SINGLE_CHAR_REVERSE_FOLDS.get(codePoint); - if (reverse2 != null) { - variants.add(reverse2); - } - - // Include upper/lower variants of all participating code points - LinkedHashSet expanded = new LinkedHashSet<>(); - for (Integer cp : variants) { - expanded.add(cp); - expanded.add(UCharacter.toLowerCase(cp)); - expanded.add(UCharacter.toUpperCase(cp)); - expanded.add(UCharacter.foldCase(cp, true)); - } - - StringBuilder sb = new StringBuilder(); - for (Integer cp : expanded) { - // Escape special characters in char class - if (cp == '\\' || cp == ']' || cp == '-' || cp == '^') { - sb.append('\\'); - } - sb.appendCodePoint(cp); - } - return sb.toString(); - } - - /** - * Append a code point to a character class StringBuilder, escaping if necessary. - */ - private static void appendCharClassChar(StringBuilder sb, int codePoint) { - // Escape special characters in character class - if (codePoint == '\\' || codePoint == ']' || codePoint == '-' || codePoint == '^' || codePoint == '[') { - sb.append('\\'); - } - sb.appendCodePoint(codePoint); - } -} diff --git a/src/main/java/org/perlonjava/runtime/regex/JavaRegexMatcher.java b/src/main/java/org/perlonjava/runtime/regex/JavaRegexMatcher.java deleted file mode 100644 index 915825eb36..0000000000 --- a/src/main/java/org/perlonjava/runtime/regex/JavaRegexMatcher.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.perlonjava.runtime.regex; - -import java.util.Map; -import java.util.regex.Matcher; - -final class JavaRegexMatcher implements RegexMatcher { - private final Matcher matcher; - JavaRegexMatcher(Matcher matcher) { - this.matcher = matcher; - } - - Matcher unwrap() { - return matcher; - } - - @Override public boolean find() { return matcher.find(); } - @Override public void region(int start, int end) { matcher.region(start, end); } - @Override public void useAnchoringBounds(boolean enabled) { matcher.useAnchoringBounds(enabled); } - @Override public void useTransparentBounds(boolean enabled) { matcher.useTransparentBounds(enabled); } - @Override public int start() { return matcher.start(); } - @Override public int end() { return matcher.end(); } - @Override public int start(int index) { return matcher.start(index); } - @Override public int end(int index) { return matcher.end(index); } - @Override public int start(String name) { return matcher.start(name); } - @Override public int end(String name) { return matcher.end(name); } - @Override public String group(int index) { - return matcher.group(index); - } - @Override public String group(String name) { return matcher.group(name); } - @Override public int groupCount() { return matcher.groupCount(); } - @Override public Map namedGroups() { return matcher.pattern().namedGroups(); } - @Override public String patternDescription() { return matcher.pattern().pattern(); } -} diff --git a/src/main/java/org/perlonjava/runtime/regex/JoniRegexPattern.java b/src/main/java/org/perlonjava/runtime/regex/JoniRegexPattern.java index 6c27d524dc..af5833c562 100644 --- a/src/main/java/org/perlonjava/runtime/regex/JoniRegexPattern.java +++ b/src/main/java/org/perlonjava/runtime/regex/JoniRegexPattern.java @@ -24,10 +24,17 @@ import static org.joni.constants.SyntaxProperties.OP2_OPTION_PERL; import static org.joni.constants.SyntaxProperties.OP2_OPTION_RUBY; import static org.joni.constants.SyntaxProperties.OP2_PLUS_POSSESSIVE_INTERVAL; +import static org.joni.constants.SyntaxProperties.OP3_PERL_LITERAL_OPEN_IN_CC; +import static org.joni.constants.SyntaxProperties.OP_ESC_C_CONTROL; +import static org.joni.constants.SyntaxProperties.OP_POSIX_BRACKET; + +import org.joni.constants.internal.AnchorType; import java.nio.charset.StandardCharsets; +import java.util.ArrayDeque; import java.util.Iterator; import java.util.ArrayList; +import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; import java.util.List; @@ -36,15 +43,17 @@ import org.perlonjava.runtime.operators.WarnDie; import org.perlonjava.runtime.operators.PerlUtfString; import org.perlonjava.runtime.NamedCharacterExpansion; +import org.perlonjava.runtime.NamedCharacterExpansionMap; import org.perlonjava.runtime.runtimetypes.*; -/** - * Stack-based regex backend for Perl constructs that require matcher semantics - * beyond the Java Pattern fast path. - */ +/** Sole production adapter from Perl regex operations to the vendored Joni fork. */ final class JoniRegexPattern { + private static final String NAMED_SEQUENCE_CLASS_WARNING = + "Using just the first character returned by \\N{} in character class"; private static final Map INPUT_ENCODINGS = new WeakHashMap<>(); private static final Map BYTE_INPUT_ENCODINGS = new WeakHashMap<>(); + private static final Map SUBJECT_INPUT_ENCODINGS = + Collections.synchronizedMap(new WeakHashMap<>()); private static final WideScalarCodec PERL_SCALAR_CODEC = new WideScalarCodec() { @Override public byte[] encode(long value, Encoding encoding) { @@ -90,56 +99,65 @@ public Decoded decode(byte[] bytes, int p, int end, Encoding encoding) { // explicitly in toJoniOptions(). Keep the richer Ruby parser surface used // by callouts and control verbs while changing only that default policy. private static final Syntax PERLONJAVA_SYNTAX = new Syntax( - "PERLONJAVA", Syntax.RUBY.op, + "PERLONJAVA", Syntax.RUBY.op | OP_POSIX_BRACKET | OP_ESC_C_CONTROL, (Syntax.RUBY.op2 & ~OP2_OPTION_RUBY) | OP2_OPTION_PERL | OP2_PLUS_POSSESSIVE_INTERVAL | OP2_ESC_H_HORIZONTAL_WHITESPACE, - Syntax.RUBY.op3, + Syntax.RUBY.op3 | OP3_PERL_LITERAL_OPEN_IN_CC, Syntax.RUBY.behavior | ALLOW_MULTIPLEX_DEFINITION_NAME_CALL, Syntax.RUBY.options & ~(Option.ASCII_RANGE | Option.POSIX_BRACKET_ALL_RANGE | Option.WORD_BOUND_ALL_RANGE), Syntax.RUBY.metaCharTable, - JoniRegexPattern::resolveNamedCharacter, - (bytes, p, end, encoding, inCharacterClass) -> - resolveCharacterProperty( - bytes, p, end, encoding, inCharacterClass, false), + null, + propertyResolver(new DeferredPropertyState()), PERL_SCALAR_CODEC); - private static int resolveNamedCharacter(byte[] bytes, int p, int end, - Encoding encoding) { - return UnicodeResolver.getCodePointFromName(new String(bytes, p, end - p, - encoding == ISO8859_1Encoding.INSTANCE - ? StandardCharsets.ISO_8859_1 : StandardCharsets.UTF_8)); - } - static final class NamedCharacterCache { - private final Map expansions = + private final Map expansions = new LinkedHashMap<>(); private final RuntimeScalar translator; NamedCharacterCache() { - this(null); + this((RuntimeScalar) null); } NamedCharacterCache(RuntimeScalar translator) { this.translator = translator == null ? null : new RuntimeScalar(translator); } + NamedCharacterCache(NamedCharacterExpansionMap preResolved) { + this.translator = null; + if (preResolved != null) expansions.putAll(preResolved.expansions()); + } + NamedCharacterExpansion resolve( String name, NamedCharacterExpansion.SourceMode sourceMode) { - return expansions.computeIfAbsent(name, + return expansions.computeIfAbsent(new NamedCharacterExpansionMap.Key(name, sourceMode), ignored -> translator == null ? NamedCharacterExpansion.resolve(name, sourceMode) : NamedCharacterExpansion.resolve(name, translator, sourceMode)); } + + + NamedCharacterExpansionMap snapshot( + NamedCharacterExpansionMap.LiteralIdentity literalIdentity, + NamedCharacterExpansionMap.CallableIdentity callableIdentity) { + return new NamedCharacterExpansionMap( + literalIdentity, callableIdentity, expansions); + } } private static Syntax syntaxForNamedCharacters( NamedCharacterCache cache, NamedCharacterExpansion.SourceMode sourceMode, - boolean caseInsensitive) { + DeferredPropertyState deferredPropertyState) { NamedCharacterResolver resolver = new NamedCharacterResolver() { @Override public int resolve(byte[] bytes, int p, int end, Encoding encoding) { - return resolveNamedCharacter(bytes, p, end, encoding); + int[] sequence = resolveSequence(bytes, p, end, encoding); + if (sequence.length != 1) { + throw new IllegalArgumentException( + "named character resolver requires one code point"); + } + return sequence[0]; } @Override @@ -147,6 +165,10 @@ public int[] resolveSequence(byte[] bytes, int p, int end, Encoding encoding) { String name = new String(bytes, p, end - p, encoding == ISO8859_1Encoding.INSTANCE ? StandardCharsets.ISO_8859_1 : StandardCharsets.UTF_8); + String trimmed = name.strip(); + if (trimmed.regionMatches(true, 0, "U+", 0, 2)) { + name = trimmed; + } NamedCharacterExpansion expansion = cache.resolve(name, sourceMode); if (!expansion.resolved()) { throw new IllegalArgumentException(expansion.diagnostic()); @@ -154,11 +176,7 @@ public int[] resolveSequence(byte[] bytes, int p, int end, Encoding encoding) { return expansion.sequence().codePoints().toArray(); } }; - CharacterPropertyResolver propertyResolver = - (bytes, p, end, encoding, inCharacterClass) -> - resolveCharacterProperty( - bytes, p, end, encoding, inCharacterClass, - caseInsensitive); + CharacterPropertyResolver propertyResolver = propertyResolver(deferredPropertyState); return new Syntax(PERLONJAVA_SYNTAX.name, PERLONJAVA_SYNTAX.op, PERLONJAVA_SYNTAX.op2, PERLONJAVA_SYNTAX.op3, PERLONJAVA_SYNTAX.behavior, PERLONJAVA_SYNTAX.options, @@ -167,6 +185,57 @@ public int[] resolveSequence(byte[] bytes, int p, int end, Encoding encoding) { PERLONJAVA_SYNTAX.wideScalarCodec); } + private static final class DeferredPropertyState { + private boolean deferred; + private boolean userDefined; + } + + private static CharacterPropertyResolver propertyResolver( + DeferredPropertyState deferredPropertyState) { + return new CharacterPropertyResolver() { + @Override + public Result resolve(byte[] bytes, int p, int end, Encoding encoding, + boolean inCharacterClass) { + return resolve(bytes, p, end, encoding, inCharacterClass, + Option.NONE); + } + + @Override + public Result resolve(byte[] bytes, int p, int end, Encoding encoding, + boolean inCharacterClass, int option) { + String property = new String(bytes, p, end - p, + encoding == ISO8859_1Encoding.INSTANCE + ? StandardCharsets.ISO_8859_1 + : StandardCharsets.UTF_8).trim(); + if (property.startsWith("^")) property = property.substring(1).trim(); + boolean userDefined = UnicodeResolver.isUserDefinedPropertyName(property); + if (userDefined) deferredPropertyState.userDefined = true; + + CharacterPropertyResolver.Result resolved = resolveCharacterProperty( + bytes, p, end, encoding, inCharacterClass, + Option.isIgnoreCase(option)); + if (resolved != null) return resolved; + + boolean caseInsensitive = Option.isIgnoreCase(option); + if (userDefined + && UnicodeResolver.mustDeferPotentialUserDefinedProperty( + property, caseInsensitive)) { + deferredPropertyState.deferred = true; + return new Result(new int[] {1, 0, 0x10ffff}, + new long[] {1, 0, Long.MAX_VALUE}, false); + } + return null; + } + + @Override + public boolean isScriptRun(byte[] bytes, int p, int end, Encoding encoding, + WideScalarCodec wideScalarCodec) { + return UnicodeResolver.isPerlScriptRun( + bytes, p, end, encoding, wideScalarCodec); + } + }; + } + private static CharacterPropertyResolver.Result resolveCharacterProperty( byte[] bytes, int p, int end, Encoding encoding, boolean inCharacterClass, boolean caseInsensitive) { @@ -179,11 +248,13 @@ private static CharacterPropertyResolver.Result resolveCharacterProperty( private final Regex regex; private final String sourcePattern; + private final String compatibilityPatternDescription; private final Map namedGroups; private final Map physicalNamedGroups; private final RegexFlags flags; private final boolean hasControlVerbState; private final boolean hasDeferredUserDefinedUnicodeProperty; + private final boolean hasUserDefinedUnicodeProperty; private final boolean byteMode; private final List compileWarnings; @@ -210,16 +281,52 @@ private static CharacterPropertyResolver.Result resolveCharacterProperty( JoniRegexPattern(String perlPattern, RegexFlags flags, int trustedCalloutCount, boolean forceAsciiClasses, boolean byteMode, boolean byteBackedPattern, NamedCharacterCache namedCharacterCache) { + this(perlPattern, flags, trustedCalloutCount, forceAsciiClasses, + byteMode, byteBackedPattern, namedCharacterCache, + forceAsciiClasses || byteMode && byteBackedPattern + ? NamedCharacterExpansion.SourceMode.BYTE + : NamedCharacterExpansion.SourceMode.UNICODE, + false); + } + + JoniRegexPattern(String perlPattern, RegexFlags flags, int trustedCalloutCount, + boolean forceAsciiClasses, boolean byteMode, + boolean byteBackedPattern, NamedCharacterCache namedCharacterCache, + boolean perlReStrict) { + this(perlPattern, flags, trustedCalloutCount, forceAsciiClasses, + byteMode, byteBackedPattern, namedCharacterCache, + forceAsciiClasses || byteMode && byteBackedPattern + ? NamedCharacterExpansion.SourceMode.BYTE + : NamedCharacterExpansion.SourceMode.UNICODE, + perlReStrict); + } + + JoniRegexPattern(String perlPattern, RegexFlags flags, int trustedCalloutCount, + boolean forceAsciiClasses, boolean byteMode, + boolean byteBackedPattern, NamedCharacterCache namedCharacterCache, + NamedCharacterExpansion.SourceMode namedCharacterSourceMode) { + this(perlPattern, flags, trustedCalloutCount, forceAsciiClasses, + byteMode, byteBackedPattern, namedCharacterCache, + namedCharacterSourceMode, false); + } + + JoniRegexPattern(String perlPattern, RegexFlags flags, int trustedCalloutCount, + boolean forceAsciiClasses, boolean byteMode, + boolean byteBackedPattern, NamedCharacterCache namedCharacterCache, + NamedCharacterExpansion.SourceMode namedCharacterSourceMode, + boolean perlReStrict) { PerlSyntaxFeatures syntaxFeatures = analyzePerlSyntax(perlPattern, flags.isExtended()); if (syntaxFeatures.keepInLookaround()) { throw new PerlCompilerException("\\K not permitted in lookahead/lookbehind in regex"); } + validateExtendedPropertyPolicy(perlPattern); this.flags = flags; this.byteMode = byteMode; hasControlVerbState = hasControlVerbState(perlPattern); - UserPropertyTranslation userProperties = translateUserDefinedProperties(perlPattern, flags); - hasDeferredUserDefinedUnicodeProperty = userProperties.deferred(); - sourcePattern = translatePattern(userProperties.pattern(), flags, trustedCalloutCount); + sourcePattern = RuntimeRegexTemplate.materializeTrustedCallouts( + perlPattern, trustedCalloutCount); + compatibilityPatternDescription = legacyCompatibilityDescription( + sourcePattern, flags, trustedCalloutCount); compileWarnings = new ArrayList<>(); java.nio.charset.Charset sourceCharset = byteMode && byteBackedPattern ? StandardCharsets.ISO_8859_1 : StandardCharsets.UTF_8; @@ -234,8 +341,13 @@ public void warn(String message) { public void warn(String message, int bytePosition) { int bounded = Math.max(0, Math.min(bytePosition, bytes.length)); int characterOffset = new String(bytes, 0, bounded, sourceCharset).length(); + WarningDisplay display = message.equals(NAMED_SEQUENCE_CLASS_WARNING) + ? canonicalNamedSequenceWarningDisplay( + sourcePattern, characterOffset, + namedCharacterCache, namedCharacterSourceMode) + : new WarningDisplay(sourcePattern, characterOffset); compileWarnings.add(RegexDiagnosticFormatter.markedPerl( - sourcePattern, characterOffset, message)); + display.pattern(), display.offset(), message)); } @Override @@ -243,23 +355,64 @@ public boolean supportsPositions() { return true; } }; - NamedCharacterExpansion.SourceMode namedCharacterSourceMode = - forceAsciiClasses || byteMode && byteBackedPattern - ? NamedCharacterExpansion.SourceMode.BYTE - : NamedCharacterExpansion.SourceMode.UNICODE; + DeferredPropertyState deferredPropertyState = new DeferredPropertyState(); Syntax syntax = syntaxForNamedCharacters( namedCharacterCache, namedCharacterSourceMode, - flags.isCaseInsensitive()); - int options = toJoniOptions(flags, forceAsciiClasses); + deferredPropertyState); + int options = toJoniOptions(flags, forceAsciiClasses, perlReStrict); if (byteMode && byteBackedPattern) options |= Option.PERL_BYTE_PATTERN; regex = new Regex(bytes, 0, bytes.length, options, byteMode ? ISO8859_1Encoding.INSTANCE : UTF8Encoding.INSTANCE, syntax, warningCollector); + hasDeferredUserDefinedUnicodeProperty = deferredPropertyState.deferred; + hasUserDefinedUnicodeProperty = deferredPropertyState.userDefined; NamedGroupMaps groupMaps = collectNamedGroups(regex); namedGroups = groupMaps.logical(); physicalNamedGroups = groupMaps.physical(); } + private record WarningDisplay(String pattern, int offset) {} + + /** + * Perl renders a named sequence as its canonical U+ list when a character + * class forces the sequence into a single-code-point context. Joni parses + * the source spelling so its warning byte position still refers to the + * original text; replace only the escape ending at that position and move + * the marker by the corresponding character delta. + */ + private static WarningDisplay canonicalNamedSequenceWarningDisplay( + String pattern, int offset, NamedCharacterCache cache, + NamedCharacterExpansion.SourceMode sourceMode) { + int escapeStart = pattern.lastIndexOf("\\N{", Math.max(0, offset - 1)); + if (escapeStart < 0) return new WarningDisplay(pattern, offset); + int nameStart = escapeStart + 3; + int close = pattern.indexOf('}', nameStart); + if (close < 0 || close + 1 != offset) { + return new WarningDisplay(pattern, offset); + } + + String name = pattern.substring(nameStart, close); + NamedCharacterExpansion expansion = cache.resolve(name, sourceMode); + if (!expansion.resolved() + || expansion.sequence().codePointCount( + 0, expansion.sequence().length()) <= 1) { + return new WarningDisplay(pattern, offset); + } + + StringBuilder canonical = new StringBuilder("\\N{U+"); + boolean first = true; + for (int codePoint : expansion.sequence().codePoints().toArray()) { + if (!first) canonical.append('.'); + canonical.append(Integer.toHexString(codePoint).toUpperCase()); + first = false; + } + canonical.append('}'); + String displayPattern = pattern.substring(0, escapeStart) + + canonical + pattern.substring(close + 1); + return new WarningDisplay(displayPattern, + escapeStart + canonical.length()); + } + RegexMatcher matcher(String input, List callbacks) { return matcher(input, callbacks, new RuntimeScalar(input)); } @@ -270,8 +423,52 @@ RegexMatcher matcher(String input, List callbacks, hasControlVerbState, byteMode, input, callbacks, subject); } + Map namedGroups() { + return namedGroups; + } + record InputEncoding(byte[] bytes, int[] charToByte, int[] byteToChar) {} + private record SubjectInputEncodings(Object value, int type, boolean uncheckedOctets, + InputEncoding unicode, InputEncoding bytes) {} + + static InputEncoding inputEncoding(String input, RuntimeScalar subject, boolean byteMode) { + boolean directImmutableString = subject != null + && (subject.type == RuntimeScalarType.STRING + || subject.type == RuntimeScalarType.BYTE_STRING) + && subject.value == input; + if (!directImmutableString) { + return byteMode ? byteInputEncoding(input) : inputEncoding(input); + } + Object value = subject.value; + + synchronized (SUBJECT_INPUT_ENCODINGS) { + SubjectInputEncodings cached = SUBJECT_INPUT_ENCODINGS.get(subject); + if (cached != null && cached.value == value && cached.type == subject.type + && cached.uncheckedOctets == subject.utf8UncheckedOctets) { + InputEncoding encoding = byteMode ? cached.bytes : cached.unicode; + if (encoding != null) return encoding; + } + + InputEncoding unicode = cached != null && cached.value == value + && cached.type == subject.type + && cached.uncheckedOctets == subject.utf8UncheckedOctets + ? cached.unicode : null; + InputEncoding bytes = cached != null && cached.value == value + && cached.type == subject.type + && cached.uncheckedOctets == subject.utf8UncheckedOctets + ? cached.bytes : null; + if (byteMode) { + bytes = buildByteInputEncoding(input); + } else { + unicode = buildInputEncoding(input); + } + SUBJECT_INPUT_ENCODINGS.put(subject, new SubjectInputEncodings( + value, subject.type, subject.utf8UncheckedOctets, unicode, bytes)); + return byteMode ? bytes : unicode; + } + } + static InputEncoding inputEncoding(String input) { synchronized (INPUT_ENCODINGS) { return INPUT_ENCODINGS.computeIfAbsent(input, JoniRegexPattern::buildInputEncoding); @@ -300,13 +497,24 @@ private static InputEncoding buildInputEncoding(String input) { } String patternDescription() { - return sourcePattern; + return compatibilityPatternDescription; } Regex engineRegex() { return regex; } + String optimizerDebugDescription() { + int anchor = regex.getAnchor(); + if ((anchor & AnchorType.ANYCHAR_STAR_ML) != 0) { + return "anchored(SBOL) implicit"; + } + if ((anchor & AnchorType.ANYCHAR_STAR) != 0) { + return "anchored(MBOL) implicit"; + } + return ""; + } + boolean hasOnlyAuthoritativeWideCharacterClasses() { return regex.hasOnlyAuthoritativeWideCharacterClasses(); } @@ -315,141 +523,59 @@ boolean hasDeferredUserDefinedUnicodeProperty() { return hasDeferredUserDefinedUnicodeProperty; } + boolean hasUserDefinedUnicodeProperty() { + return hasUserDefinedUnicodeProperty; + } + List compileWarnings() { return List.copyOf(compileWarnings); } - private record UserPropertyTranslation(String pattern, boolean deferred) {} - - private static UserPropertyTranslation translateUserDefinedProperties( - String pattern, RegexFlags flags) { - StringBuilder translated = new StringBuilder(pattern.length()); - boolean deferred = false; - int extendedClassBracketDepth = 0; - int standardClassBracketDepth = 0; + /** Retains only source policy that the runtime-neutral resolver cannot see. */ + private static void validateExtendedPropertyPolicy(String pattern) { + int extendedDepth = 0; for (int i = 0; i < pattern.length(); i++) { - char ch = pattern.charAt(i); - if (ch == '\\' && i + 1 < pattern.length() && pattern.charAt(i + 1) == '\\') { - translated.append("\\\\"); - i++; - continue; - } - if (extendedClassBracketDepth == 0 && pattern.startsWith("(?[", i)) { - translated.append("(?["); - extendedClassBracketDepth = 1; - i += 2; - continue; - } - if (extendedClassBracketDepth > 0 && ch == '[') { - extendedClassBracketDepth++; - translated.append(ch); - continue; - } - if (extendedClassBracketDepth > 0 && ch == ']') { - extendedClassBracketDepth--; - translated.append(ch); - continue; - } - if (extendedClassBracketDepth == 0 && ch == '[') { - standardClassBracketDepth++; - translated.append(ch); - continue; - } - if (extendedClassBracketDepth == 0 - && standardClassBracketDepth > 0 && ch == ']') { - standardClassBracketDepth--; - translated.append(ch); - continue; - } - if (ch != '\\' || i + 3 >= pattern.length() - || (pattern.charAt(i + 1) != 'p' && pattern.charAt(i + 1) != 'P') - || pattern.charAt(i + 2) != '{') { - if (ch == '\\' && i + 1 < pattern.length()) { - translated.append(pattern, i, i + 2); - i++; - } else { - translated.append(ch); - } - continue; - } - int end = pattern.indexOf('}', i + 3); - if (end < 0) { - translated.append(ch); - continue; - } - String property = pattern.substring(i + 3, end).trim(); - if (property.isEmpty()) { - // Malformed Perl property syntax belongs to Joni's lexer. Do - // not ask the adapter resolver to classify an empty name. - translated.append(pattern, i, end + 1); - i = end; - continue; - } - String unnegated = property.startsWith("^") - ? property.substring(1).trim() : property; - boolean userDefined = UnicodeResolver.isUserDefinedPropertyName(unnegated); - boolean scriptExtensions = unnegated.matches( - "(?i)^(?:scx|script[-_ ]?extensions)\\s*(?:=|:(?!:)).*"); - boolean frontendProperty = unnegated.matches( - "(?i)^(?:script|sc|block|blk|age|in|present[_ ]?in)\\s*(?:=|:(?!:)).*"); - boolean perlBuiltInAlias = UnicodeResolver.isPerlBuiltInPropertyAlias(unnegated); - boolean preserveUserDefined = userDefined - && UnicodeResolver.mustPreserveUserDefinedProperty( - unnegated, flags.isCaseInsensitive()); - boolean joniResolvedProperty = UnicodeResolver.resolveJoniProperty( - unnegated, extendedClassBracketDepth > 0 - || standardClassBracketDepth > 0, - flags.isCaseInsensitive()) != null; - if (joniResolvedProperty && (userDefined - || (!userDefined || perlBuiltInAlias && !preserveUserDefined) - && (frontendProperty || scriptExtensions - || perlBuiltInAlias))) { - translated.append(pattern, i, end + 1); - i = end; - continue; - } - if ((frontendProperty || scriptExtensions || perlBuiltInAlias) - && extendedClassBracketDepth > 0) { - translated.append(pattern, i, end + 1); - i = end; - continue; - } - if ((frontendProperty || scriptExtensions || perlBuiltInAlias) - && standardClassBracketDepth > 0) { - String propertyClass = UnicodeResolver.translateUnicodePropertyForCharClass( - property, pattern.charAt(i + 1) == 'P'); - if (propertyClass.startsWith("[") && propertyClass.endsWith("]")) { - translated.append(propertyClass, 1, propertyClass.length() - 1); - } else { - translated.append(propertyClass); + if (pattern.charAt(i) == '\\') { + if (i + 2 < pattern.length() + && (pattern.charAt(i + 1) == 'p' + || pattern.charAt(i + 1) == 'P') + && pattern.charAt(i + 2) == '{') { + int end = pattern.indexOf('}', i + 3); + if (end < 0) continue; + String property = pattern.substring(i + 3, end).trim(); + if (property.startsWith("^")) { + property = property.substring(1).trim(); + } + if (extendedDepth > 0 + && UnicodeResolver.isPerlStringProperty(property)) { + throw new PerlCompilerException(RegexDiagnosticFormatter.markedPerl( + pattern, end + 1, + "Unicode string properties are not implemented in (?[...])")); + } + if (extendedDepth > 0 + && UnicodeResolver.isUserDefinedPropertyName(property) + && (UnicodeResolver.mustDeferPotentialUserDefinedProperty( + property, false) + || UnicodeResolver.mustDeferPotentialUserDefinedProperty( + property, true))) { + throw new PerlCompilerException( + "Unknown user-defined property name \"" + property + "\""); + } + i = end; + continue; } - i = end; - continue; - } - if (!userDefined && !scriptExtensions && !frontendProperty && !perlBuiltInAlias) { - translated.append(pattern, i, end + 1); - i = end; + if (i + 1 < pattern.length()) i++; continue; } - try { - String propertyClass = UnicodeResolver.translateUnicodeProperty( - property, pattern.charAt(i + 1) == 'P', flags.isCaseInsensitive()); - translated.append("(?-i:") - .append(normalizeGeneratedPropertyClassForJoni(propertyClass)) - .append(')'); - } catch (IllegalArgumentException error) { - String message = error.getMessage(); - if (!userDefined || message != null - && (message.contains("in expansion of") - || message.startsWith("Can't find Unicode property definition"))) { - throw error; - } - translated.append("[\\s\\S]"); - deferred = true; + if (extendedDepth == 0 && pattern.startsWith("(?[", i)) { + extendedDepth = 1; + i += 2; + } else if (extendedDepth > 0 && pattern.charAt(i) == '[') { + extendedDepth++; + } else if (extendedDepth > 0 && pattern.charAt(i) == ']') { + extendedDepth--; } - i = end; } - return new UserPropertyTranslation(translated.toString(), deferred); } /** @@ -478,7 +604,8 @@ private static String normalizeGeneratedPropertyClassForJoni(String propertyClas return normalized.toString(); } - private static int toJoniOptions(RegexFlags flags, boolean forceAsciiClasses) { + private static int toJoniOptions(RegexFlags flags, boolean forceAsciiClasses, + boolean perlReStrict) { int options = Option.NONE; if (flags.isCaseInsensitive()) options |= Option.IGNORECASE; if (flags.isExtended()) options |= Option.EXTEND; @@ -487,7 +614,9 @@ private static int toJoniOptions(RegexFlags flags, boolean forceAsciiClasses) { if (flags.isDotAll()) options |= Option.MULTILINE; if (!flags.isMultiLine()) options |= Option.SINGLELINE; if (flags.isAscii() || forceAsciiClasses) options |= Option.ASCII_RANGE; + if (flags.isAscii()) options |= Option.PERL_EXPLICIT_ASCII; if (flags.isAsciiStrict()) options |= Option.PERL_ASCII_STRICT; + if (perlReStrict) options |= Option.PERL_RE_STRICT; // Ruby/Oniguruma syntax implicitly makes unnamed groups non-capturing // when a pattern also contains named groups. Perl keeps both kinds of // captures numbered. Force that behavior unless /n explicitly disables @@ -513,6 +642,7 @@ static boolean requiresJoniBackend(String pattern, RegexFlags flags) { || syntaxFeatures.asciiStrictPresent() || syntaxFeatures.keepPresent() || syntaxFeatures.lookbehindPresent() + || syntaxFeatures.nativeExtendedClassPresent() || syntaxFeatures.branchResetPresent() || syntaxFeatures.conditionalPresent() || syntaxFeatures.alphaAssertionPresent() @@ -572,6 +702,7 @@ static boolean containsNamedCharacterEscape(String pattern) { private record PerlSyntaxFeatures(boolean keepPresent, boolean keepInLookaround, boolean lookbehindPresent, + boolean nativeExtendedClassPresent, boolean branchResetPresent, boolean conditionalPresent, boolean alphaAssertionPresent, @@ -586,6 +717,7 @@ private static PerlSyntaxFeatures analyzePerlSyntax(String pattern, boolean exte java.util.ArrayDeque groups = new java.util.ArrayDeque<>(); boolean keepPresent = false; boolean lookbehindPresent = false; + boolean nativeExtendedClassPresent = false; boolean branchResetPresent = false; boolean conditionalPresent = false; boolean alphaAssertionPresent = false; @@ -603,7 +735,14 @@ private static PerlSyntaxFeatures analyzePerlSyntax(String pattern, boolean exte } if (extendedClassDepth > 0) { if (ch == '\\' && i + 1 < pattern.length()) { + if (pattern.charAt(i + 1) == 'p' || pattern.charAt(i + 1) == 'P') { + nativeExtendedClassPresent = true; + } i++; + } else if (ch == '[' && i + 1 < pattern.length() + && pattern.charAt(i + 1) == ':') { + nativeExtendedClassPresent = true; + extendedClassDepth++; } else if (ch == '[') { extendedClassDepth++; } else if (ch == ']' && --extendedClassDepth == 0) { @@ -653,7 +792,7 @@ private static PerlSyntaxFeatures analyzePerlSyntax(String pattern, boolean exte } else if (escaped == 'K') { keepPresent = true; if (lookaroundDepth > 0) { - return new PerlSyntaxFeatures(true, true, lookbehindPresent, branchResetPresent, conditionalPresent, + return new PerlSyntaxFeatures(true, true, lookbehindPresent, nativeExtendedClassPresent, branchResetPresent, conditionalPresent, alphaAssertionPresent, asciiStrictPresent); } } @@ -703,7 +842,11 @@ private static PerlSyntaxFeatures analyzePerlSyntax(String pattern, boolean exte || name.equals("negative_lookahead") || name.equals("nlb") || name.equals("negative_lookbehind") - || name.equals("atomic"); + || name.equals("atomic") + || name.equals("script_run") + || name.equals("sr") + || name.equals("atomic_script_run") + || name.equals("asr"); } boolean lookaround = pattern.startsWith("(?=", i) || pattern.startsWith("(?!", i) @@ -718,7 +861,7 @@ private static PerlSyntaxFeatures analyzePerlSyntax(String pattern, boolean exte if (groups.pop()) lookaroundDepth--; } } - return new PerlSyntaxFeatures(keepPresent, false, lookbehindPresent, branchResetPresent, conditionalPresent, + return new PerlSyntaxFeatures(keepPresent, false, lookbehindPresent, nativeExtendedClassPresent, branchResetPresent, conditionalPresent, alphaAssertionPresent, asciiStrictPresent); } @@ -731,6 +874,103 @@ private static boolean hasControlVerbState(String pattern) { || pattern.contains("(*COMMIT"); } + /** + * Test-facing compatibility normalizer. Production patterns retain raw + * {@code \N{...}} source for Joni's resolver; this helper keeps its + * historical one-code-point assertion independent of that native path. + */ + static String translatePattern(String pattern) { + RegexFlags flags = RegexFlags.fromModifiers("", pattern); + return legacyCompatibilityDescription( + translateCompatibilityPattern(pattern, flags), flags, 0); + } + + /** + * Preserves the package-private description contract used by legacy unit + * tests and debug output. Production compilation, matching, warnings, and + * diagnostics use {@link #sourcePattern} unchanged, so this must never feed + * Joni or runtime regex reconstruction. + */ + private static String legacyCompatibilityDescription(String pattern, + RegexFlags flags, + int trustedCalloutCount) { + StringBuilder description = new StringBuilder(pattern.length() + 8); + boolean escaped = false; + boolean inClass = false; + boolean inlineExtendedOption = hasInlineExtendedOption(pattern); + for (int i = 0; i < pattern.length(); i++) { + char ch = pattern.charAt(i); + if (escaped) { + description.append(ch); + escaped = false; + continue; + } + if (ch == '\\' && i + 3 < pattern.length() + && (pattern.charAt(i + 1) == 'p' || pattern.charAt(i + 1) == 'P') + && pattern.charAt(i + 2) == '{') { + int end = pattern.indexOf('}', i + 3); + if (end > i + 3) { + String property = pattern.substring(i + 3, end).trim(); + if (isLegacyAgeWildcard(property)) { + String propertyClass = UnicodeResolver.translateUnicodeProperty( + property, pattern.charAt(i + 1) == 'P', + flags.isCaseInsensitive()); + description.append("(?-i:") + .append(normalizeGeneratedPropertyClassForJoni(propertyClass)) + .append(')'); + i = end; + continue; + } + } + } + if (ch == '\\') { + description.append(ch); + escaped = true; + continue; + } + if (ch == '[') { + inClass = true; + description.append(ch); + continue; + } + if (ch == ']' && inClass) { + inClass = false; + description.append(ch); + continue; + } + if (!inClass && pattern.startsWith("(*:", i)) { + description.append("(*MARK:"); + i += 2; + continue; + } + if (inClass && flags.isExtendedWhitespace() && !inlineExtendedOption + && Character.isWhitespace(ch)) { + continue; + } + if (!inClass && pattern.startsWith("(?)", i)) { + description.append("(?:)"); + i += 2; + continue; + } + if (!inClass && pattern.startsWith("(?{", i) + && !isTrustedCallout(pattern, i, trustedCalloutCount)) { + int end = findCodeBlockEnd(pattern, i); + if (end >= 0) { + description.append("(?:)"); + i = end; + continue; + } + } + description.append(ch); + } + return description.toString(); + } + + private static boolean isLegacyAgeWildcard(String property) { + return property.matches( + "(?is)^(?:age|in|present[-_ ]?in)\\s*(?:=|:(?!:))\\s*:\\\\A.*\\\\z:$"); + } + private static boolean hasInlineExtendedOption(String pattern) { boolean escaped = false; boolean inClass = false; @@ -765,24 +1005,12 @@ private static boolean hasInlineExtendedOption(String pattern) { return false; } - static String translatePattern(String pattern) { - return translatePattern(pattern, RegexFlags.fromModifiers("", pattern), 0, true); - } - - private static String translatePattern(String pattern, RegexFlags flags, - int trustedCalloutCount) { - return translatePattern(pattern, flags, trustedCalloutCount, false); - } - - private static String translatePattern(String pattern, RegexFlags flags, - int trustedCalloutCount, - boolean resolveNamedCharacters) { + private static String translateCompatibilityPattern(String pattern, RegexFlags flags) { StringBuilder out = new StringBuilder(pattern.length() + 16); boolean escaped = false; boolean inClass = false; boolean atClassStart = false; boolean classAllowsLeadingClose = false; - boolean inlineExtendedOption = hasInlineExtendedOption(pattern); int posixClassDepth = 0; for (int i = 0; i < pattern.length(); i++) { char ch = pattern.charAt(i); @@ -796,7 +1024,7 @@ private static String translatePattern(String pattern, RegexFlags flags, atClassStart = false; classAllowsLeadingClose = false; } - if (resolveNamedCharacters && pattern.startsWith("\\N{", i)) { + if (pattern.startsWith("\\N{", i)) { int end = pattern.indexOf('}', i + 3); if (end > i + 3) { int codePoint = UnicodeResolver.getCodePointFromName( @@ -806,22 +1034,6 @@ private static String translatePattern(String pattern, RegexFlags flags, continue; } } - // In Perl, \g{name} is a backreference. Ruby/Oniguruma uses - // \g for a subexpression call and \k for the - // backreference, so passing the brace form through makes Joni - // diagnose it as an invalid subexpression call. Numeric and - // relative brace forms follow the same translation. - if (!inClass && pattern.startsWith("\\g{", i)) { - int end = pattern.indexOf('}', i + 3); - if (end > i + 3) { - String backreference = pattern.substring(i + 3, end); - if (isValidPerlBraceBackreference(backreference)) { - out.append("\\k<").append(backreference).append('>'); - i = end; - continue; - } - } - } out.append(ch); escaped = true; continue; @@ -831,19 +1043,19 @@ private static String translatePattern(String pattern, RegexFlags flags, boolean posixClass = i + 1 < pattern.length() && (pattern.charAt(i + 1) == ':' || pattern.charAt(i + 1) == '.' - || pattern.charAt(i + 1) == '='); + || pattern.charAt(i + 1) == '=') + && !(i + 2 < pattern.length() && pattern.charAt(i + 2) == ']'); if (posixClass) { posixClassDepth++; atClassStart = false; classAllowsLeadingClose = false; out.append(ch); continue; - } else { - out.append("\\["); - atClassStart = false; - classAllowsLeadingClose = false; - continue; } + out.append(ch); + atClassStart = false; + classAllowsLeadingClose = false; + continue; } inClass = true; atClassStart = true; @@ -851,17 +1063,6 @@ private static String translatePattern(String pattern, RegexFlags flags, out.append(ch); continue; } - if (!inClass && pattern.startsWith("(*:", i)) { - // Perl's abbreviated MARK form is (*:NAME). Joni accepts the - // equivalent long spelling and publishes the mark normally. - out.append("(*MARK:"); - i += 2; - continue; - } - if (inClass && flags.isExtendedWhitespace() && !inlineExtendedOption - && Character.isWhitespace(ch)) { - continue; - } if (inClass && atClassStart && ch == '^') { out.append(ch); atClassStart = false; @@ -888,20 +1089,6 @@ private static String translatePattern(String pattern, RegexFlags flags, atClassStart = false; classAllowsLeadingClose = false; } - if (!inClass && pattern.startsWith("(?{", i) - && !isTrustedCallout(pattern, i, trustedCalloutCount)) { - // A callback introduced as text by runtime interpolation has - // no parser-created lexical closure to invoke. Preserve the - // historical compatibility behavior for that unsupported - // case: treat it as a zero-width no-op. Structured callbacks - // remain match-time Joni callouts and are handled below. - int end = findCodeBlockEnd(pattern, i); - if (end >= 0) { - out.append("(?:)"); - i = end; - continue; - } - } if (!inClass && pattern.startsWith("(?[", i)) { int bracketDepth = 0; boolean comment = false; @@ -938,32 +1125,11 @@ private static String translatePattern(String pattern, RegexFlags flags, i = Math.min(end, pattern.length() - 1); continue; } - if (!inClass && pattern.startsWith("(?)", i)) { - out.append("(?:)"); - i += 2; - continue; - } out.append(ch); } return out.toString(); } - private static boolean isValidPerlBraceBackreference(String content) { - if (content.isEmpty()) return false; - int start = content.charAt(0) == '-' ? 1 : 0; - if (start == content.length()) return false; - if (start == 1 || Character.isDigit(content.charAt(0))) { - for (int i = start; i < content.length(); i++) { - if (!Character.isDigit(content.charAt(i))) return false; - } - return true; - } - for (int i = 0; i < content.length(); i++) { - if (Character.isWhitespace(content.charAt(i))) return false; - } - return true; - } - private static void appendResolvedNamedCharacter(StringBuilder out, int codePoint, RegexFlags flags) { boolean extendedSyntax = flags.isExtended() @@ -1016,25 +1182,6 @@ private static int findCodeBlockEnd(String pattern, int offset) { return -1; } - /** - * Joni's Ruby syntax does not understand Java's {@code &&} character-class - * intersection. For an explicitly ASCII-bounded Perl extended class, - * evaluate the already-translated Java class and emit the exact byte set. - */ - private static void appendAsciiClassForJoni(StringBuilder out, String javaClass) { - // Java requires literal closing/opening brackets to be escaped even in - // the leading position accepted by Perl's bracket syntax. - javaClass = javaClass.replace("[^][", "[^\\]\\["); - java.util.regex.Pattern predicate = java.util.regex.Pattern.compile(javaClass); - out.append('['); - for (int value = 0; value < 128; value++) { - if (predicate.matcher(Character.toString((char) value)).matches()) { - out.append(String.format("\\x%02X", value)); - } - } - out.append(']'); - } - private record NamedGroupMaps(Map logical, Map physical) {} @@ -1098,8 +1245,7 @@ private static final class JoniRegexMatcher implements RegexMatcher { this.input = input; this.callbacks = callbacks; this.subject = subject; - InputEncoding encoding = byteMode - ? byteInputEncoding(input) : inputEncoding(input); + InputEncoding encoding = inputEncoding(input, subject, byteMode); this.bytes = encoding.bytes(); this.charToByte = encoding.charToByte(); this.byteToChar = encoding.byteToChar(); @@ -1207,6 +1353,7 @@ public String group(int index) { int begin = index == 0 ? matcher.getBegin() : captures.getBeg(index); int end = index == 0 ? matcher.getEnd() : captures.getEnd(index); if (begin < 0 || end < 0) return null; + if (index == 0 && begin > end) return null; return input.substring(toCharOffset(begin), toCharOffset(end)); } @@ -1358,6 +1505,9 @@ static CaptureSnapshot of(MatchView match) { private boolean executedNestedCallbackPattern; private String failedNestedLastClosedCapture; private String failedNestedLastParenMatch; + private final ArrayDeque callbackMutations = + new ArrayDeque<>(); + private boolean preserveCallbackMutations; PerlCalloutHandler(String input, int[] byteToChar, List callbacks, RegexFlags outerFlags, boolean publishesControlVerbState, @@ -1404,7 +1554,8 @@ public DynamicPatternResult executeDynamic(int id, MatchView match) { } Evaluation evaluation = evaluate(callback, match); RuntimeScalar value = evaluation.result(); - if (value.type == RuntimeScalarType.UNDEF) { + if (value.type == RuntimeScalarType.UNDEF + && callback.uninitializedWarningsEnabled) { WarnDie.warnWithCategory( new RuntimeScalar("Use of uninitialized value"), RuntimeScalarCache.scalarEmptyString, "uninitialized"); @@ -1440,7 +1591,10 @@ public DynamicPatternResult executeDynamic(int id, MatchView match) { nestedCallbacks = runtimeRegex.executableCallbacks; } else { try { - nestedPattern = new JoniRegexPattern(dynamicSource, outerFlags); + boolean byteBackedDynamic = value.type == RuntimeScalarType.BYTE_STRING; + boolean compileAsBytes = byteMode && byteBackedDynamic; + nestedPattern = new JoniRegexPattern(dynamicSource, outerFlags, 0, + compileAsBytes, compileAsBytes, byteBackedDynamic); } catch (SyntaxException exception) { String message = exception.getMessage(); if (message != null && (message.contains("premature end of char-class") @@ -1491,6 +1645,9 @@ private Evaluation evaluate(RuntimeRegexCallback callback, MatchView match) { } } CaptureSnapshot priorDynamicView = previousDynamicView; + if (callback.kind == RuntimeRegexCallback.Kind.BLOCK && parent == null) { + callbackMutations.addLast(RegexCallbackMutationSnapshot.capture(callback.code)); + } MatchView provisional = callback.kind == RuntimeRegexCallback.Kind.DYNAMIC ? dynamicCaptureView(match, priorDynamicView) : match; publishProvisional(provisional); @@ -1563,7 +1720,9 @@ public void unwind(Object value) { @Override public void complete(Object value) { - restore((Token) value, true); + Token token = (Token) value; + if (token.block() && parent == null) preserveCallbackMutations = true; + restore(token, true); } @Override @@ -1582,6 +1741,7 @@ public void finish(boolean matched) { GlobalVariable.getGlobalVariable(GlobalContext.encodeSpecialVar("R")) .set(completedResult); } else if (!matched) { + if (!preserveCallbackMutations) restoreCallbackMutations(); initialRegexState.restore(); if (hasFailedNestedCaptureState) { state.lastClosedCapture = failedNestedLastClosedCapture; @@ -1590,6 +1750,7 @@ public void finish(boolean matched) { } } } finally { + callbackMutations.clear(); DynamicVariableManager.popToLocalLevel(initialLocalLevel); } } @@ -1601,6 +1762,9 @@ private void recordFailedNestedCaptureState(String lastClosed, String lastParen) } void abort() { + // Perl retains ordinary assignments performed before a callback + // exception; only dynamic local() scope is unwound here. + callbackMutations.clear(); DynamicVariableManager.popToLocalLevel(initialLocalLevel); } @@ -1619,6 +1783,12 @@ private void restore(Token token, boolean completed) { } } + private void restoreCallbackMutations() { + while (!callbackMutations.isEmpty()) { + callbackMutations.removeLast().restore(); + } + } + private static MatchView dynamicCaptureView( MatchView current, CaptureSnapshot previous) { CaptureSnapshot adjusted = CaptureSnapshot.of(current); diff --git a/src/main/java/org/perlonjava/runtime/regex/PerlUnicodeScalarNameData.java b/src/main/java/org/perlonjava/runtime/regex/PerlUnicodeScalarNameData.java new file mode 100644 index 0000000000..f60261cf9f --- /dev/null +++ b/src/main/java/org/perlonjava/runtime/regex/PerlUnicodeScalarNameData.java @@ -0,0 +1,152 @@ +/* + * Generated from the current imported Perl unicore/Name.pl. + * Do not edit manually; run dev/tools/generate_perl_unicode_scalar_name_data.pl. + * + * Name.pl is generated by Perl's mktables from the Unicode Character Database. + * Duplicate-name policy matches Perl's anchored table search: the first row wins. + * Distinct names for the same code point are all retained as Unicode aliases. + * + * Unicode data source copyright: + * © 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 + */ +package org.perlonjava.runtime.regex; + +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Base64; + +public final class PerlUnicodeScalarNameData { + public static final String SOURCE_SHA256 = "5ed5a90410345357b3bd3199d15790833d1e0d5b06b6dcf548507671bd78eacd"; + public static final int ENTRY_COUNT = 35079; + public static final int DUPLICATE_NAME_COUNT = 0; + + private static final String[] ENCODED = { + "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s4wFMRgBtIwFMhgBtYwFMxgBtowFNBgBt4wFNRgBuIwFNhgBuYwFNxgBuowFOBgBu4wFORcCvIwFMjAYAb2MBTEYAb6MBTIYAb+MBTMYAcCMBTQYAcGMBTUYAcKMBTYYAcOMBTcYAcSMBTgYAcWMBTkXAsaMBTMwBQvA9QdNSUNBTCBIRUFSVAIEk01DSE9SAgrRT0QgV0lUSCBET1QCCqLpB0dFUiBTWU1CT0wDAqBETEUFDp5TIFdJVEggUyBJTlNJREULCKRTVU5ERVJCQVIDB6DsB1JZIEZBQ0UDCqtCU1RST00gU0lHTgMLp+wHVUlTSEVEIEZBQ0UCAqVMS0gCAZzoB1QDBIiYB0VOTkEHCvbpByBXSVRIIEJBUlMDHsBSSUNMT0NLV0lTRSBDTE9TRUQgQ0lSQ0xFIEFSUk9XDw+zRE9OVE9VUiBJTlRFR1JBTA4ohOoHRE9XTldBUkRTIEFORCBVUFdBUkRTIE9QRU4gQ0lSQ0xFIEFSUk9XUw4T8k9HQVBQRUQgQ0lSQ0xFIEFSUk9XDguRVElOVEVHUkFUSU9ODhG6Q09QRU4gQ0lSQ0xFIEFSUk9XDhS2Q1RPUCBTRU1JQ0lSQ0xFIEFSUk9XDySNV1JJQU5HTEUtSEVBREVEIEJPVFRPTSBVLVNIQVBFRCBBUlJPVx4TjldMRUZUIFUtU0hBUEVEIEFSUk9XHhHvVk9QRU4gQ0lSQ0xFIEFSUk9XHhSMV1JJR0hUIFUtU0hBUEVEIEFSUk9XHhKPV1RPUCBVLVNIQVBFRCBBUlJPVwECnwFQQwIZ+kZMIEZVTkNUSU9OQUwgU1lNQk9MIEFMUEhBGwn2RiBVTkRFUkJBUhYNwEZCQUNLU0xBU0ggQkFSFhDJRkNJUkNMRSBCQUNLU0xBU0gdCeVGRElBRVJFU0lTHQO+RkpPVB0E30ZTVEFSHwO9RklMRR0I3EZVTkRFUkJBUhcI6kZPTU1BIEJBUhYN4kZERUwgRElBRVJFU0lTGgXSRlNUSUxFGgXrRlRJTERFGQjLRlRBIFNUSUxFHAjZRlVOREVSQkFSFw/aRklBTU9ORCBVTkRFUkJBUhcP8UZPV04gQ0FSRVQgVElMREUbCuZGU0hPRSBTVElMRRsIzkZUQUNLIEpPVCAIykZVTkRFUkJBUhoK1kZXQVJEUyBWQU5FFhD3RkVQU0lMT04gVU5ERVJCQVIWFulGR1JFQVRFUi1USEFOIERJQUVSRVNJUxYGtkZJLUJFQU0XA/NGT1RBGgn4RiBVTkRFUkJBUhYN5EZKT1QgRElBRVJFU0lTGgjbRlVOREVSQkFSFg/nRkxFRlQgU0hPRSBTVElMRRoKxUZXQVJEUyBWQU5FFgX1Rk9NRUdBGwn5RiBVTkRFUkJBUhYElUdRVUFEGgrCRiBCQUNLU0xBU0gbBrxGQ0lSQ0xFHATgRk9MT04bA9RGREVMHgLNRlRBHAa6RklBTU9ORB0EuUZWSURFHAnMRk9XTiBDQVJFVB8L10ZXQVJEUyBBUlJPVxsFuEZFUVVBTBsMxEZHUkVBVEVSLVRIQU4bA7tGSk9UGw/HRkxFRlRXQVJEUyBBUlJPVx0Hw0ZTUy1USEFOGwnvRk5PVCBFUVVBTBsI8EZRVUVTVElPThsQyEZSSUdIVFdBUkRTIEFSUk9XGwXBRlNMQVNIGwjTRlVQIENBUkVUHQvQRldBUkRTIEFSUk9XGAjeRk9URSBRVUFEHAjYRlVOREVSQkFSFgP0RlJITxcOxkZJR0hUV0FSRFMgVkFORRYS7kZTRU1JQ09MT04gVU5ERVJCQVIXCL9GTEFTSCBCQVIXCrdGUVVJU0ggUVVBRBcN40ZUQVIgRElBRVJFU0lTGAntRklMRSBUSUxERRYP6EZUSUxERSBESUFFUkVTSVMWDvJGVVAgQ0FSRVQgVElMREUZCN1GU0hPRSBKT1QZDuFGVEFDSyBESUFFUkVTSVMeA9VGSk9UHgfRRk9WRVJCQVIYCs9GV0FSRFMgVkFORRYF7EZaSUxERQIF5FdPTExPTgMHJ1NUUk9QSEUCCr2dB1BMRSBTWU1CT0wEF58BSUNBVElPTiBQUk9HUkFNIENPTU1BTkQDEdBEUk9BQ0hFUyBUSEUgTElNSVQFIsZEWElNQVRFTFkgQlVUIE5PVCBBQ1RVQUxMWSBFUVVBTCBUTw4R8FRFUVVBTCBPUiBFUVVBTCBUTxQCxURUTxYQ0kQgT1IgVEhFIElNQUdFIE9GAQfSTFFVQVJJVVMBGIcRUkFCSUMgQkFTRUxJTkUgUk9VTkQgRE9UCBTQnQRJQkxJQ0FMIEVORCBPRiBWRVJTRQcW/J0EQ09NQklOSU5HIEFMRUYgT1ZFUkxBWQoCjAxNQQgK5RFVUkxZIERBTU1BEgPoEVRBTg0F5BFGQVRIQRID5xFUQU4NBeYRS0FTUkESA+kRVEFOBwXPDERBTU1BDA74/AMgSVNPTEFURUQgRk9STQ0L+fwDTUVESUFMIEZPUk0NCP4RV0lUSCBET1QMA8wMVEFODw7y/AMgSVNPTEFURUQgRk9STQkMjQxURSBTRVBBUkFUT1IIEOsMRUNJTUFMIFNFUEFSQVRPUggT4hFJU1BVVEVEIEVORCBPRiBBWUFICBv7EU9VQkxFIFJJR0hUIEFSUk9XSEVBRCBBQk9WRSMJ/BEgV0lUSCBET1QOEvqdBFZFUlRJQ0FMIEJBUiBCRUxPVw0HnhFEIE1BRERBBxbrDUVNUFRZIENFTlRSRSBISUdIIFNUT1AUCOoNTE9XIFNUT1AICt0NTkQgT0YgQVlBSA4JnQxURVhUIE1BUksHBc4MRkFUSEEMDvb8AyBJU09MQVRFRCBGT1JNDQv3/ANNRURJQUwgRk9STQ0O9RFXSVRIIERPVCBBQk9WRRIE9BFSSU5HEgjeDFRXTyBET1RTDAPLDFRBTg8O8PwDIElTT0xBVEVEIEZPUk0IEO0MSVZFIFBPSU5URUQgU1RBUggOggxPT1ROT1RFIE1BUktFUggI1A1VTEwgU1RPUAcVnxFIQUxGIE1BRERBIE9WRVIgTUFEREEJCdQMTVpBIEFCT1ZFDQXVDEJFTE9XBw7XDElOVkVSVEVEIERBTU1BBwXQDEtBU1JBDA76/AMgSVNPTEFURUQgRk9STQ0L+/wDTUVESUFMIEZPUk0NDvYRV0lUSCBET1QgQkVMT1cMA80MVEFODw70/AMgSVNPTEFURUQgRk9STQcS0RFMQVJHRSBDSVJDTEUgQkVMT1cND84RUk9VTkQgRE9UIEFCT1ZFFwXPEUJFTE9XFxPSEUlOU0lERSBDSVJDTEUgQkVMT1cIE/cRRUZUIEFSUk9XSEVBRCBBQk9WRRYF+RFCRUxPVwkH1Q1UVEVSIEFFDwq7EUZSSUNBTiBGRUgWBL0RTk9PThYDvBFRQUYZFsQRIFdJVEggVEhSRUUgRE9UUyBBQk9WRQ8CuQxJThELyv0DIEZJTkFMIEZPUk0SDMv9A0lOSVRJQUwgRk9STRMMyf0DU09MQVRFRCBGT1JNEgvM/QNNRURJQUwgRk9STRIVoA1XSVRIIFRIUkVFIERPVFMgQUJPVkUiBbMRQkVMT1ciGN4OUE9JTlRJTkcgRE9XTldBUkRTIEFCT1ZFGA3dDldPIERPVFMgQUJPVkUgEN8OVkVSVElDQUxMWSBBQk9WRQ8DpwxMRUYSC479AyBGSU5BTCBGT1JNEw2N/QNJU09MQVRFRCBGT1JNEwfJDE1BS1NVUkEaC/D9AyBGSU5BTCBGT1JNGw3v/QNJU09MQVRFRCBGT1JNEwXxDFdBU0xBGAvR9gMgRklOQUwgRk9STRkN0PYDSVNPTEFURUQgRk9STRQf9RBJVEggQVRUQUNIRUQgQk9UVE9NIFJJR0hUIEtBU1JBMw79ECBBTkQgRE9UIEFCT1ZFOAmAEUxFRlQgUklORyEF8BBGQVRIQSEF9BBLQVNSQSEKghFMRUZUIEhBTVpBJgn4EFJPVU5EIERPVCELgRFSSUdIVCBIQU1aQScJ9xBST1VORCBET1QiDvYQT1VORCBET1QgQUJPVkUrBfkQQkVMT1chD/EQVE9QIFJJR0hUIEZBVEhBMA77ECBBTkQgRE9UIEFCT1ZFNQn+EExFRlQgUklORxgJ+hBET1QgQUJPVkUYJ/QORVhURU5ERUQgQVJBQklDLUlORElDIERJR0lUIFRIUkVFIEFCT1ZFNQjzDldPIEFCT1ZFGAujDEhBTVpBIEFCT1ZFIwuE/QMgRklOQUwgRk9STSQNg/0DSVNPTEFURUQgRk9STR4FpQxCRUxPVyMLiP0DIEZJTkFMIEZPUk0kDYf9A0lTT0xBVEVEIEZPUk0YEvMQTEVGVCBNSURETEUgU1RST0tFGAuiDE1BRERBIEFCT1ZFIwuC/QMgRklOQUwgRk9STSQNgf0DSVNPTEFURUQgRk9STRgT8hBSSUdIVCBNSURETEUgU1RST0tFKw78ECBBTkQgRE9UIEFCT1ZFMAn/EExFRlQgUklORxgQ8gxXQVZZIEhBTVpBIEFCT1ZFIwXzDEJFTE9XDgT7DEJFRUgSC9P2AyBGSU5BTCBGT1JNEwzU9gNJTklUSUFMIEZPUk0UDNL2A1NPTEFURUQgRk9STRML1fYDTUVESUFMIEZPUk0QAagMSBELkP0DIEZJTkFMIEZPUk0SDJH9A0lOSVRJQUwgRk9STRMMj/0DU09MQVRFRCBGT1JNEguS/QNNRURJQUwgRk9STRIj0Q5XSVRIIERPVCBCRUxPVyBBTkQgVEhSRUUgRE9UUyBBQk9WRRcLoRFIQU1aQSBBQk9WRRcW1Q5JTlZFUlRFRCBTTUFMTCBWIEJFTE9XFxC2EVNNQUxMIE1FRU0gQUJPVkUdAdYOVh4GoBEgQkVMT1cXHdAOVEhSRUUgRE9UUyBIT1JJWk9OVEFMTFkgQkVMT1ciFtIOUE9JTlRJTkcgVVBXQVJEUyBCRUxPVzgT0w4gQU5EIFRXTyBET1RTIEFCT1ZFGBvUDldPIERPVFMgQkVMT1cgQU5EIERPVCBBQk9WRRECgA1FSBML2/YDIEZJTkFMIEZPUk0UDNz2A0lOSVRJQUwgRk9STRUM2vYDU09MQVRFRCBGT1JNFAvd9gNNRURJQUwgRk9STQ4DtgxEQUQRC779AyBGSU5BTCBGT1JNEgy//QNJTklUSUFMIEZPUk0TDL39A1NPTEFURUQgRk9STRILwP0DTUVESUFMIEZPUk0SDvsNV0lUSCBET1QgQkVMT1cQA4wNSEFMEwuF9wMgRklOQUwgRk9STRQNhPcDSVNPTEFURUQgRk9STRABrwxMEQuq/QMgRklOQUwgRk9STRINqf0DSVNPTEFURUQgRk9STRIOig1XSVRIIERPVCBCRUxPVyAOiw0gQU5EIFNNQUxMIFRBSBcPkA1GT1VSIERPVFMgQUJPVkUXFtoOSU5WRVJURUQgU01BTEwgViBCRUxPVyAB7g1WFwSJDVJJTkcXGo8NVEhSRUUgRE9UUyBBQk9WRSBET1dOV0FSRFMiBa4RQkVMT1cYGMKdBFdPIERP", + "VFMgVkVSVElDQUxMWSBCRUxPVzAO2Q4gQU5EIFNNQUxMIFRBSA8FjQ1EQUhBTBQLg/cDIEZJTkFMIEZPUk0VDYL3A0lTT0xBVEVEIEZPUk0RAYgNTBILifcDIEZJTkFMIEZPUk0TDYj3A0lTT0xBVEVEIEZPUk0PCu4MT1RMRVNTIEJFSBYDoQ1GRUgWA+8MUUFGDwKODVVMEQuH9wMgRklOQUwgRk9STRINhvcDSVNPTEFURUQgRk9STQ8DhA1ZRUgSC/P2AyBGSU5BTCBGT1JNEwz09gNJTklUSUFMIEZPUk0UDPL2A1NPTEFURUQgRk9STRML9fYDTUVESUFMIEZPUk0OAdANRQ8L5fcDIEZJTkFMIEZPUk0QDOb3A0lOSVRJQUwgRk9STREM5PcDU09MQVRFRCBGT1JNEAvn9wNNRURJQUwgRk9STQ4JzA1GQVJTSSBZRUgXC/33AyBGSU5BTCBGT1JNGAz+9wNJTklUSUFMIEZPUk0ZDPz3A1NPTEFURUQgRk9STRgL//cDTUVESUFMIEZPUk0YK/cOV0lUSCBFWFRFTkRFRCBBUkFCSUMtSU5ESUMgRElHSVQgRk9VUiBCRUxPVzkL9g5USFJFRSBBQk9WRToI9Q5XTyBBQk9WRR0KvQxJTlZFUlRFRCBWHRC/DFRIUkVFIERPVFMgQUJPVkUeDb4MV08gRE9UUyBBQk9WRQ8CwQxFSBEL0v0DIEZJTkFMIEZPUk0SDNP9A0lOSVRJQUwgRk9STRMM0f0DU09MQVRFRCBGT1JNEgvU/QNNRURJQUwgRk9STRIOow1XSVRIIERPVCBCRUxPVyAVpBEgQU5EIFRIUkVFIERPVFMgQUJPVkUbC6INTU9WRUQgQkVMT1cXEKUNVEhSRUUgRE9UUyBCRUxPVyIW4Q5QT0lOVElORyBVUFdBUkRTIEJFTE9XGA3gDldPIERPVFMgQkVMT1cOA68NR0FGEQuT9wMgRklOQUwgRk9STRIMlPcDSU5JVElBTCBGT1JNEwyS9wNTT0xBVEVEIEZPUk0SC5X3A01FRElBTCBGT1JNEhSwEVdJVEggSU5WRVJURUQgU1RST0tFFwSwDVJJTkcXELQNVEhSRUUgRE9UUyBBQk9WRRgNsg1XTyBET1RTIEJFTE9XDwS6DEhBSU4TC879AyBGSU5BTCBGT1JNFAzP/QNJTklUSUFMIEZPUk0VDM39A1NPTEFURUQgRk9STRQL0P0DTUVESUFMIEZPUk0UDvwNV0lUSCBET1QgQkVMT1cZEMMRVEhSRUUgRE9UUyBBQk9WRQ8DyBFSQUYPA7MNVUVIEguX9wMgRklOQUwgRk9STRMMmPcDSU5JVElBTCBGT1JNFAyW9wNTT0xBVEVEIEZPUk0TC5n3A01FRElBTCBGT1JNDgOtDEhBSBELov0DIEZJTkFMIEZPUk0SDKP9A0lOSVRJQUwgRk9STRMMof0DU09MQVRFRCBGT1JNEguk/QNNRURJQUwgRk9STRIr/A5XSVRIIEVYVEVOREVEIEFSQUJJQy1JTkRJQyBESUdJVCBGT1VSIEJFTE9XFwuBDUhBTVpBIEFCT1ZFFxaKEUlOVkVSVEVEIFNNQUxMIFYgQkVMT1cXHfIOU01BTEwgQVJBQklDIExFVFRFUiBUQUggQUJPVkUwC+8OTkQgVFdPIERPVFMvBe4OQkVMT1cXEIUNVEhSRUUgRE9UUyBBQk9WRSIW2A5QT0lOVElORyBVUFdBUkRTIEJFTE9XGA3XDldPIERPVFMgQUJPVkUgDoINVkVSVElDQUwgQUJPVkUQA6EMTVpBEw6A/QMgSVNPTEFURUQgRk9STQ8CxwxFSBEMvg0gRE9BQ0hBU0hNRUUdC6v3AyBGSU5BTCBGT1JNHgys9wNJTklUSUFMIEZPUk0fDKr3A1NPTEFURUQgRk9STR4LrfcDTUVESUFMIEZPUk0SCur9A0ZJTkFMIEZPUk0SBMENR09BTBYLp/cDIEZJTkFMIEZPUk0XDKj3A0lOSVRJQUwgRk9STRgMpvcDU09MQVRFRCBGT1JNFwup9wNNRURJQUwgRk9STRcQwg1XSVRIIEhBTVpBIEFCT1ZFEgzr/QNJTklUSUFMIEZPUk0TDOn9A1NPTEFURUQgRk9STRIL7P0DTUVESUFMIEZPUk0SD/8NV0lUSCBJTlZFUlRFRCBWFwnADVlFSCBBQk9WRSALpfcDIEZJTkFMIEZPUk0hDaT3A0lTT0xBVEVEIEZPUk0PCfQMSUdIIEhBTVpBGAX1DCBBTEVGGQP2DFdBVxkD+AxZRUgOBKwMSkVFTRILnv0DIEZJTkFMIEZPUk0TDJ/9A0lOSVRJQUwgRk9STRQMnf0DU09MQVRFRCBGT1JNEwug/QNNRURJQUwgRk9STRMVxRFXSVRIIFRIUkVFIERPVFMgQUJPVkUjBcYRQkVMT1cZDaIRV08gRE9UUyBBQk9WRRABmA1IEQuL9wMgRklOQUwgRk9STRINivcDSVNPTEFURUQgRk9STQ4DwwxLQUYRC9r9AyBGSU5BTCBGT1JNEgzb/QNJTklUSUFMIEZPUk0TDNn9A1NPTEFURUQgRk9STRIL3P0DTUVESUFMIEZPUk0SDqwNV0lUSCBET1QgQUJPVkUbBbQRQkVMT1cXBKsNUklORxcQrg1USFJFRSBET1RTIEJFTE9XGA3/DldPIERPVFMgQUJPVkUgEMSdBFZFUlRJQ0FMTFkgQkVMT1cQCqAMU0hNSVJJIFlFSA8EqQ1FSEVIEwuP9wMgRklOQUwgRk9STRQMkPcDSU5JVElBTCBGT1JNFQyO9wNTT0xBVEVEIEZPUk0UC5H3A01FRElBTCBGT1JNFA7iDldJVEggRE9UIEFCT1ZFGQfCEVNNQUxMIFYZEOMOVEhSRUUgRE9UUyBBQk9WRSQFvAxCRUxPVyQW5A5QT0lOVElORyBVUFdBUkRTIEJFTE9XGg27DFdPIERPVFMgQUJPVkUiEI0RVkVSVElDQUxMWSBCRUxPVw8DrgxIQUgSC6b9AyBGSU5BTCBGT1JNEwyn/QNJTklUSUFMIEZPUk0UDKX9A1NPTEFURUQgRk9STRMLqP0DTUVESUFMIEZPUk0PCcUNSVJHSElaIE9FGAvh9wMgRklOQUwgRk9STRkN4PcDSVNPTEFURUQgRk9STRYCyQ1ZVRgL4/cDIEZJTkFMIEZPUk0ZDeL3A0lTT0xBVEVEIEZPUk0OA8QMTEFNEQve/QMgRklOQUwgRk9STRIM3/0DSU5JVElBTCBGT1JNEwzd/QNTT0xBVEVEIEZPUk0SC+D9A01FRElBTCBGT1JNEgjqDldJVEggQkFSFwm2DURPVCBBQk9WRRkIphFVQkxFIEJBUhcdxxFTTUFMTCBBUkFCSUMgTEVUVEVSIFRBSCBBQk9WRR0BtQ1WFxC3DVRIUkVFIERPVFMgQUJPVkUiBbgNQkVMT1cPB60RT1cgQUxFRg4EnAxNQVJLDwPFDEVFTRIL4v0DIEZJTkFMIEZPUk0TDOP9A0lOSVRJQUwgRk9STRQM4f0DU09MQVRFRCBGT1JNEwvk/QNNRURJQUwgRk9STRMO5Q5XSVRIIERPVCBBQk9WRRwF5g5CRUxPVxgQpxFUSFJFRSBET1RTIEFCT1ZFDgKtDU5HEAvU9wMgRklOQUwgRk9STREM1fcDSU5JVElBTCBGT1JNEgzT9wNTT0xBVEVEIEZPUk0RC9b3A01FRElBTCBGT1JNEAOxDU9FSBMLm/cDIEZJTkFMIEZPUk0UDJz3A0lOSVRJQUwgRk9STRUMmvcDU09MQVRFRCBGT1JNFAud9wNNRURJQUwgRk9STQ8DxgxPT04SC+b9AyBGSU5BTCBGT1JNEwa6DUdIVU5OQRkLn/cDIEZJTkFMIEZPUk0aDZ73A0lTT0xBVEVEIEZPUk0TDOf9A0lOSVRJQUwgRk9STRQM5f0DU09MQVRFRCBGT1JNEwvo/QNNRURJQUwgRk9STRMOuQ1XSVRIIERPVCBCRUxPVxgQiRFJTlZFUlRFRCBTTUFMTCBWGAS8DVJJTkccBo8RIEFCT1ZFGAnoDlNNQUxMIFRBSB4B6Q5WGBC9DVRIUkVFIERPVFMgQUJPVkUZDecOV08gRE9UUyBCRUxPVw8Dgw1ZRUgSC/f2AyBGSU5BTCBGT1JNEwz49gNJTklUSUFMIEZPUk0UDPb2A1NPTEFURUQgRk9STRML+fYDTUVESUFMIEZPUk0OAsYNT0UQC9r3AyBGSU5BTCBGT1JNEQ3Z9wNJU09MQVRFRCBGT1JNDgP+DFBFSBEL1/YDIEZJTkFMIEZPUk0SDNj2A0lOSVRJQUwgRk9STRMM1vYDU09MQVRFRCBGT1JNEgvZ9gNNRURJQUwgRk9STRIVtxFXSVRIIFNNQUxMIE1FRU0gQUJPVkUdAb4RVhECpg1FSBML7/YDIEZJTkFMIEZPUk0UDPD2A0lOSVRJQUwgRk9STRUM7vYDU09MQVRFRCBGT1JNFAvx9gNNRURJQUwgRk9STQ4DwgxRQUYRC9b9AyBGSU5BTCBGT1JNEgzX/QNJTklUSUFMIEZPUk0TDNX9A1NPTEFURUQgRk9STRIL2P0DTUVESUFMIEZPUk0SDqcNV0lUSCBET1QgQUJPVkUbBaURQkVMT1cgErURIEFORCBOTyBET1RTIEFCT1ZFFxCoDVRIUkVFIERPVFMgQUJPVkUOA7EMUkVIEQuu/QMgRklOQUwgRk9STRINrf0DSVNPTEFURUQgRk9STRIOlA1XSVRIIERPVCBCRUxPVyAOlg0gQU5EIERPVCBBQk9WRRcPmQ1GT1VSIERPVFMgQUJPVkUXC+wOSEFNWkEgQUJPVkUXCu8NSU5WRVJURUQgVhcEqhFMT09QFwSTDVJJTkcXJPEOU01BTEwgQVJBQklDIExFVFRFUiBUQUggQU5EIFRXTyBET1RTHQq5EU5PT04gQUJPVkUdAZINVh4GlQ0gQkVMT1cYBdsOVFJPS0UXDpcNVFdPIERPVFMgQUJPVkUgEOsOVkVSVElDQUxMWSBBQk9WRQ8Euw1OT09OEwuh9wMgRklOQUwgRk9STRQMovcDSU5JVElBTCBGT1JNFQyg9wNTT0xBVEVEIEZPUk0UC6P3A01FRElBTCBGT1JNDwusEU9ISU5HWUEgWUVIDwORDVJFSBILjfcDIEZJTkFMIEZPUk0TDYz3A0lTT0xBVEVEIEZPUk0OA7UMU0FEEQu6/QMgRklOQUwgRk9STRIMu/0DSU5JVElBTCBGT1JNEwy5/QNTT0xBVEVEIEZPUk0SC7z9A01FRElBTCBGT1JNEhWeDVdJVEggVEhSRUUgRE9UUyBBQk9WRSIFrxFCRUxPVxgNnQ1XTyBET1RTIEJFTE9XDwOzDEVFThILsv0DIEZJTkFMIEZPUk0TDLP9A0lOSVRJQUwgRk9STRQMsf0DU09MQVRFRCBGT1JNEwu0/QNNRURJQUwgRk9STRMcmg1XSVRIIERPVCBCRUxPVyBBTkQgRE9UIEFCT1ZFGCb9DkVYVEVOREVEIEFSQUJJQy1JTkRJQyBESUdJVCBGT1VSIEFCT1ZFGA/cDkZPVVIgRE9UUyBBQk9WRRgK/g5JTlZFUlRFRCBWGCTwDlNNQUxMIEFSQUJJQyBMRVRURVIgVEFIIEFORCBUV08gRE9UUxgQmw1USFJFRSBET1RTIEJFTE9XKBWcDSBBTkQgVEhSRUUgRE9UUyBBQk9WRRkY7Q5XTyBET1RTIFZFUlRJQ0FMTFkgQUJPVkUPBLQMSEVFThMLtv0DIEZJTkFMIEZPUk0UDLf9A0lOSVRJQUwgRk9STRUMtf0DU09MQVRFRCBGT1JNFAu4/QNNRURJQUwgRk9STRQO+g1XSVRIIERPVCBCRUxPVw8LsRFUUkFJR0hUIFdBVw8P8AxVUEVSU0NSSVBUIEFMRUYPCKoNV0FTSCBLQUYOA7cMVEFIEQvC/QMgRklOQUwgRk9STRIMw/0DSU5JVElBTCBGT1JNEwzB/QNTT0xBVEVEIEZPUk0SC8T9A01FRElBTCBGT1JNEg6LEVdJVEggRE9UIEJFTE9XFxCfDVRIUkVFIERPVFMgQUJPVkUiBYwRQkVMT1cYDaMRV08gRE9UUyBBQk9WRSAQw50EVkVSVElDQUxMWSBCRUxPVw8Ehg1DSEVIEwv79gMgRklOQUwgRk9STRQM/PYDSU5JVElBTCBGT1JNFQz69gNTT0xBVEVEIEZPUk0UC/32A01FRElBTCBGT1JNFA6/DVdJVEggRE9UIEFCT1ZFGQfBEVNNQUxMIFYTAocNRUgVC//2AyBGSU5BTCBGT1JNFgyA9wNJTklUSUFMIEZPUk0XDP72A1NPTEFURUQgRk9STRYLgfcDTUVESUFMIEZPUk0PAqoMRUgRC5b9AyBGSU5BTCBGT1JNEgyX/QNJTklUSUFMIEZPUk0TDJX9A1NPTEFURUQgRk9STRIHqQxNQVJCVVRBGQuU/QMgRklOQUwgRk9STRoEww1HT0FMGg2T/QNJU09MQVRFRCBGT1JNEwqY/QNFRElBTCBGT1JNEgn8DFdJVEggUklORxcPuBFTTUFMTCBURUggQUJPVkUdAb8RVhca/QxUSFJFRSBET1RTIEFCT1ZFIERPV05XQVJEUxEC/wxFSBML4/YDIEZJTkFMIEZPUk0UDOT2A0lOSVRJQUwgRk9STRUM4vYDU09MQVRFRCBGT1JNFAvl9gNNRURJQUwgRk9STQ8DsAxIQUwSC6z9AyBGSU5BTCBGT1JNEw2r/QNJU09MQVRFRCBGT1JNEAKrDEVIEgua/QMgRklOQUwgRk9STRMMm/0DSU5JVElBTCBGT1JNFAyZ/QNTT0xBVEVEIEZPUk0TC5z9A01FRElBTCBGT1JNEAfGnQRJTiBOT09OEwOGEVlFSA8D+QxURUgSC+f2AyBGSU5BTCBGT1JNEwzo9gNJTklUSUFMIEZPUk0UDOb2A1NPTEFURUQgRk9STRML6fYDTUVESUFMIEZPUk0TDMARV0lUSCBTTUFMTCBWEgL6DEVIFAvf9gMgRklOQUwgRk9STRUM4PYDSU5JVElBTCBGT1JNFgze9gNTT0xBVEVEIEZPUk0VC+H2A01FRElBTCBGT1JNDgHHDVUPC9j3AyBGSU5BTCBGT1JNEA3X9wNJU09MQVRFRCBGT1JNEBD3DFdJVEggSEFNWkEgQUJPVkUgDt33AyBJU09MQVRFRCBGT1JNDy7o9wNJR0hVUiBLQVpBS0ggS0lSR0hJWiBBTEVGIE1BS1NVUkEgSU5JVElBTCBGT1JNMQvp9wNNRURJQUwgRk9STQ4Cyw1WRRAL3/cDIEZJTkFMIEZPUk0RDd73A0lTT0xBVEVEIEZPUk0QAaQNSBEL6/YDIEZJTkFMIEZPUk0SDOz2A0lOSVRJQUwgRk9STRMM6vYDU09MQVRFRCBGT1JNEgvt9gNNRURJQUwgRk9STQ4DyAxXQVcRC+79AyBGSU5BTCBGT1JNEg3t/QNJU09MQVRFRCBGT1JNEg7PDVdJVEggRE9UIEFCT1ZFGwarEVdJVEhJThcn+Q5FWFRFTkRFRCBBUkFCSUMtSU5ESUMgRElHSVQgVEhSRUUgQUJPVkU0CPgOV08gQUJPVkUXC6QMSEFNWkEgQUJPVkUiC4b9AyBGSU5BTCBGT1JNIw2F/QNJU09MQVRFRCBGT1JNFwTEDVJJTkcXDsoNVFdPIERPVFMgQUJPVkUOA8oMWUVIEQfSDSBCQVJSRUUYC6/3AyBGSU5BTCBGT1JNGQ2u9wNJU09MQVRFRCBGT1JNGSz7DldJVEggRVhURU5ERUQgQVJBQklDLUlORElDIERJR0lUIFRIUkVFIEFCT1ZFOwj6DldPIEFCT1ZFHgvTDUhBTVpBIEFCT1ZFKQux9wMgRklOQUwgRk9STSoNsPcDSVNPTEFURUQgRk9S", + "TRIK8v0DRklOQUwgRk9STRIM8/0DSU5JVElBTCBGT1JNEwzx/QNTT0xBVEVEIEZPUk0SC/T9A01FRElBTCBGT1JNEhTHnQRXSVRIIEZPVVIgRE9UUyBCRUxPVxcLpgxIQU1aQSBBQk9WRSILiv0DIEZJTkFMIEZPUk0jDIv9A0lOSVRJQUwgRk9STSQMif0DU09MQVRFRCBGT1JNIwuM/QNNRURJQUwgRk9STRcHzg1TTUFMTCBWFwTNDVRBSUwYD9ENSFJFRSBET1RTIEJFTE9XGBupEVdPIERPVFMgQkVMT1cgQU5EIERPVCBBQk9WRSoLqBFIQU1aQSBBQk9WRSoQuhFTTUFMTCBOT09OIEFCT1ZFDwHIDVUQC9z3AyBGSU5BTCBGT1JNEQ3b9wNJU09MQVRFRCBGT1JNDgO4DFpBSBELxv0DIEZJTkFMIEZPUk0SDMf9A0lOSVRJQUwgRk9STRMMxf0DU09MQVRFRCBGT1JNEgvI/QNNRURJQUwgRk9STRACsgxJThILsP0DIEZJTkFMIEZPUk0TDa/9A0lTT0xBVEVEIEZPUk0TFbIRV0lUSCBJTlZFUlRFRCBWIEFCT1ZFCCiT+gNJR0FUVVJFIEFJTiBXSVRIIEFMRUYgTUFLU1VSQSBGSU5BTCBGT1JNJg33+QNJU09MQVRFRCBGT1JNGRG6+QNKRUVNIElOSVRJQUwgRk9STR8MqfgDU09MQVRFRCBGT1JNHhT1+gNXSVRIIE1FRU0gRklOQUwgRk9STSgMxPsDSU5JVElBTCBGT1JNGRG7+QNNRUVNIElOSVRJQUwgRk9STR8MqvgDU09MQVRFRCBGT1JNHhz4+gNXSVRIIEFMRUYgTUFLU1VSQSBGSU5BTCBGT1JNIw/2+gNNRUVNIEZJTkFMIEZPUk0oDPf6A0lOSVRJQUwgRk9STSMOtvsDWUVIIEZJTkFMIEZPUk0ZDpT6A1lFSCBGSU5BTCBGT1JNHQ34+QNJU09MQVRFRCBGT1JNESHR9wNKSkFMIEFMTEFBSFUgRkFSQUpBSFUgQVNILVNIQVJFRUYeHM37A1RBQUFMQUEgRkFSQUpBSFUgQVNILVNIQVJFRUYREvP7A0tCQVIgSVNPTEFURUQgRk9STREQzfoDTEFZSEFBIEFTLVNBTEFBTSAN0Z0EVFUgV0FTLVNBTEFBTRUP9/sDRSBJU09MQVRFRCBGT1JNFQvS9wNJIEFSLVJBSE1BSBgIx/oDUy1TQUxBQU0fDcr6A1RVIFdBUy1TQUxBQU0WC8j6A00gQVMtU0FMQUFNIA3SnQRUVSBXQVMtU0FMQUFNFwzJ+gNBQSBBUy1TQUxBQU0iDdOdBFRVIFdBUy1TQUxBQU0SK5D5A0VGIE1BS1NVUkEgV0lUSCBTVVBFUlNDUklQVCBBTEVGIEZJTkFMIEZPUk0zDd34A0lTT0xBVEVEIEZPUk0VGLz6A1dJVEggRkFUSEFUQU4gRklOQUwgRk9STSMNvfoDSVNPTEFURUQgRk9STRIR8vsDTEFIIElTT0xBVEVEIEZPUk0RC//7A1paQSBXQSBKQUxMECDu+ANCRUggV0lUSCBBTEVGIE1BS1NVUkEgRklOQUwgRk9STSYNifgDSVNPTEFURUQgRk9STRkQnfkDSEFIIElOSVRJQUwgRk9STR4MhvgDU09MQVRFRCBGT1JNHRPC+wNXSVRIIFlFSCBGSU5BTCBGT1JNGg+g+QNFSCBJTklUSUFMIEZPUk0dC+L5A01FRElBTCBGT1JNGRGc+QNKRUVNIElOSVRJQUwgRk9STR8MhfgDU09MQVRFRCBGT1JNGRGe+QNLSEFIIElOSVRJQUwgRk9STR8Mh/gDU09MQVRFRCBGT1JNHhOe+wNXSVRIIFlFSCBGSU5BTCBGT1JNGQ/s+ANNRUVNIEZJTkFMIEZPUk0eDJ/5A0lOSVRJQUwgRk9STR8MiPgDU09MQVRFRCBGT1JNHgvh+QNNRURJQUwgRk9STRkP7fgDTk9PTiBGSU5BTCBGT1JNGQ7q+ANSRUggRklOQUwgRk9STRkO7/gDWUVIIEZJTkFMIEZPUk0dDYr4A0lTT0xBVEVEIEZPUk0ZD+v4A1pBSU4gRklOQUwgRk9STREc/fsDSVNNSUxMQUggQVItUkFITUFOIEFSLVJBSEVFTRATxPcDREFBTUFUIEJBUkFLQUFUVUhVTRIeo/oDRCBXSVRIIEFMRUYgTUFLU1VSQSBGSU5BTCBGT1JNJg2H+gNJU09MQVRFRCBGT1JNGRC1+QNIQUggSU5JVElBTCBGT1JNHgyj+ANTT0xBVEVEIEZPUk0dHO76A1dJVEggQUxFRiBNQUtTVVJBIEZJTkFMIEZPUk0iDqv7A1lFSCBGSU5BTCBGT1JNGRG0+QNKRUVNIElOSVRJQUwgRk9STR8MovgDU09MQVRFRCBGT1JNGRG2+QNLSEFIIElOSVRJQUwgRk9STR8MpPgDU09MQVRFRCBGT1JNHhTv+gNXSVRIIE1FRU0gRklOQUwgRk9STSgM8PoDSU5JVElBTCBGT1JNGRG3+QNNRUVNIElOSVRJQUwgRk9STR8MpfgDU09MQVRFRCBGT1JNGQ6s+gNSRUggRklOQUwgRk9STR0NkPoDSVNPTEFURUQgRk9STRkOpPoDWUVIIEZJTkFMIEZPUk0dDYj6A0lTT0xBVEVEIEZPUk0QIPz4A0ZFSCBXSVRIIEFMRUYgTUFLU1VSQSBGSU5BTCBGT1JNJg2x+ANJU09MQVRFRCBGT1JNGRC/+QNIQUggSU5JVElBTCBGT1JNHgyu+ANTT0xBVEVEIEZPUk0ZEb75A0pFRU0gSU5JVElBTCBGT1JNHwyt+ANTT0xBVEVEIEZPUk0ZEcD5A0tIQUggSU5JVElBTCBGT1JNHwyv+ANTT0xBVEVEIEZPUk0eFPz6A1dJVEggTUVFTSBGSU5BTCBGT1JNKAz9+gNJTklUSUFMIEZPUk0ZEcH5A01FRU0gSU5JVElBTCBGT1JNHwyw+ANTT0xBVEVEIEZPUk0eE8H7A1dJVEggWUVIIEZJTkFMIEZPUk0ZDv34A1lFSCBGSU5BTCBGT1JNHQ2y+ANJU09MQVRFRCBGT1JNECKV+gNHSEFJTiBXSVRIIEFMRUYgTUFLU1VSQSBGSU5BTCBGT1JNKA35+QNJU09MQVRFRCBGT1JNGxG8+QNKRUVNIElOSVRJQUwgRk9STSEMq/gDU09MQVRFRCBGT1JNGxG9+QNNRUVNIElOSVRJQUwgRk9STSEMrPgDU09MQVRFRCBGT1JNIBz7+gNXSVRIIEFMRUYgTUFLU1VSQSBGSU5BTCBGT1JNJQ/5+gNNRUVNIEZJTkFMIEZPUk0lDvr6A1lFSCBGSU5BTCBGT1JNGw6W+gNZRUggRklOQUwgRk9STR8N+vkDSVNPTEFURUQgRk9STRAPzPcDSEFGSVpBSFUgQUxMQUFIHwnN9wNVIFRBQUFMQUEYEc73A00gQUxMQUFIVSBUQUFBTEFBGRLP9wNBQSBBTExBQUhVIFRBQUFMQUESHpv6A0ggV0lUSCBBTEVGIE1BS1NVUkEgRklOQUwgRk9STSYN//kDSVNPTEFURUQgRk9STRkRqfkDSkVFTSBJTklUSUFMIEZPUk0fDJf4A1NPTEFURUQgRk9STR4Tv/sDV0lUSCBZRUggRklOQUwgRk9STRkRqvkDTUVFTSBJTklUSUFMIEZPUk0fDJj4A1NPTEFURUQgRk9STR4c2/oDV0lUSCBBTEVGIE1BS1NVUkEgRklOQUwgRk9STSMO2voDWUVIIEZJTkFMIEZPUk0ZDpz6A1lFSCBGSU5BTCBGT1JNHQ2A+gNJU09MQVRFRCBGT1JNESLT+ANFSCBXSVRIIEFMRUYgTUFLU1VSQSBJU09MQVRFRCBGT1JNGRHX+QNKRUVNIElOSVRJQUwgRk9STR8M0fgDU09MQVRFRCBGT1JNGRHY+QNNRUVNIElOSVRJQUwgRk9STR8M0vgDU09MQVRFRCBGT1JNHhaT+wNXSVRIIEpFRU0gSU5JVElBTCBGT1JNIxGU+wNNRUVNIElOSVRJQUwgRk9STRkd2fkDU1VQRVJTQ1JJUFQgQUxFRiBJTklUSUFMIEZPUk0ZEdT4A1lFSCBJU09MQVRFRCBGT1JNEA3D9wNKQUxMQSBXQS1BTEFBFQr7+wNKQUxBTE9VSE9VESCd+gNFRU0gV0lUSCBBTEVGIE1BS1NVUkEgRklOQUwgRk9STScNgfoDSVNPTEFURUQgRk9STRoQp/kDSEFIIElOSVRJQUwgRk9STR8MlfgDU09MQVRFRCBGT1JNHhym+wNXSVRIIEFMRUYgTUFLU1VSQSBGSU5BTCBGT1JNIw6++wNZRUggRklOQUwgRk9STRoRqPkDTUVFTSBJTklUSUFMIEZPUk0gDJb4A1NPTEFURUQgRk9STR8cp/sDV0lUSCBBTEVGIE1BS1NVUkEgRklOQUwgRk9STSQO2PoDSEFIIEZJTkFMIEZPUk0oDNn6A0lOSVRJQUwgRk9STSQOpfsDWUVIIEZJTkFMIEZPUk0aDp76A1lFSCBGSU5BTCBGT1JNHg2C+gNJU09MQVRFRCBGT1JNEBiA+QNLQUYgV0lUSCBBTEVGIEZJTkFMIEZPUk0eDbf4A0lTT0xBVEVEIEZPUk0eEoP5A01BS1NVUkEgRklOQUwgRk9STSYNvfgDSVNPTEFURUQgRk9STRkQxfkDSEFIIElOSVRJQUwgRk9STR4MufgDU09MQVRFRCBGT1JNGRHE+QNKRUVNIElOSVRJQUwgRk9STR8MuPgDU09MQVRFRCBGT1JNGRHG+QNLSEFIIElOSVRJQUwgRk9STR8MuvgDU09MQVRFRCBGT1JNGQ6B+QNMQU0gRklOQUwgRk9STR0Mx/kDSU5JVElBTCBGT1JNHgy7+ANTT0xBVEVEIEZPUk0dC+v5A01FRElBTCBGT1JNGQ+C+QNNRUVNIEZJTkFMIEZPUk0eDMj5A0lOSVRJQUwgRk9STR8MvPgDU09MQVRFRCBGT1JNHgvs+QNNRURJQUwgRk9STR4Uu/sDV0lUSCBNRUVNIEZJTkFMIEZPUk0oDMP7A0lOSVRJQUwgRk9STSMOt/sDWUVIIEZJTkFMIEZPUk0ZDoT5A1lFSCBGSU5BTCBGT1JNHQ2++ANJU09MQVRFRCBGT1JNEhTO+wNSUkFNQSBBTExBQUhVIFdBSkhBSBEgn/oDSEFIIFdJVEggQUxFRiBNQUtTVVJBIEZJTkFMIEZPUk0nDYP6A0lTT0xBVEVEIEZPUk0aEZr4A0hBSCBJU09MQVRFRCBGT1JNGhGr+QNKRUVNIElOSVRJQUwgRk9STSAMmfgDU09MQVRFRCBGT1JNGhGs+QNNRUVNIElOSVRJQUwgRk9STSAMm/gDU09MQVRFRCBGT1JNGg6g+gNZRUggRklOQUwgRk9STR4NhPoDSVNPTEFURUQgRk9STRAY/P0DTEFNIFdJVEggQUxFRiBGSU5BTCBGT1JNHg37/QNJU09MQVRFRCBGT1JNHhKG+QNNQUtTVVJBIEZJTkFMIEZPUk0mDcP4A0lTT0xBVEVEIEZPUk0eG/j9A1dJVEggSEFNWkEgQUJPVkUgRklOQUwgRk9STS8N9/0DSVNPTEFURUQgRk9STSkQ+v0DQkVMT1cgRklOQUwgRk9STS8N+f0DSVNPTEFURUQgRk9STSMW9v0DTUFEREEgQUJPVkUgRklOQUwgRk9STS8N9f0DSVNPTEFURUQgRk9STRkQyvkDSEFIIElOSVRJQUwgRk9STR4MwPgDU09MQVRFRCBGT1JNHRyC+wNXSVRIIEFMRUYgTUFLU1VSQSBGSU5BTCBGT1JNIg+A+wNNRUVNIEZJTkFMIEZPUk0nDLX7A0lOSVRJQUwgRk9STSIOgfsDWUVIIEZJTkFMIEZPUk0aD835A0VIIElOSVRJQUwgRk9STRkRyfkDSkVFTSBJTklUSUFMIEZPUk0fDL/4A1NPTEFURUQgRk9STR4UhPsDV0lUSCBKRUVNIEZJTkFMIEZPUk0oDIP7A0lOSVRJQUwgRk9STSMPvPsDTUVFTSBGSU5BTCBGT1JNKAy6+wNJTklUSUFMIEZPUk0jDqz7A1lFSCBGSU5BTCBGT1JNGRHL+QNLSEFIIElOSVRJQUwgRk9STR8MwfgDU09MQVRFRCBGT1JNHhSF+wNXSVRIIE1FRU0gRklOQUwgRk9STSgMhvsDSU5JVElBTCBGT1JNGQ+F+QNNRUVNIEZJTkFMIEZPUk0eDMz5A0lOSVRJQUwgRk9STR8MwvgDU09MQVRFRCBGT1JNHgvt+QNNRURJQUwgRk9STR4Th/sDV0lUSCBIQUggRklOQUwgRk9STScMiPsDSU5JVElBTCBGT1JNIw6t+wNZRUggRklOQUwgRk9STRkOh/kDWUVIIEZJTkFMIEZPUk0dDcT4A0lTT0xBVEVEIEZPUk0QGYj5A01FRU0gV0lUSCBBTEVGIEZJTkFMIEZPUk0fFcn4A01BS1NVUkEgSVNPTEFURUQgRk9STRoQz/kDSEFIIElOSVRJQUwgRk9STR8MxvgDU09MQVRFRCBGT1JNHhaJ+wNXSVRIIEpFRU0gSU5JVElBTCBGT1JNIxGK+wNNRUVNIElOSVRJQUwgRk9STSMOi/sDWUVIIEZJTkFMIEZPUk0aEc75A0pFRU0gSU5JVElBTCBGT1JNIAzF+ANTT0xBVEVEIEZPUk0fFYz7A1dJVEggSEFIIElOSVRJQUwgRk9STSQRkvsDS0hBSCBJTklUSUFMIEZPUk0kEY37A01FRU0gSU5JVElBTCBGT1JNJA7A+wNZRUggRklOQUwgRk9STRoR0PkDS0hBSCBJTklUSUFMIEZPUk0gDMf4A1NPTEFURUQgRk9STR8WjvsDV0lUSCBKRUVNIElOSVRJQUwgRk9STSQRj/sDTUVFTSBJTklUSUFMIEZPUk0kDrn7A1lFSCBGSU5BTCBGT1JNGg+J+QNNRUVNIEZJTkFMIEZPUk0fDNH5A0lOSVRJQUwgRk9STSAMyPgDU09MQVRFRCBGT1JNHxOx+wNXSVRIIFlFSCBGSU5BTCBGT1JNGhHK+ANZRUggSVNPTEFURUQgRk9STREV9PsDT0hBTU1BRCBJU09MQVRFRCBGT1JNEBjYnQROQVdXQVJBIEFMTEFBSFUgTUFSUUFEQUgRII75A09PTiBXSVRIIEFMRUYgTUFLU1VSQSBGSU5BTCBGT1JNJw3P+ANJU09MQVRFRCBGT1JNGhDT+QNIQUggSU5JVElBTCBGT1JNHwzM+ANTT0xBVEVEIEZPUk0eHJb7A1dJVEggQUxFRiBNQUtTVVJBIEZJTkFMIEZPUk0jEZX7A01FRU0gSU5JVElBTCBGT1JNIw6z+wNZRUggRklOQUwgRk9STRsP1vkDRUggSU5JVElBTCBGT1JNHgvv+QNNRURJQUwgRk9STRoR0vkDSkVFTSBJTklUSUFMIEZPUk0gDMv4A1NPTEFURUQgRk9STR8cmfsDV0lUSCBBTEVGIE1BS1NVUkEgRklOQUwgRk9STSQOvfsDSEFIIEZJTkFMIEZPUk0oDLj7A0lOSVRJQUwgRk9STSQPl/sDTUVFTSBGSU5BTCBGT1JNKQyY+wNJTklUSUFMIEZPUk0kDsf7A1lFSCBGSU5BTCBGT1JNGhHU+QNLSEFIIElOSVRJQUwgRk9STSAMzfgDU09MQVRFRCBGT1JNGg+M+QNNRUVNIEZJTkFMIEZPUk0fDNX5A0lOSVRJQUwgRk9STSAMzvgDU09MQVRFRCBGT1JNHwvu+QNNRURJQUwgRk9STR8cm/sDV0lUSCBBTEVGIE1BS1NVUkEgRklOQUwgRk9STSQOmvsDWUVIIEZJTkFMIEZPUk0aD435A05PT04gRklOQUwgRk9STRoOivkDUkVI", + "IEZJTkFMIEZPUk0aDo/5A1lFSCBGSU5BTCBGT1JNHg3Q+ANJU09MQVRFRCBGT1JNGg+L+QNaQUlOIEZJTkFMIEZPUk0QFtSdBFFBRERBU0EgQUxMQUFIVSBTSVJSQUgSHv74A0YgV0lUSCBBTEVGIE1BS1NVUkEgRklOQUwgRk9STSYNtfgDSVNPTEFURUQgRk9STRkQwvkDSEFIIElOSVRJQUwgRk9STR4Ms/gDU09MQVRFRCBGT1JNGRHD+QNNRUVNIElOSVRJQUwgRk9STR8MtPgDU09MQVRFRCBGT1JNHhP++gNXSVRIIEhBSCBGSU5BTCBGT1JNJwy0+wNJTklUSUFMIEZPUk0jD//6A01FRU0gRklOQUwgRk9STSMOsvsDWUVIIEZJTkFMIEZPUk0ZDv/4A1lFSCBGSU5BTCBGT1JNHQ22+ANJU09MQVRFRCBGT1JNEirx+wNMQSBVU0VEIEFTIEtPUkFOSUMgU1RPUCBTSUdOIElTT0xBVEVEIEZPUk0RDcv6A1VERElTQSBTSVJSQUgcBNWdBFVIVU0gAtadBEFBFwzXnQRUIEFTUkFBUlVIVU0QEMH6A1JBREkgQUxMQUFIVSBBTkggAsL6A0FBIALD+gNVTSICxPoDQUEhA8X6A05OQR0LyfsDVEFBQUxBQSBBTkgoAsr7A0FBKALL9wNVTSoCy/sDQUESDcD6A0hJTUFIVSBBTExBQUgfCMj7AyBUQUFBTEFBGAjP+gNNIEFMTEFBSCAJyPcDVSBUQUFBTEFBGQnJ9wNBQSBBTExBQUgiCcr3A1UgVEFBQUxBQRMSkPsDTUFUVSBBTExBQUhJIEFMQVlIJQKR+wNBQSUCxvcDSU0nAsf3A0FBIA3F9wNUQUFBTEFBIEFMQVlIEhL2+wNTT1VMIElTT0xBVEVEIEZPUk0RJtz4A0VIIFdJVEggU1VQRVJTQ1JJUFQgQUxFRiBJU09MQVRFRCBGT1JNECCh+gNTQUQgV0lUSCBBTEVGIE1BS1NVUkEgRklOQUwgRk9STSYNhfoDSVNPTEFURUQgRk9STRkQsfkDSEFIIElOSVRJQUwgRk9STR4MoPgDU09MQVRFRCBGT1JNHRPk+gNXSVRIIEhBSCBGSU5BTCBGT1JNJgzl+gNJTklUSUFMIEZPUk0iDqn7A1lFSCBGSU5BTCBGT1JNGRGy+QNLSEFIIElOSVRJQUwgRk9STRkRs/kDTUVFTSBJTklUSUFMIEZPUk0fDKH4A1NPTEFURUQgRk9STR4U5voDV0lUSCBNRUVNIEZJTkFMIEZPUk0oDMX7A0lOSVRJQUwgRk9STRkOq/oDUkVIIEZJTkFMIEZPUk0dDY/6A0lTT0xBVEVEIEZPUk0ZDqL6A1lFSCBGSU5BTCBGT1JNHQ2G+gNJU09MQVRFRCBGT1JNEg/P+wNMQUFNVUhVIEFMQVlOQUEUD/X7A00gSVNPTEFURUQgRk9STRMQ+fsDTEEgSVNPTEFURUQgRk9STRYn8PsDVVNFRCBBUyBLT1JBTklDIFNUT1AgU0lHTiBJU09MQVRFRCBGT1JNFRbG+gNMTEFBSFUgQUxBWUhJIFdBLUFBTElIHBjQ9wNUQUFBTEFBIEFMQVlISSBXQS1TQUxMQU0YE/r7A0hPVSBBTEFZSEUgV0FTQUxMQU0ZIsz7A1UgQUxBWUhJIFdBLUFMQUEgQUFMSUhFRSBXQS1TQUxMQU0kEcz6A0FBTElIRUUgV0EtU0FMTEFNESCX+gNFRU4gV0lUSCBBTEVGIE1BS1NVUkEgRklOQUwgRk9STScN+/kDSVNPTEFURUQgRk9STRoQrvkDSEFIIElOSVRJQUwgRk9STR8MnfgDU09MQVRFRCBGT1JNHgu1+gNNRURJQUwgRk9STR4W3PoDV0lUSCBKRUVNIElOSVRJQUwgRk9STRsPsfoDRUggSU5JVElBTCBGT1JNHgvo+QNNRURJQUwgRk9STRoRrfkDSkVFTSBJTklUSUFMIEZPUk0gDJz4A1NPTEFURUQgRk9STR8LtPoDTUVESUFMIEZPUk0fHN76A1dJVEggQUxFRiBNQUtTVVJBIEZJTkFMIEZPUk0kEN36A0hBSCBJTklUSUFMIEZPUk0aEa/5A0tIQUggSU5JVElBTCBGT1JNIAye+ANTT0xBVEVEIEZPUk0fC7b6A01FRElBTCBGT1JNHxyo+wNXSVRIIEFMRUYgTUFLU1VSQSBGSU5BTCBGT1JNJA7G+wNZRUggRklOQUwgRk9STRoRsPkDTUVFTSBJTklUSUFMIEZPUk0gDJ/4A1NPTEFURUQgRk9STR8L5/kDTUVESUFMIEZPUk0fE9/6A1dJVEggSEFIIEZJTkFMIEZPUk0oDOD6A0lOSVRJQUwgRk9STSQR4foDSkVFTSBJTklUSUFMIEZPUk0kD+L6A01FRU0gRklOQUwgRk9STSkM4/oDSU5JVElBTCBGT1JNGg6q+gNSRUggRklOQUwgRk9STR4NjvoDSVNPTEFURUQgRk9STRoOmPoDWUVIIEZJTkFMIEZPUk0eDfz5A0lTT0xBVEVEIEZPUk0RHuH4A0hBRERBIFdJVEggREFNTUEgSVNPTEFURUQgRk9STSIL8/kDTUVESUFMIEZPUk0hEd74A1RBTiBJU09MQVRFRCBGT1JNHBPg+ANGQVRIQSBJU09MQVRFRCBGT1JNIgvy+QNNRURJQUwgRk9STRwT4vgDS0FTUkEgSVNPTEFURUQgRk9STSIL9PkDTUVESUFMIEZPUk0hEd/4A1RBTiBJU09MQVRFRCBGT1JNHB7j+ANTVVBFUlNDUklQVCBBTEVGIElTT0xBVEVEIEZPUk0SIJn6A0VFTiBXSVRIIEFMRUYgTUFLU1VSQSBGSU5BTCBGT1JNKA39+QNJU09MQVRFRCBGT1JNGw6m+gNIQUggRklOQUwgRk9STR8MrvoDSU5JVElBTCBGT1JNIAyK+gNTT0xBVEVEIEZPUk0fC7j6A01FRElBTCBGT1JNHxTn+gNXSVRIIE1FRU0gRklOQUwgRk9STSkM6PoDSU5JVElBTCBGT1JNJA6q+wNZRUggRklOQUwgRk9STRwPsvoDRUggSU5JVElBTCBGT1JNHwvq+QNNRURJQUwgRk9STRsPpfoDSkVFTSBGSU5BTCBGT1JNIAyt+gNJTklUSUFMIEZPUk0hDIn6A1NPTEFURUQgRk9STSALt/oDTUVESUFMIEZPUk0gE+n6A1dJVEggWUVIIEZJTkFMIEZPUk0bD6f6A0tIQUggRklOQUwgRk9STSAMr/oDSU5JVElBTCBGT1JNIQyL+gNTT0xBVEVEIEZPUk0gC7n6A01FRElBTCBGT1JNGw+o+gNNRUVNIEZJTkFMIEZPUk0gDLD6A0lOSVRJQUwgRk9STSEMjPoDU09MQVRFRCBGT1JNIAvp+QNNRURJQUwgRk9STSAU6voDV0lUSCBLSEFIIEZJTkFMIEZPUk0qDOv6A0lOSVRJQUwgRk9STSUP7PoDTUVFTSBGSU5BTCBGT1JNKgzt+gNJTklUSUFMIEZPUk0bDqn6A1JFSCBGSU5BTCBGT1JNHw2N+gNJU09MQVRFRCBGT1JNGw6a+gNZRUggRklOQUwgRk9STR8N/vkDSVNPTEFURUQgRk9STREU/vsDVUJIQUFOQUhVIFdBIFRBQUFMQUEQFM76A1RBQkFBUkFLQSBXQS1UQUFBTEFBEh6R+gNIIFdJVEggQUxFRiBNQUtTVVJBIEZJTkFMIEZPUk0mDfX5A0lTT0xBVEVEIEZPUk0ZELj5A0hBSCBJTklUSUFMIEZPUk0eDKb4A1NPTEFURUQgRk9STRkRs/oDTUVFTSBJTklUSUFMIEZPUk0fDKf4A1NPTEFURUQgRk9STR4LuvoDTUVESUFMIEZPUk0eE/H6A1dJVEggSEFIIEZJTkFMIEZPUk0nDPL6A0lOSVRJQUwgRk9STSMR8/oDTUVFTSBJTklUSUFMIEZPUk0jDvT6A1lFSCBGSU5BTCBGT1JNGQ6S+gNZRUggRklOQUwgRk9STR0N9vkDSVNPTEFURUQgRk9STREf9PgDRUggV0lUSCBBTEVGIE1BS1NVUkEgRklOQUwgRk9STSYNj/gDSVNPTEFURUQgRk9STRkQovkDSEFIIElOSVRJQUwgRk9STR4MjPgDU09MQVRFRCBGT1JNHRTR+gNXSVRIIEpFRU0gRklOQUwgRk9STScM0voDSU5JVElBTCBGT1JNIhHT+gNNRUVNIElOSVRJQUwgRk9STRoPpfkDRUggSU5JVElBTCBGT1JNHQvk+QNNRURJQUwgRk9STRkRofkDSkVFTSBJTklUSUFMIEZPUk0fDIv4A1NPTEFURUQgRk9STR4coPsDV0lUSCBBTEVGIE1BS1NVUkEgRklOQUwgRk9STSMR0PoDTUVFTSBJTklUSUFMIEZPUk0jDp/7A1lFSCBGSU5BTCBGT1JNGRGj+QNLSEFIIElOSVRJQUwgRk9STR8MjfgDU09MQVRFRCBGT1JNHhyi+wNXSVRIIEFMRUYgTUFLU1VSQSBGSU5BTCBGT1JNIxHU+gNNRUVNIElOSVRJQUwgRk9STSMOofsDWUVIIEZJTkFMIEZPUk0ZD/L4A01FRU0gRklOQUwgRk9STR4MpPkDSU5JVElBTCBGT1JNHwyO+ANTT0xBVEVEIEZPUk0eC+P5A01FRElBTCBGT1JNHhyk+wNXSVRIIEFMRUYgTUFLU1VSQSBGSU5BTCBGT1JNIxDW+gNIQUggSU5JVElBTCBGT1JNIxHV+gNKRUVNIElOSVRJQUwgRk9STSMR1/oDS0hBSCBJTklUSUFMIEZPUk0jDqP7A1lFSCBGSU5BTCBGT1JNGQ/z+ANOT09OIEZJTkFMIEZPUk0ZDvD4A1JFSCBGSU5BTCBGT1JNGQ71+ANZRUggRklOQUwgRk9STR0NkPgDSVNPTEFURUQgRk9STRkP8fgDWkFJTiBGSU5BTCBGT1JNESfb+ANIQUwgV0lUSCBTVVBFUlNDUklQVCBBTEVGIElTT0xBVEVEIEZPUk0SH/r4A0VIIFdJVEggQUxFRiBNQUtTVVJBIEZJTkFMIEZPUk0nDZP4A0lTT0xBVEVEIEZPUk0aD+b5A0hFSCBNRURJQUwgRk9STRoSkfgDSkVFTSBJU09MQVRFRCBGT1JNGg/4+ANNRUVNIEZJTkFMIEZPUk0fDKb5A0lOSVRJQUwgRk9STSAMkvgDU09MQVRFRCBGT1JNHwvl+QNNRURJQUwgRk9STRoP+fgDTk9PTiBGSU5BTCBGT1JNGg72+ANSRUggRklOQUwgRk9STRoO+/gDWUVIIEZJTkFMIEZPUk0eDZT4A0lTT0xBVEVEIEZPUk0aD/f4A1pBSU4gRklOQUwgRk9STRBA+vcDVUlHSFVSIEtJUkdISVogWUVIIFdJVEggSEFNWkEgQUJPVkUgV0lUSCBBTEVGIE1BS1NVUkEgRklOQUwgRk9STUYM+/cDSU5JVElBTCBGT1JNRwz59wNTT0xBVEVEIEZPUk0QFvj7A1dBU0FMTEFNIElTT0xBVEVEIEZPUk0QIJX5A1lFSCBXSVRIIEFMRUYgTUFLU1VSQSBGSU5BTCBGT1JNJg3Z+ANJU09MQVRFRCBGT1JNGRDb+QNIQUggSU5JVElBTCBGT1JNHgzW+ANTT0xBVEVEIEZPUk0dE677A1dJVEggWUVIIEZJTkFMIEZPUk0bHO33A01aQSBBQk9WRSBXSVRIIEFFIEZJTkFMIEZPUk0tDez3A0lTT0xBVEVEIEZPUk0rDuv3A0xFRiBGSU5BTCBGT1JNLw3q9wNJU09MQVRFRCBGT1JNLxLo+ANNQUtTVVJBIEZJTkFMIEZPUk03DYP4A0lTT0xBVEVEIEZPUk0qDPf3A0UgRklOQUwgRk9STSwM+PcDSU5JVElBTCBGT1JNLQz29wNTT0xBVEVEIEZPUk0qEJj5A0hBSCBJTklUSUFMIEZPUk0vDIH4A1NPTEFURUQgRk9STSsPm/kDRUggSU5JVElBTCBGT1JNLgvg+QNNRURJQUwgRk9STSoRl/kDSkVFTSBJTklUSUFMIEZPUk0wDID4A1NPTEFURUQgRk9STSoRmfkDS0hBSCBJTklUSUFMIEZPUk0qD+b4A01FRU0gRklOQUwgRk9STS8MmvkDSU5JVElBTCBGT1JNMAyC+ANTT0xBVEVEIEZPUk0vC9/5A01FRElBTCBGT1JNKg/n+ANOT09OIEZJTkFMIEZPUk0qDfP3A09FIEZJTkFMIEZPUk0tDfL3A0lTT0xBVEVEIEZPUk0qDuT4A1JFSCBGSU5BTCBGT1JNKgzx9wNVIEZJTkFMIEZPUk0sDfD3A0lTT0xBVEVEIEZPUk0qDu/3A1dBVyBGSU5BTCBGT1JNLg3u9wNJU09MQVRFRCBGT1JNKg7p+ANZRUggRklOQUwgRk9STS4NhPgDSVNPTEFURUQgRk9STSsM9fcDVSBGSU5BTCBGT1JNLQ309wNJU09MQVRFRCBGT1JNKg/l+ANaQUlOIEZJTkFMIEZPUk0aD975A0VIIElOSVRJQUwgRk9STR0L8fkDTUVESUFMIEZPUk0ZEdr5A0pFRU0gSU5JVElBTCBGT1JNHwzV+ANTT0xBVEVEIEZPUk0eE6/7A1dJVEggWUVIIEZJTkFMIEZPUk0ZEdz5A0tIQUggSU5JVElBTCBGT1JNHwzX+ANTT0xBVEVEIEZPUk0ZD5P5A01FRU0gRklOQUwgRk9STR4M3fkDSU5JVElBTCBGT1JNHwzY+ANTT0xBVEVEIEZPUk0eC/D5A01FRElBTCBGT1JNHhSc+wNXSVRIIE1FRU0gRklOQUwgRk9STSgMnfsDSU5JVElBTCBGT1JNIw6w+wNZRUggRklOQUwgRk9STRkPlPkDTk9PTiBGSU5BTCBGT1JNGQ6R+QNSRUggRklOQUwgRk9STRkOlvkDWUVIIEZJTkFMIEZPUk0dDdr4A0lTT0xBVEVEIEZPUk0ZD5L5A1pBSU4gRklOQUwgRk9STRAaufkDWkFIIFdJVEggTUVFTSBJTklUSUFMIEZPUk0fDKj4A1NPTEFURUQgRk9STR4Lu/oDTUVESUFMIEZPUk0HDJwRTUFEREEgV0FBSklCDAfTDEggQUJP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VElPTiBNQVJLBxCIEVJBSVNFRCBST1VORCBET1QJAYgMWQgN3QxFVkVSU0VEIERBTU1BCBT4EUlHSFQgQVJST1dIRUFEIEFCT1ZFHAn9ESBXSVRIIERPVBcF+hFCRUxPVwgj7A1PVU5ERUQgSElHSCBTVE9QIFdJVEggRklMTEVEIENFTlRSRQcJmwxTRU1JQ09MT04IBdEMSEFEREENDvz8AyBJU09MQVRFRCBGT1JNDgv9/ANNRURJQUwgRk9STQgTkQxJR04gQUxBWUhFIEFTU0FMTEFNDAWPDE1JU1JBDBGTDFJBREkgQUxMQUhPVSBBTkhVDhCSDEhNQVRVTExBSCBBTEFZSEUMBYMMU0FGSEEOGpAMTExBTExBSE9VIEFMQVlIRSBXQVNTQUxMQU0OBIQMTVZBVA4DgQxOQUgND/0NSU5ESEkgQU1QRVJTQU5EExD+DVBPU1RQT1NJVElPTiBNRU4MCZQMVEFLSEFMTFVTCAqZDE1BTEwgREFNTUENCckRRkFSU0kgWUVIDwOYDFRIQQ0I1hFISUdIIEFJThIU4Q1ET1RMRVNTIEhFQUQgT0YgS0hBSBIJyhFGQVJTSSBZRUgTDuART09UTk9URSBNQVJLRVISBNoNSkVFTRII2Q1MQU0gQUxFRhMelgxJR0FUVVJFIEFMRUYgV0lUSCBMQU0gV0lUSCBZRUglCpYMWUVIIEJBUlJFRRse1w1RQUYgV0lUSCBMQU0gV0lUSCBBTEVGIE1BS1NVUkEbHtYNU0FEIFdJVEggTEFNIFdJVEggQUxFRiBNQUtTVVJBEgXkDU1BRERBExDYDUVFTSBJTklUSUFMIEZPUk0YDOINU09MQVRFRCBGT1JNEgToDU5PT04WC9gRIFdJVEggS0FTUkESA9cRUUFGEgzfDVJPVU5ERUQgWkVSTxID1RFTQUQTA9wNRUVOEwnhEUlHTiBTQUZIQRIDlQxUQUgTCdsNSFJFRSBET1RTEhjgDVVQUklHSFQgUkVDVEFOR1VMQVIgWkVSTxID8xFXQVcTCpgRT1JEIEFMLUpVWhgG3BFOLU5JU0YYBdQRUi1SVUIYB9sRUy1TQUpEQRgL2hFUSC1USEFMQVRIQRcD3hFRSUYXA8wRU0FIGQPdEUtUQRcF3xFXQVFGQRID5w1ZRUgVG8sRIEJBUlJFRSBXSVRIIFRXTyBET1RTIEJFTE9XEgPNEVpBSBQClwxJTg0FmgxLQVNSQQ0I7Q1MT1cgTUVFTREE+50ETk9PThUL2REgV0lUSCBLQVNSQREE4w1TRUVOEQPTEVdBVxIKmhFPUkQgSU1BQUxBFwaZEVNITUFBTRYF/50ETUFEREEWBP6dBFFBU1IWBf2dBFNBS1RBFgebEVRBU0hFRUwNA+UNV0FXDQPmDVlFSBAbxZ0EIEJBUlJFRSBXSVRIIFRXTyBET1RTIEJFTE9XCBPeDVRBUlQgT0YgUlVCIEVMIEhJWkIIDdYMVUJTQ1JJUFQgQUxFRgkD0gxLVU4MBtARIEJFTE9XDQ3+/ANJU09MQVRFRCBGT1JNDQv//ANNRURJQUwgRk9STQkYnRFQRVJTQ1JJUFQgQUxFRiBNT0tIQVNTQVMID7L3A1lNQk9MIERPVCBBQk9WRRIFs/cDQkVMT1cQF7z3A1VCTEUgVkVSVElDQUwgQkFSIEJFTE9XDg+69wNGT1VSIERPVFMgQUJPVkUYBbv3A0JFTE9XDgS/9wNSSU5HDg/A9wNTTUFMTCBUQUggQUJPVkUYBcH3A0JFTE9XDhC29wNUSFJFRSBET1RTIEFCT1ZFGQW39wNCRUxPVxkYuPcDUE9JTlRJTkcgRE9XTldBUkRTIEFCT1ZFLAW59wNCRUxPVw8NtPcDV08gRE9UUyBBQk9WRRcFtfcDQkVMT1cXEL33A1ZFUlRJQ0FMTFkgQUJPVkUiBb73A0JFTE9XDgvC9wNXQVNMQSBBQk9WRQcN8/wDVEFJTCBGUkFHTUVOVAkFwAxUV0VFTA4U8fwDIFdJVEggRkFUSEFUQU4gQUJPVkUUEIMRT1ZFUlNUUlVDSyBIQU1aQR8DhBFXQVcUDoURVFdPIERPVFMgQkVMT1cIEuwMSE9VU0FORFMgU0VQQVJBVE9SCA7sEU9ORSBMT09QIEFCT1ZFEQXvEUJFTE9XDA3qEU9ORSBET1QgQUJPVkUUBe0RQkVMT1cMDusRVFdPIERPVFMgQUJPVkUVBe4RQkVMT1cIGp4MUklQTEUgRE9UIFBVTkNUVUFUSU9OIE1BUksIEeMRVVJORUQgREFNTUEgQkVMT1cHDY4RVkVSVElDQUwgVEFJTAgT3AxPV0VMIFNJR04gRE9UIEJFTE9XEhbbDElOVkVSVEVEIFNNQUxMIFYgQUJPVkUS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B1ZFUkFHRSBCT1gBDsG4BEhBSUtTVUtJIERBTkRBCwrYuARJR0lUIEVJR0hUEATVuARGSVZFEQPUuARPVVIQBNm4BE5JTkUQA9G4BE9ORRAF17gEU0VWRU4RAta4BElYEAXTuARUSFJFRREC0rgEV08QBNC4BFpFUk8LC8K4BE9VQkxFIERBTkRBCgzEuARHQVAgRklMTEVSLTEVAcW4BDIKEuy4BEhVTkRSRURTIFVOSVQgTUFSSwoIgLgETEVUVEVSIEESAYG4BEESAYu4BEkSAY24BFURAqS4BEJBEgKluARIQRECk7gEQ0ESApS4BEhBEQKfuAREQRICmrgEREETApu4BEhBEgKguARIQREBirgERRECkLgER0ESApG4BEhBEQKuuARIQREBgrgESRIBg7gESREClbgESkESApa4BEhBEQKOuARLQRICj7gESEERAqm4BExBEQKmuARNQRECobgETkESApK4BEdBEgKcuAROQRICl7gEWUERAYy4BE8RAqK4BFBBEgKjuARIQRECqLgEUkERAq24BFNBEgKruARIQRICrLgEU0ERAp24BFRBEgKeuARIQRICmLgEVEETApm4BEhBEQGEuARVEgGFuARVEQKquARWQRIIiLgET0NBTElDIEwZAYa4BFIaAYe4BFIRAqe4BFlBCgzhuAROVU1CRVIgRUlHSFQWAeq4BFkRBee4BEZJRlRZEwLeuARWRRIE5rgET1JUWRMC3bgEVVIRBOK4BE5JTkUVAuu4BFRZEQPauARPTkURBeC4BFNFVkVOFgLpuARUWRIC37gESVgUAui4BFRZEQPjuARURU4SBeW4BEhJUlRZEwPcuARSRUUSBeS4BFdFTlRZEwHbuARPCg29uARTSUdOIEFOVVNWQVJBEAfAuARWQUdSQUhBDwu8uARDQU5EUkFCSU5EVQ8Gv7gEVklSQU1BEQW+uARTQVJHQQoNr7gEVk9XRUwgU0lHTiBBQRYBubgESRYBu7gEVRUBuLgERRUBsLgESRYBsbgESRUBurgETxUBsrgEVRYBs7gEVRUJtrgEVk9DQUxJQyBMHQG0uARSHgG1uARSCg7DuARXT1JEIFNFUEFSQVRPUgEGsu0HSUNZQ0xFBgO07QdJU1QCEflTRyBSRVZFUlNFIFNPTElEVVMEB/hTU09MSURVUwIE2egHS0lOSQII4vMHTExFRCBDQVAEBbHnB0lBUkRTAgyjTE9IQVpBUkQgU0lHTgICpugHUkQDCoLnB1RIREFZIENBS0UCA6zzB1NPTgIKv0FUQ09JTiBTSUdOAwfm9QdJTkcgTElQAQvTU0xBQ0sgQk9XVElFBhGsTkNFTlRSRSBXSElURSBTVEFSBwrX9AdIRVNTIEFMRklMDAbdTEJJU0hPUBIXkvQHIFJPVEFURUQgTklORVRZIERFR1JFRVMbG7z0B1RXTyBIVU5EUkVEIFNFVkVOVFkgREVHUkVFUwwKyfQHRVFVSUhPUFBFUhYXzPQHIFJPVEFURUQgTklORVRZIERFR1JFRVMMBNb0B0ZFUloMBNpMS0lORxAXj/QHIFJPVEFURUQgTklORVRZIERFR1JFRVMZG7n0B1RXTyBIVU5EUkVEIFNFVkVOVFkgREVHUkVFUw0F3kxOSUdIVBIbh/QHIFJPVEFURUQgRk9SVFktRklWRSBERUdSRUVTGw6T9AdOSU5FVFkgREVHUkVFUxsfnPQHT05FIEhVTkRSRUQgVEhJUlRZLUZJVkUgREVHUkVFUxsdxvQHVEhSRUUgSFVORFJFRCBGSUZURUVOIERFR1JFRVMcGr30B1dPIEhVTkRSRUQgU0VWRU5UWSBERUdSRUVTJxOx9AdUV0VOVFktRklWRSBERUdSRUVTEgfT9ActQklTSE9QEwXR9AdRVUVFThME0vQHUk9PSwwE30xQQVdOEBeU9AcgUk9UQVRFRCBOSU5FVFkgREVHUkVFUxkbvvQHVFdPIEhVTkRSRUQgU0VWRU5UWSBERUdSRUVTDAXbTFFVRUVOEReQ9AcgUk9UQVRFRCBOSU5FVFkgREVHUkVFUxobuvQHVFdPIEhVTkRSRUQgU0VWRU5UWSBERUdSRUVTDATcTFJPT0sQF5H0ByBST1RBVEVEIE5JTkVUWSBERUdSRUVTGRu79AdUV08gSFVORFJFRCBTRVZFTlRZIERFR1JFRVMMDaf0B1RVUk5FRCBCSVNIT1ATBKT0B0tJTkcUBaj0B05JR0hUEwSp9AdQQVdOEwWl9AdRVUVFThMEpvQHUk9PSwcFz0tJUkNMRQwL+kcgRk9SIFJFQ09SRA0P7VNXSVRIIERPV04gQVJST1cSDolNVFdPIFdISVRFIERPVFMSD4hNV0hJVEUgRE9UIFJJR0hUBwjjTExVQiBTVUlUBw7oTVJPU1MgT04gU0hJRUxEByOoV1VSVkVEIERPV05XQVJEUyBBTkQgTEVGVFdBUkRTIEFSUk9XGxCpV1JJR0hUV0FSRFMgQVJST1cNHa5XTEVGVFdBUkRTIEFORCBET1dOV0FSRFMgQVJST1cbDaxXVVBXQVJEUyBBUlJPVw0er1dSSUdIVFdBUkRTIEFORCBET1dOV0FSRFMgQVJST1ccDa1XVVBXQVJEUyBBUlJPVw0bqldVUFdBUkRTIEFORCBMRUZUV0FSRFMgQVJST1cZEKtXUklHSFRXQVJEUyBBUlJPVwYHxktESUFNT05EDQjBVyBDRU5UUkVEDg3WTk1JTlVTIFdISVRFIFgOCN5XT04gQ1JPU1MOBOZMU1VJVA4P6lNXSVRIIERPV04gQVJST1cHG6PrB09XTiBQT0lOVElORyBCQUNLSEFORCBJTkRFWAoZ7EctUE9JTlRJTkcgRE9VQkxFIFRSSUFOR0xFFBiD7wdJU09TQ0VMRVMgUklHSFQgVFJJQU5HTEUUDr5LU01BTEwgVFJJQU5HTEUUCLxLVFJJQU5HTEUKG59XV0FSRFMgRVFVSUxBVEVSQUwgQVJST1dIRUFEBwzDTVJBVUdIVFMgS0lORw8Dwk1NQU4IBaLmB09QTEVUBgSRTUZMQUcIBr9OT1JFVFRFBwW/6wdPTERFUggPpk5VUiBQT0lOVEVEIFNUQVIGFqrrB0hBUkQgU0hFTEwgRkxPUFBZIERJU0sHBKTrB0VBUlQLBeVMIFNVSVQIBaJWWEFHT04HEaxWT1JJWk9OVEFMIEVMTElQU0UIB9dTVVJHTEFTUwYMpFZMQVJHRSBDSVJDTEUSG+uYByBNSU5VUyBMRUZUIFFVQVJURVIgU0VDVElPThoU7pgHT1dFUiBRVUFSVEVSIFNFQ1RJT04ZFe2YB1JJR0hUIFFVQVJURVIgU0VDVElPThkV7JgHVVBQRVIgUVVBUlRFUiBTRUNUSU9ODAabVlNRVUFSRQcO2E1FRlQgTEFORSBNRVJHRQsXnOsHUE9JTlRJTkcgQkFDS0hBTkQgSU5ERVgUBZpMSU5ERVgKGepHLVBPSU5USU5HIERPVUJMRSBUUklBTkdMRSMS7kcgV0lUSCBWRVJUSUNBTCBCQVIUGIDvB0lTT1NDRUxFUyBSSUdIVCBUUklBTkdMRRQHxEtQT0lOVEVSFA7CS1NNQUxMIFRSSUFOR0xFFAjAS1RSSUFOR0xFCgzMQFdBUkRTIEJVTExFVBAVnFdFUVVJTEFURVJBTCBBUlJPV0hFQUQHEuNLT1dFUiBMRUZUIFRSSUFOR0xFDA7iS1JJR0hUIFRSSUFOR0xFCAXrU1pFTkdFBg6lVk1FRElVTSBESUFNT05EDhX3R09XTi1QT0lOVElORyBUUklBTkdMRSMIxlcgQ0VOVFJFRA0W9EdMRUZULVBPSU5USU5HIFRSSUFOR0xFIwjHVyBDRU5UUkVEDganVk9aRU5HRQ0X9UdSSUdIVC1QT0lOVElORyBUUklBTkdMRSQIyFcgQ0VOVFJFRA0Nme8HU01BTEwgRElBTU9ORBMHn+8HTE9aRU5HRRMG/ktTUVVBUkUOBfxLUVVBUkUNFPZHVVAtUE9JTlRJTkcgVFJJQU5HTEUhCMVXIENFTlRSRUQHCrhNT09OIExJTElUSAYM75gHTkVVVFJBTCBGQUNFBwKSTklCBgfEV09DVEFHT04GDbBLUEFSQUxMRUxPR1JBTQcG8ucHRU5OQU5UCQWfVlRBR09OBwaI6wdVU0hQSU4GFtNOUVVFU1RJT04gTUFSSyBPUk5BTUVOVAYJrEtSRUNUQU5HTEUHHJ3rB0lHSFQgUE9JTlRJTkcgQkFDS0hBTkQgSU5ERVgVBZtMSU5ERVgMDrOdB1RSSUFOR0xFIENBUkVUCxnpRy1QT0lOVElORyBET1VCTEUgVFJJQU5HTEUkEu1HIFdJVEgg", + "VkVSVElDQUwgQkFSFRiC7wdJU09TQ0VMRVMgUklHSFQgVFJJQU5HTEUVCNNWUEVOVEFHT04WBrpLT0lOVEVSFQ64S1NNQUxMIFRSSUFOR0xFFQi2S1RSSUFOR0xFHRnvRyBXSVRIIERPVUJMRSBWRVJUSUNBTCBCQVILC6FPV0FSRFMgQVJST1cWBKRPSEVBRBEGzUBCVUxMRVQRFZ5XRVFVSUxBVEVSQUwgQVJST1dIRUFEBwb25wdPU0VUVEUGD4BOU0FGRVRZIFNDSVNTT1JTBweCTkNJU1NPUlMHCpdMSE9HSSBQSUVDRQcT8eoHS1VMTCBBTkQgQ1JPU1NCT05FUwcUhO8HTElHSFRMWSBTTUFMTCBDSVJDTEUVBo3vB1NRVUFSRQcMqVZNQUxMIERJQU1PTkQMB6pWTE9aRU5HRQwGqktTUVVBUkUNA9FWVEFSDBPN9wdVUC1QT0lOVElORyBDSEVWUk9OCAq7TElMSU5HIEZBQ0UHBsdNTk9XTUFOBwngTFBBREUgU1VJVAcFoEtRVUFSRQwHsuoHIEJVVFRPTg0HwFdDRU5UUkVEDQj5R0ZPUiBTVE9QBwOFTFRBUgcMgExVTiBXSVRIIFJBWVMGCY5MVEVMRVBIT05FBwuX7wdJTlkgRElBTU9ORAsHne8HTE9aRU5HRQsGjO8HU1FVQVJFBxL/6gdPVUNIVE9ORSBURUxFUEhPTkUHBN9NUlVDSwcX1k1XTy1XQVkgTEVGVCBXQVkgVFJBRkZJQwYa+0xVTklWRVJTQUwgUkVDWUNMSU5HIFNZTUJPTAcZousHUCBQT0lOVElORyBCQUNLSEFORCBJTkRFWAgZ60ctUE9JTlRJTkcgRE9VQkxFIFRSSUFOR0xFEhiB7wdJU09TQ0VMRVMgUklHSFQgVFJJQU5HTEUSDrRLU01BTEwgVFJJQU5HTEUSCLJLVFJJQU5HTEUIEeRLUEVSIExFRlQgVFJJQU5HTEUMDuVLUklHSFQgVFJJQU5HTEUIG51XV0FSRFMgRVFVSUxBVEVSQUwgQVJST1dIRUFEBhCuVlZFUlRJQ0FMIEVMTElQU0UPCa5LUkVDVEFOR0xFCQ+Y7wdZIFNNQUxMIERJQU1PTkQRB57vB0xPWkVOR0URBp1WU1FVQVJFBRu2Ty1GRUFUSEVSRUQgTk9SVEggRUFTVCBBUlJP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DAihRklOVEVHUkFMDBDbXExFRlQgUEFSRU5USEVTSVMQDd2YBy1GQUNJTkcgUk9CT1QZDe2bB1VOTkVSIEZSQU1FLTElAe+bBzIMEdxcUklHSFQgUEFSRU5USEVTSVMRDd+YBy1GQUNJTkcgUk9CT1QaDembB1VOTkVSIEZSQU1FLTEmAeubBzIMD+ebB1NUQU5ESU5HIFBFUlNPTgch6vcHSlVTVElGSUVEIFVQUEVSIEhBTEYgQkxBQ0sgQ0lSQ0xFHAzi9wdXSElURSBDSVJDTEUHC55GTEVGVCBDT1JORVINA41GUk9QDAykXEhBTEYgQlJBQ0tFVAwq7fcHSlVTVElGSUVEIFVQUEVSIFJJR0hUIFFVQVJURVIgQkxBQ0sgQ0lSQ0xFBwvdR1BBUkVOVEhFU0lTBwyfRlJJR0hUIENPUk5FUg4DjEZST1ANDKVcSEFMRiBCUkFDS0VUDSnu9wdKVVNUSUZJRUQgVVBQRVIgTEVGVCBRVUFSVEVSIEJMQUNLIENJUkNMRQcOtUdTUVVBUkUgQlJBQ0tFVBUYtkcgT1ZFUiBUT1AgU1FVQVJFIEJSQUNLRVQHFuFHVE9SVE9JU0UgU0hFTEwgQlJBQ0tFVAIFkOkHVVFVRVQHC5XnByBPRiBGTE9XRVJTAgv55wdXIEFORCBBUlJPVwMMz+oHTCBPRiBIWUdJRUlBBQrj8gdXSVRIIFNQT09OBAOz5wdJTkcDA8hFVElFBhXRUyBXSVRIIExFRlQgSEFMRiBCTEFDSwwQ0lNSSUdIVCBIQUxGIEJMQUNLAkWJnAdYIERSQVdJTkdTIERPVUJMRSBESUFHT05BTCBMT1dFUiBMRUZUIFRPIE1JRERMRSBDRU5UUkUgVE8gTE9XRVIgUklHSFQdGaCYB1VQUEVSIExFRlQgVE8gTE9XRVIgUklHSFQrHIqcB01JRERMRSBDRU5UUkUgVE8gVVBQRVIgUklHSFQjE5+YB1JJR0hUIFRPIExPV0VSIExFRlQVEuZKT1dOIEFORCBIT1JJWk9OVEFMHQTXSkxFRlQdBdRKUklHSFQUCtBKSE9SSVpPTlRBTBQR6UpVUCBBTkQgSE9SSVpPTlRBTBsE3UpMRUZUGwXaSlJJR0hUFAjRSlZFUlRJQ0FMHA/sSiBBTkQgSE9SSVpPTlRBTCEE40pMRUZUIQXgSlJJR0hUDx/lSldOIERPVUJMRSBBTkQgSE9SSVpPTlRBTCBTSU5HTEUdC9ZKTEVGVCBTSU5HTEUdDNNKUklHSFQgU0lOR0xFEhqwSkhFQVZZIEFORCBIT1JJWk9OVEFMIExJR0hUHAqSSkxFRlQgTElHSFQhCKdKVVAgTElHSFQcC45KUklHSFQgTElHSFQiCJ9KVVAgTElHSFQcE8FKVVAgSE9SSVpPTlRBTCBMSUdIVBIar0pMSUdIVCBBTkQgSE9SSVpPTlRBTCBIRUFWWRwKkUpMRUZUIEhFQVZZIQipSlVQIEhFQVZZHAuNSlJJR0hUIEhFQVZZIgihSlVQIEhFQVZZHBPHSlVQIEhPUklaT05UQUwgSEVBVlkSHORKU0lOR0xFIEFORCBIT1JJWk9OVEFMIERPVUJMRR0L1UpMRUZUIERPVUJMRR0M0kpSSUdIVCBET1VCTEUNHM1KSEVBVlkgRE9VQkxFIERBU0ggSE9SSVpPTlRBTB8Iz0pWRVJUSUNBTBUC+0pXThcPs0ogQU5EIEhPUklaT05UQUwcBJNKTEVGVBwFj0pSSUdIVBMKgUpIT1JJWk9OVEFMEwT4SkxFRlQXEP5KIEFORCBMSUdIVCBSSUdIVBMZiUpRVUFEUlVQTEUgREFTSCBIT1JJWk9OVEFMIgiLSlZFUlRJQ0FMEwX6SlJJR0hUExaFSlRSSVBMRSBEQVNIIEhPUklaT05UQUwfCIdKVkVSVElDQUwTAvlKVVAVD7tKIEFORCBIT1JJWk9OVEFMGgSbSkxFRlQbCf9KSUdIVCBET1dOGgWXSlJJR0hUEwiDSlZFUlRJQ0FMGw/LSiBBTkQgSE9SSVpPTlRBTCAEq0pMRUZUIAWjSlJJR0hUDSLFSkxFRlQgRE9XTiBIRUFWWSBBTkQgUklHSFQgVVAgTElHSFQSGq1KSEVBVlkgQU5EIFJJR0hUIERPV04gTElHSFQiCLVKVVAgTElHSFQiDr1KVkVSVElDQUwgTElHSFQSGrJKTElHSFQgQU5EIFJJR0hUIERPV04gSEVBVlkiCLpKVVAgSEVBVlkiDspKVkVSVElDQUwgSEVBVlkSHcNKVVAgSEVBVlkgQU5EIFJJR0hUIERPV04gTElHSFQOFu5KSUdIVCBBUkMgRE9XTiBBTkQgTEVGVCAF7UpSSUdIVBcL70pVUCBBTkQgTEVGVB4F8EpSSUdIVBMVnpgHQk9UVE9NIEFORCBMT1dFUiBMRUZUEw7zSkRJQUdPTkFMIENST1NTHAeu9wdESUFNT05EHCra9wdMT1dFUiBMRUZUIFRPIE1JRERMRSBDRU5UUkUgVE8gTE9XRVIgUklHSFQqG973B1VQUEVSIENFTlRSRSBUTyBMT1dFUiBSSUdIVBwbovcHTUlERExFIExFRlQgVE8gTE9XRVIgQ0VOVFJFNxCm9wcgVE8gTUlERExFIFJJR0hUMQXT9wdSSUdIVCscp/cHVVBQRVIgQ0VOVFJFIFRPIE1JRERMRSBSSUdIVEcQrPcHIFRPIExPV0VSIENFTlRSRSMVo/cHUklHSFQgVE8gTE9XRVIgQ0VOVFJFMgTQ9wdMRUZULCut9wdVUFBFUiBDRU5UUkUgVE8gTUlERExFIExFRlQgVE8gTE9XRVIgQ0VOVFJFHBrX9wdVUFBFUiBDRU5UUkUgVE8gTE9XRVIgTEVGVDIF1fcHUklHSFQsC6D3B01JRERMRSBMRUZUNyGo9wcgQU5EIE1JRERMRSBSSUdIVCBUTyBMT1dFUiBDRU5UUkU4D6T3B1RPIExPV0VSIENFTlRSRUcQq/cHIFRPIE1JRERMRSBSSUdIVDMFofcHUklHSFQ4IKn3ByBBTkQgTUlERExFIExFRlQgVE8gTE9XRVIgQ0VOVFJFOQ+l9wdUTyBMT1dFUiBDRU5UUkVID6r3ByBUTyBNSURETEUgTEVGVCIU1PcHTEVGVCBUTyBMT1dFUiBDRU5UUkU2D9z3", + "ByBUTyBVUFBFUiBSSUdIVDAF8kpSSUdIVCob2/cHTUlERExFIENFTlRSRSBUTyBMT1dFUiBMRUZUOwvY9wdVUFBFUiBSSUdIVDEF0vcHUklHSFQ2Dt/3ByBUTyBMT1dFUiBMRUZUIhXW9wdSSUdIVCBUTyBMT1dFUiBDRU5UUkUxBPFKTEVGVCsc2fcHTUlERExFIENFTlRSRSBUTyBMT1dFUiBSSUdIVDIE0fcHTEVGVDYP3fcHIFRPIExPV0VSIFJJR0hUFBXMSk9VQkxFIERBU0ggSE9SSVpPTlRBTB8IzkpWRVJUSUNBTBUC90pXThcPrEogQU5EIEhPUklaT05UQUwcBJBKTEVGVBwFjEpSSUdIVBMKgEpIT1JJWk9OVEFMHRCcmAcgQU5EIExPV0VSIFJJR0hUIgubmAdVUFBFUiBSSUdIVB4Ur/cHV0lUSCBWRVJUSUNBTCBTVFJPS0UTBPRKTEVGVBcQ/EogQU5EIEhFQVZZIFJJR0hUExmISlFVQURSVVBMRSBEQVNIIEhPUklaT05UQUwiCIpKVkVSVElDQUwTBfZKUklHSFQTEp2YB1RPUCBBTkQgVVBQRVIgTEVGVBQVhEpSSVBMRSBEQVNIIEhPUklaT05UQUwfCIZKVkVSVElDQUwTAvVKVVAVD/1KIEFORCBIRUFWWSBET1dOGwm0Sk9SSVpPTlRBTBoEmEpMRUZUGgWUSlJJR0hUEwiCSlZFUlRJQ0FMGxCZnAcgQU5EIEJPVFRPTSBMRUZUJwWXnAdSSUdIVCAKvEpIT1JJWk9OVEFMIASkSkxFRlQgBZxKUklHSFQgCJicB1RPUCBMRUZUJAWWnAdSSUdIVA0ixkpSSUdIVCBET1dOIEhFQVZZIEFORCBMRUZUIFVQIExJR0hUExmuSkhFQVZZIEFORCBMRUZUIERPV04gTElHSFQiCLZKVVAgTElHSFQiDr5KVkVSVElDQUwgTElHSFQTGbFKTElHSFQgQU5EIExFRlQgRE9XTiBIRUFWWSIIuUpVUCBIRUFWWSIOyUpWRVJUSUNBTCBIRUFWWRMcxEpVUCBIRUFWWSBBTkQgTEVGVCBET1dOIExJR0hUDR/oSlVQIERPVUJMRSBBTkQgSE9SSVpPTlRBTCBTSU5HTEUbC9xKTEVGVCBTSU5HTEUbDNlKUklHSFQgU0lOR0xFEB/ASkhFQVZZIEFORCBET1dOIEhPUklaT05UQUwgTElHSFQaELhKSE9SSVpPTlRBTCBMSUdIVBoPpkpMRUZUIERPV04gTElHSFQfBZpKTElHSFQaEJ5KUklHSFQgRE9XTiBMSUdIVCAFlkpMSUdIVBAfyEpMSUdIVCBBTkQgRE9XTiBIT1JJWk9OVEFMIEhFQVZZGhC3SkhPUklaT05UQUwgSEVBVlkaD6pKTEVGVCBET1dOIEhFQVZZHwWZSkhFQVZZGhCiSlJJR0hUIERPV04gSEVBVlkgBZVKSEVBVlkQHOdKU0lOR0xFIEFORCBIT1JJWk9OVEFMIERPVUJMRRsL20pMRUZUIERPVUJMRRsM2EpSSUdIVCBET1VCTEUNJetKVkVSVElDQUwgRE9VQkxFIEFORCBIT1JJWk9OVEFMIFNJTkdMRSEL4kpMRUZUIFNJTkdMRSEM30pSSUdIVCBTSU5HTEUWGsJKSEVBVlkgQU5EIEhPUklaT05UQUwgTElHSFQgCqhKTEVGVCBMSUdIVCALoEpSSUdIVCBMSUdIVBYav0pMSUdIVCBBTkQgSE9SSVpPTlRBTCBIRUFWWSAKpUpMRUZUIEhFQVZZIAudSlJJR0hUIEhFQVZZFhzqSlNJTkdMRSBBTkQgSE9SSVpPTlRBTCBET1VCTEUhC+FKTEVGVCBET1VCTEUhDN5KUklHSFQgRE9VQkxFAwnK8gdJTkcgR0xPVkUCAeboB1kDCMntB1MgU1lNQk9MAQKCAVBIAQvHoARSQUhNSSBEQU5EQQgK7qAESUdJVCBFSUdIVA0E66AERklWRQ4D6qAET1VSDQTvoAROSU5FDQPnoARPTkUNBe2gBFNFVkVODgLsoARJWA0F6aAEVEhSRUUOAuigBFdPDQTmoARaRVJPCAvIoARPVUJMRSBEQU5EQQcIhaAETEVUVEVSIEEPAYagBEEPAZCgBEkPAZKgBFUOAqmgBEJBDwKqoARIQQ4CmKAEQ0EPApmgBEhBDgKkoAREQQ8Cn6AEREEQAqCgBEhBDwKloARIQQ4Bj6AERQ4ClaAER0EPApagBEhBDgKzoARIQQ4Bh6AESQ8BiKAESQ4CmqAESkEPApugBEhBDgKToARLQQ8ClKAESEEOAq6gBExBDwK0oARMQQ4Cq6AETUEOAqagBE5BDwKXoARHQQ8CoaAETkEPApygBFlBDgGRoARPDwz1oARMRCBUQU1JTCBMTEEaArWgBExBGAS3oAROTk5BGAO2oARSUkEYB/GgBFNIT1JUIEUeAfKgBE8OAqegBFBBDwKooARIQQ4CraAEUkEOArKgBFNBDwKwoARIQQ8CsaAEU0EOAqKgBFRBDwKjoARIQQ8CnaAEVEEQAp6gBEhBDgGJoARVDwGKoARVDgKvoARWQQ8IjaAET0NBTElDIEwXAY6gBEwWAYugBFIXAYygBFIOAqygBFlBBwzZoAROVU1CRVIgRUlHSFQTAeKgBFkOBd+gBEZJRlRZEALWoARWRQ8E3qAET1JUWRAC1aAEVVIOBv+gBEpPSU5FUg4E2qAETklORRIC46AEVFkOA9KgBE9ORREI5KAEIEhVTkRSRUQSCOWgBFRIT1VTQU5EDgXYoARTRVZFThMC4aAEVFkPAtegBElYEQLgoARUWQ4D26AEVEVODwXdoARISVJUWRAD1KAEUkVFDwXcoARXRU5UWRAB06AETwcYzKAEUFVOQ1RVQVRJT04gQ1JFU0NFTlQgQkFSEwPJoARET1QVCMqgBFVCTEUgRE9UEwTLoARMSU5FFATNoARPVFVTBw2BoARTSUdOIEFOVVNWQVJBDAuAoARDQU5EUkFCSU5EVQwLg6AESklIVkFNVUxJWUEMEPCgBE9MRCBUQU1JTCBWSVJBTUEMC4SgBFVQQURITUFOSVlBDAeCoARWSVNBUkdBBwbGoARWSVJBTUEIDLigBE9XRUwgU0lHTiBBQRMBw6AESRMBxaAEVRIOuaAEQkhBVFRJUFJPTFUgQUESAcKgBEUSAbqgBEkTAbugBEkSAcSgBE8TEPOgBExEIFRBTUlMIFNIT1JUIEUiAfSgBE8SAbygBFUTAb2gBFUSCcCgBFZPQ0FMSUMgTBsBwaAETBoBvqAEUhsBv6AEUgMSgFBJTExFIFBBVFRFUk4gQkxBTksQBoFQRE9UUy0xFgGDUDIXAYdQMxgBj1A0GQGfUDUaAb9QNhsB/1A3HAH/UTgbAb9ROBoB31A3GwHfUTgaAZ9ROBkBr1A2GgHvUDcbAe9ROBoBr1E4GQHPUDcaAc9ROBkBj1E4GAGXUDUZAbdQNhoB91A3GwH3UTgaAbdROBkB11A3GgHXUTgZAZdROBgBp1A2GQHnUDcaAedROBkBp1E4GAHHUDcZAcdROBgBh1E4FwGLUDQYAZtQNRkBu1A2GgH7UDcbAftROBoBu1E4GQHbUDcaAdtROBkBm1E4GAGrUDYZAetQNxoB61E4GQGrUTgYActQNxkBy1E4GAGLUTgXAZNQNRgBs1A2GQHzUDcaAfNROBkBs1E4GAHTUDcZAdNROBgBk1E4FwGjUDYYAeNQNxkB41E4GAGjUTgXAcNQNxgBw1E4FwGDUTgWAYVQMxcBjVA0GAGdUDUZAb1QNhoB/VA3GwH9UTgaAb1ROBkB3VA3GgHdUTgZAZ1ROBgBrVA2GQHtUDcaAe1ROBkBrVE4GAHNUDcZAc1ROBgBjVE4FwGVUDUYAbVQNhkB9VA3GgH1UTgZAbVROBgB1VA3GQHVUTgYAZVROBcBpVA2GAHlUDcZAeVROBgBpVE4FwHFUDcYAcVROBcBhVE4FgGJUDQXAZlQNRgBuVA2GQH5UDcaAflROBkBuVE4GAHZUDcZAdlROBgBmVE4FwGpUDYYAelQNxkB6VE4GAGpUTgXAclQNxgByVE4FwGJUTgWAZFQNRcBsVA2GAHxUDcZAfFROBgBsVE4FwHRUDcYAdFROBcBkVE4FgGhUDYXAeFQNxgB4VE4FwGhUTgWAcFQNxcBwVE4FgGBUTgVAYJQMhYBhlAzFwGOUDQYAZ5QNRkBvlA2GgH+UDcbAf5ROBoBvlE4GQHeUDcaAd5ROBkBnlE4GAGuUDYZAe5QNxoB7lE4GQGuUTgYAc5QNxkBzlE4GAGOUTgXAZZQNRgBtlA2GQH2UDcaAfZROBkBtlE4GAHWUDcZAdZROBgBllE4FwGmUDYYAeZQNxkB5lE4GAGmUTgXAcZQNxgBxlE4FwGGUTgWAYpQNBcBmlA1GAG6UDYZAfpQNxoB+lE4GQG6UTgYAdpQNxkB2lE4GAGaUTgXAapQNhgB6lA3GQHqUTgYAapROBcBylA3GAHKUTgXAYpROBYBklA1FwGyUDYYAfJQNxkB8lE4GAGyUTgXAdJQNxgB0lE4FwGSUTgWAaJQNhcB4lA3GAHiUTgXAaJROBYBwlA3FwHCUTgWAYJROBUBhFAzFgGMUDQXAZxQNRgBvFA2GQH8UDcaAfxROBkBvFE4GAHcUDcZAdxROBgBnFE4FwGsUDYYAexQNxkB7FE4GAGsUTgXAcxQNxgBzFE4FwGMUTgWAZRQNRcBtFA2GAH0UDcZAfRROBgBtFE4FwHUUDcYAdRROBcBlFE4FgGkUDYXAeRQNxgB5FE4FwGkUTgWAcRQNxcBxFE4FgGEUTgVAYhQNBYBmFA1FwG4UDYYAfhQNxkB+FE4GAG4UTgXAdhQNxgB2FE4FwGYUTgWAahQNhcB6FA3GAHoUTgXAahROBYByFA3FwHIUTgWAYhROBUBkFA1FgGwUDYXAfBQNxgB8FE4FwGwUTgWAdBQNxcB0FE4FgGQUTgVAaBQNhYB4FA3FwHgUTgWAaBROBUBwFA3FgHAUTgVAYBROAQB4PMHTgID3uYHRUFEBBCCAUsgUEVSTUlUVEVEIEhFUkUECrHyB1NULUZFRURJTkcDAtgFVkUCA/HzB0lDSwMM8OgHREUgV0lUSCBWRUlMBAuJ5gdHRSBBVCBOSUdIVAMGvOkHRUZDQVNFBQHy9AdTAgbm8gdPQ0NPTEkDB6YBS0VOIEJBUgcbi0dDSVJDTEUgV0lUSCBOT1JUSFdFU1QgQVJST1cHBZTpB0hFQVJUAwL58wdPTQMIjvIHV04gSEVBUlQBAQhTAQnL8wdVQkJMRSBURUEGAef1B1MCBKP1B0NLRVQCAZvoB0cDFJ80SU5FU0UgRU5EIE9GIFNFQ1RJT04JCJU0TEVUVEVSIEEQAoU0QkEQAow0Q0EQAok0REEQAoE0R0EQApY0SEEQAo00SkEQAoA0S0EQApI0TEEQAoY0TUERAoc0UEEQAoo0TkERAoI0R0ESAoM0S0ERAos0UkERAo40WUESAo80Q0EQAoQ0UEEQApE0UkEQApQ0U0EQAog0VEEQApM0VkEQApA0WUEJB540UEFMTEFXQQkNmzRWT1dFTCBTSUdOIEFFFAGZNEUUAZc0SRQBmjRPFAGYNFUCDMAuSElEIExFVFRFUiBBDQLKLkJBDQLHLkRBDQLELkdBDQLRLkhBDQHBLkkNAsMuS0ENAs4uTEENAssuTUENAsguTkEOAsUuR0ENAskuUEENAs0uUkENAtAuU0ENAsYuVEENAcIuVQ0Czy5XQQ0CzC5ZQQYM0i5WT1dFTCBTSUdOIEkRAdMuVQIT1+cHSUxESU5HIENPTlNUUlVDVElPTgIEokBMTEVUBgmZRCBPUEVSQVRPUgQE6+oHSE9STggR7OoHIFdJVEggU09VTkQgV0FWRVMEBM5LU0VZRQIFr+YHUlJJVE8CAYztB1MDBY/tByBTVE9QAw/k6AdUIElOIFNJTEhPVUVUVEUED+XoB1MgSU4gU0lMSE9VRVRURQIEyPMHVFRFUgYDi/MHRkxZAQ7//QNZVEUgT1JERVIgTUFSSwIhnKEHWkFOVElORSBNVVNJQ0FMIFNZTUJPTCBBR09HSSBBUkdJIgWboQdPVEVSSR8Fn6EHR09SR0kjBaChB09URVJJHwSeoQdNRVNJIQSdoQdUUklBHwmaoQdQT0xJIEFSR0kkBaGhB0dPUkdJGguooAdOQVRSSUNISVNNQRsN4qAHVElLRU5PS1lMSVNNQSEC3KAHTUEaEI2gB1BFU08gRUtGT05JVElLT04gBrOgB1hPIE5FTxsChaEHTEkbD6KgB09ERVJNQSBBUkNIQUlPTiIDhKEHTkVPHBXSoAdTVFJPRk9JIFNZTkRFU01PUyBORU8kEK2hB1RFTE9VUyBJQ0hJTUFUT1MiAZGgB1MjBpKgByBESVBMSSQD0aAHTkVPHAWjoAdUSEVNQRoEl6EHUkdPTh0J86AHU1lOVEhFVE9OGwjsoQdLVElLTyBESSEC66EHR0EhAu2hB0tFIQLvoQdOSSEC6aEHUEEhA+qhB1ZPVSEC7qEHWk8ZB9agB0NIQU1JTEkfApigB09OGw+7oAdPUkVWTUEgQVJDSEFJT04iA+egB05FTxsKyaEHUk9BIEtMSVRPTh8GyqEHU1BBVEhJHwXIoQdaWUdPUxkGgaAHREFTRUlBGgaZoQdJQVJHT04cEduhB1NUT0xJIEFQTEkgTUVHQUxJKATaoQdJS1JJIgXcoQdESVBMSSIH3aEHVEhFU0VPUxsW0KEHRVNJUyBBUExJIERZTyBET0RFS0FUQSAV0qEHRElHUkFNTU9TIEVYIERPREVLQVRBIBzRoQdNT05PR1JBTU1PUyBURVNTRVJBIERPREVLQVRBIA3PoQdURVRBUlRJTU9SSU9OIRfToQdSSUdSQU1NT1MgT0tUTyBET0RFS0FUQSMIzqEHVElNT1JJT04bCuehB0ZUT0dHT1MgT1UbBpKhB0dPUkdPTiEblKEHIFBBUkVTVElHTUVOT04gQVJJU1RFUkEgQU5POQSToQdLQVRPMAWVoQdERVhJQRwI5qEHUkFNTUEgR0cbA4ahB1BMSR4JgKEHIEFSQ0hBSU9OGgKvoAdZTxkK5KAHRUtTVFJFUFRPThoG1aAHTEFGUk9OGhW2oQdOQVJYSVMgS0FJIEZUSE9SQSBWT1UbB/ugB0RPRk9OT04aB+igB1BFR0VSTUEaE/SgB1RFUk9OIEFSR09TWU5USEVUT04gC+CgB1BBUkFLQUxFU01BGg6OoAdYTyBFS0ZPTklUSUtPThkSsKEHRkFORVJPU0lTIERJRk9OSUFTIwqvoQdNT05PRk9OSUFTIwuuoQdURVRSQUZPTklBUxoaxaEHSFRPUkEgU0tMSVJPTiBDSFJPTUEgVkFTSVMaDrSgB1RIT1JBIEFSQ0hBSU9OKA+5oQcgREVZVEVST1UgSUNIT1UgDL2hB0RJQVRPTklLSSBESSoCv6EHS0UqBLuhB05BTkErBcKhB0kgQU5PLQTBoQdLQVRPKgK6oQdQQSoCwKEHWk8gFMyhB0VOQVJNT05JT1MgQU5USUZPTklBIBbLoQdJIFlGRVNJUyBURVRBUlRJTU9SSU9OIBfDoQdNQUxBS09OIENIUk9NQSBESUZPTklBUy8KxKEHTU9OT0ZPTklBUyAKvKEHTkFPUyBJQ0hPUyEFx6EHRU5BTk8gFcahB1NLTElST04gQ0hST01BIFNZTkFGSS8FxaEHVkFTSVMoC76hB0RJQVRPTk9OIERJGQ3YoQdHRU5JS0kgRElFU0lTIAbZoQdZRkVTSVMaDpagB09SR09OIEFSQ0hBSU9OIAePoQdORU8gQU5PJAT1oQdLQVRPIBaQoQdQQVJFU1RJR01FTk9OIEFSSVNURVJBLgWRoQdERVhJQR4J8qAHU1lOVEhFVE9O", + "HBC0oQdUSE1JS09OIE4gQVBMT1VOJge1oQdESVBMT1VOGgvFoAdST05USElTTUFUQRkHv6AHSUNIQURJThoJmKEHTUlESUFSR09OHAW3oQdGT05PTh0FtaAHVEhPUkEhArihB09OGhasoQdTQUtJQSBURUxPVVMgSUNISU1BVE9TGwuaoAdPTiBBUkNIQUlPTh4DxqAHTkVPGQ+3oAdLQVRBVkEgVFJPTUlLT04fA/qgB1NNQRwFh6AHSElTVEkaD5ugB0VOVElNQSBBUkNIQUlPTiEHz6AHTkVPIEFOTyUE86EHS0FUTyUE8aEHTUVTTyACkKAHVEEiCZygByBBUkNIQUlPTiMHzqAHTkVPIEFOTycE8qEHS0FUTycE8KEHTUVTTxoFpKAHTEFTTUEfBP+gByBBTk8gBPShB0tBVE8aB7qgB09OVEVWTUEhBcKgByBBTExPGwWJoQdST05JUxsGyqAHVUZJU01BGguCoQdSQVRJTUEgQUxMTyIHgaEHUkNIQUlPTiEDg6EHTkVPIAKyoAdUQR8JzKAHT0tPVUZJU01BIAjUoAdZUE9SUk9PThsGjKAHRU1BU1RJGgbhoAdZTElTTUEZEouhB0xFSU1NQSBEWU8gQ0hST05PTiAMiqEHRU5PUyBDSFJPTk9VIA+OoQdJTUlTRU9TIENIUk9OT1UgEI2hB1RFU1NBUk9OIENIUk9OT04hDIyhB1JJT04gQ0hST05PThsDrqAHTU9JGgbdoAdZR0lTTUEZHKWhB01BUlRZUklBIEFMTEkgREVZVEVST1MgSUNIT1MnDKOhB1BST1RPUyBJQ0hPUyIOpKEHREVZVEVST1MgSUNIT1MiDaqhB0xFR0VUT1MgSUNIT1MiDauhB1BMQUdJT1MgSUNIT1MqDrOhB1RFVEFSVE9TIElDSE9TIwuioQdST1RPUyBJQ0hPUycLsqEHVkFSWVMgSUNIT1MiDqihB1RFVEFSVE9TIElDSE9TKw2poQdMRUdFVE9TIElDSE9TIwinoQdSSUZPTklBUyUJpqEHVE9TIElDSE9TIguxoQdWQVJZUyBJQ0hPUxoK16AHSUtST04gSVNPThkEwKAHTkFOQRkPlaAHT0xJR09OIEFSQ0hBSU9OIAPHoAdORU8aBdugB01BTE9OGgqEoAdYRUlBIERJUExJHwuDoAdFS0ZPTklUSUtP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QUwgQkFSIEFORCBUT1AgSEFMRiBESVZJREVEIEJZIFZFUlRJQ0FMIEJBUgcm1UtXSVRIIEFMTCBCVVQgVVBQRVIgTEVGVCBRVUFEUkFOVCBCTEFDSwwOtVNIT1JJWk9OVEFMIEJBUgwP0EtMRUZUIEhBTEYgQkxBQ0sND9JLT1dFUiBIQUxGIEJMQUNLDBDRS1JJR0hUIEhBTEYgQkxBQ0sMGcJTU01BTEwgQ0lSQ0xFIFRPIFRIRSBSSUdIVA0Nu1NVUEVSSU1QT1NFRCBYDCPDU1RXTyBIT1JJWk9OVEFMIFNUUk9LRVMgVE8gVEhFIFJJR0hUDBDTS1VQUEVSIEhBTEYgQkxBQ0sSFNRLUklHSFQgUVVBRFJBTlQgQkxBQ0sMDc1LVkVSVElDQUwgRklMTAYVjuIHRCBBTlRJQ0xPQ0tXSVNFIEFSUk9XFRa8Uy1ST1RBVEVEIERJVklTSU9OIFNJR04JEJtFU1RFUklTSyBPUEVSQVRPUggGv1dCT0xEIFgJBb9TVUxMRVQIGe7iB0MgV0lUSCBPVkVSTEFJRCBCQUNLU0xBU0gJAe3iB0MJAa3iB0QJC4LyB1JPU1MgRk9STUVFFA+A8gcgV0lUSCBGT1VSIERPVFMaCIHyB1RXTyBET1RTDgbA6gdQT01NRUUNCdJNSU5HIExBTkVTCASdRURBU0gJCudISUdJVCBFSUdIVA4E5EhGSVZFDwPjSE9VUg4E6EhOSU5FDgPgSE9ORQ4F5khTRVZFTg8C5UhJWA4F4khUSFJFRQ8C4UhXTw4E6klaRVJPCgu4VFZJU0lPTiBTSUdOEgSYRUxBU0gJIo/iB09MTEFSIFNJR04gV0lUSCBPVkVSTEFJRCBCQUNLU0xBU0gKCplFVCBPUEVSQVRPUggGnEVFUVVBTFMIDMFTR1JFQVRFUi1USEFOCA7pZEhBTkdVTCBDSElFVUNIFgL3ZCBBEAToZElFVUMUAvZkIEEPBe1kSElFVUgUAvtkIEEPBedkSUVVTkcUAvVkIEEVAf5kVQ8H6mRLSElFVUtIFgL4ZCBBEAXgZElZRU9LFQLuZCBBDwXkZE1JRVVNFALyZCBBDwXhZE5JRVVOFALvZCBBDwfsZFBISUVVUEgWAvpkIEEQBOVkSUVVUBQC82QgQQ8F42RSSUVVTBQC8WQgQQ8E5mRTSU9TEwL0ZCBBDwfrZFRISUVVVEgWAvlkIEEQBeJkSUtFVVQVAvBkIEEJG7JPRUFWWSBXSElURSBSSUdIVFdBUkRTIEFSUk9XCRiJR09SSVpPTlRBTCBCQVIgV0lUSCBOT1RDSAkL7+IHVU1BTiBGSUdVUkUIENHkB0lERU9HUkFQSCBBQ0NFUFQTCNDkB0RWQU5UQUdFEwevZUxMSUFOQ0UTCJ9lVFRFTlRJT04SBqVlQ0VOVFJFEw2XZU9OR1JBVFVMQVRJT04UAqJlUFkUBaNlUlJFQ1QSBY9lRUFSVEgTBIdlSUdIVBMJrWVOVEVSUFJJU0UTCJ1lWENFTExFTlQSBptlRkVNQUxFEwiWZUlOQU5DSUFMFAKLZVJFFAKEZVZFEwODZU9VUhIEkmVIQVZFEwOkZUlHSBIEoGVJVEVNEgzFZEtJTkRFUkdBUlRFThMDx2RPVE8SBZhlTEFCT1ITA6dlRUZUEwKmZU9XEgSaZU1BTEUTB6llRURJQ0lORRQDjmVUQUwTA4plT09OEgSUZU5BTUUTBLBlSUdIVBQCiGVORRIDgGVPTkUSBZ5lUFJJTlQSCMRkUVVFU1RJT04SCKplUkVMSUdJT04UBq5lU09VUkNFFQGhZVQTBKhlSUdIVBIGxmRTQ0hPT0wTBZllRUNSRVQUA4ZlVkVOEwKFZUlYEwaTZU9DSUVUWRMGlWVQRUNJQUwTBJFlVE9DSxQDq2VVRFkTB5xlVUlUQUJMRRQBkGVOFAesZVBFUlZJU0USA4llVEVOEwSCZUhSRUUTAoFlV08SBYxlV0FURVIT", + "A41lT09ECRHI7QdORk9STUFUSU9OIFNPVVJDRQkcq+IHVEFMSUMgTEFUSU4gQ0FQSVRBTCBMRVRURVIgQyQBrOIHUggK0GVLQVRBS0FOQSBBEQHTZUURAullSEESAexlRRIB6mVJEgHtZU8SAetlVREB0WVJEQLVZUtBEgHYZUUSAdZlSRIB2WVPEgHXZVURAu5lTUESAfFlRRIB72VJEgHyZU8SAfBlVREC5GVOQRIB52VFEgHlZUkSAehlTxIB5mVVEQHUZU8RAvZlUkESAfllRRIB92VJEgH6ZU8SAfhlVREC2mVTQRIB3WVFEgHbZUkSAd5lTxIB3GVVEQLfZVRBEgHiZUUSAeBlSRIB42VPEgHhZVURAdJlVREC+2VXQRIB/WVFEgH8ZUkSAf5lTxEC82VZQRIB9WVPEgH0ZVUJFvxkT1JFQU4gQ0hBUkFDVEVSIENIQU1LTxkF/WRKVUVVSQgWtklMQVRJTiBDQVBJVEFMIExFVFRFUiBBHQG3SUIdAbhJQx0BuUlEHQG6SUUdAbtJRh0BvElHHQG9SUgdAb5JSR0Bv0lKHQHASUsdAcFJTB0BwklNHQHDSU4dAcRJTx0BxUlQHQHGSVEdAcdJUh0ByElTHQHJSVQdAcpJVR0By0lWHQHMSVcdAc1JWB0BzklZHQHPSVoODtBJU01BTEwgTEVUVEVSIEEbAdFJQhsB0klDGwHTSUQbAdRJRRsB1UlGGwHWSUcbAddJSBsB2ElJGwHZSUobAdpJSxsB20lMGwHcSU0bAd1JThsB3klPGwHfSVAbAeBJURsB4UlSGwHiSVMbAeNJVBsB5ElVGwHlSVYbAeZJVxsB50lYGwHoSVkbAelJWgkIwFNFU1MtVEhBTggFlkVNSU5VUwkptlRVTFRJUExJQ0FUSU9OIFNJR04gV0lUSCBDSVJDVU1GTEVYIEFDQ0VOVAgP8UhOVU1CRVIgRUlHSFRFRU4UEc9kWSBPTiBCTEFDSyBTUVVBUkUQBepITEVWRU4PB+5IRklGVEVFThMBv2VZFBDMZCBPTiBCTEFDSyBTUVVBUkUQBLVlT1JUWRQGvWUgRUlHSFQVBLplRklWRRYDuWVPVVIVBL5lTklORRUPy2RPTiBCTEFDSyBTUVVBUkUXAbZlRRUFvGVTRVZFThYCu2VJWBUFuGVUSFJFRRYCt2VXTxEG7UhVUlRFRU4PCPJITklORVRFRU4PCfBIU0VWRU5URUVOFRHOZFkgT04gQkxBQ0sgU1FVQVJFEAbvSElYVEVFThMRzWRZIE9OIEJMQUNLIFNRVUFSRQ8D6UhURU4SEMhkIE9OIEJMQUNLIFNRVUFSRRAH7EhISVJURUVOFAHaZFkVBrNlIEVJR0hUFgTfZEZJVkUXA95kT1VSFgS0ZU5JTkUWD8pkT04gQkxBQ0sgU1FVQVJFGAHbZEUWBbJlU0VWRU4XArFlSVgWBd1kVEhSRUUXAtxkV08QBetIV0VMVkUSA/NITlRZFQbYZCBFSUdIVBYE1WRGSVZFFwPUZE9VUhYE2WROSU5FFg/JZE9OIEJMQUNLIFNRVUFSRRgB0WRFFgXXZFNFVkVOFwLWZElYFgXTZFRIUkVFFwLSZFdPCB7CTk9QRU4gQ0VOVFJFIEVJR0hUIFBPSU5URUQgU1RBUggIt1NQQVJBTExFTAkMuVNFUlBFTkRJQ1VMQVIJA5VFTFVTCQq2YE9TVEFMIE1BUksID7hTUkVWRVJTRSBTT0xJRFVTCQyaRUlORyBPUEVSQVRPUggG1+8HU1FVQVJFCAWXRVRJTUVTCQfV7wdSSUFOR0xFEAWKRyBET1dOCAy2U1ZFUlRJQ0FMIEJBUggMvlNXSElURSBCVUxMRVQOBKpOU1RBUgkBruIHWggBvldYCA+N4gdaRVJPIFdJVEggU0xBU0gEEJBUVUxBVElPTiBGVU5DVElPTgUMXk1GTEVYIEFDQ0VOVAUGqucHUyBURU5UAgfZ5wdUWVNDQVBFCQiG5gcgQVQgRFVTSwERrl1KSyBSQURJQ0FMIEJBTUJPTw0D2F1MVUUNDKpdT0xUIE9GIENMT1RIDgLjXU5FDgGGXVgNCLpdUlVTSCBPTkUSA7tdVFdPDBHmXUMtU0lNUExJRklFRCBCSVJEGQTLXUNBUlQZBvBdRFJBR09OGQPgXUVBVBoD7F1WRU4ZBOVdRklTSBoC3F1MWRoD6l1ST0cZBNRdR0FURRoD0F1PTEQZBeJdSE9SU0UZBNpdTEVBRhoD011PTkcZBOddU0FMVBoCxV1FRRoEyV1IRUxMGgOwXUlMSxoFyF1QRUVDSBkO2V1UQU5ORUQgTEVBVEhFUhoE7l1PT1RIGgXzXVVSVExFGQTbXVdJTkQNBJtdSE9LRQ0Dz11JVFkOBqBdVklMSUFODQSBXUxJRkYOBcJdT1RIRVMNAqddT1cMBZ5dREVBVEgNCYpdSVZJTkFUSU9ODQKoXU9HDAfdXUVBVCBPTkUQBd9dVEhSRUURAt5dV08NArhdV0UNAqtdWUUMBKNdRklSRQ0Dyl1PT1QMBeRdR0hPU1QNCL5dUkFTUyBPTkUSBcBdVEhSRUUTAr9dV08MBJhdSEFORA0D4V1FQUQPBpZdUlQgT05FEgOXXVRXTw0Dx11PUk4ME+9dSi1TSU1QTElGSUVEIERSQUdPThkE611FVkVOGQXtXVRPT1RIGgXyXVVSVExFDQOpXUFERQwJiF1LTklGRSBPTkUSA4ldVFdPDAmRXUxBTUUgRk9VUhEDjl1PTkURBZBdVEhSRUUSAo9dV08NB9FdT05HIE9ORRED0l1UV08MBLxdTUVBVA4CtV1TSA0DnV1PT04OBL1dUlRBUg4En11USEVSDgfVXVVORCBPTkUSA9ZdVFdPDAi0XU5FVCBGT1VSEAOxXU9ORRAFs11USFJFRRECsl1XTwwDuV1PTEQMB6RdUEFXIE9ORRADpV1UV08NBYVdRVJTT04MBNddUkFJTg4Bt11NDgGZXVANBYBdRVBFQVQMBItdU0VBTA4Igl1DT05EIE9ORRMFhF1USFJFRRQCg11XTw0Etl1IRUVQDQOvXUlMSw4Ypl1NUExJRklFRCBIQUxGIFRSRUUgVFJVTksYA8ZdT1JOFwTMXVdBTEsYBOhdSEVBVBcG6V1ZRUxMT1cNCIxdTUFMTCBPTkUSA41dVFdPDQSSXU5BS0UOB5RdT1VUIE9ORRIDlV1UV08NCaxdUElSSVQgT05FEwOtXVRXTw0CnF1VTgwFh11UQUJMRQ0Fk11IUkVBRA0EwV1JR0VSDQXxXVVSVExFDAjNXVdBTEsgT05FEQPOXVRXTw4HoV1URVIgT05FEgOiXVRXTw0Hw11FU1QgT05FEQPEXVRXTwQKw2NTVFJPS0UgQlhHCwHUY0QLAdBjSAwB1mNHDAHHY1ANAsxjV0cMAuRjWEcNAuBjV0cMAdVjWg0BxmNHDQHKY1QNAc1jVw4ByGNHDQHFY1oOActjUA4BzmNaDwHhY0cLAc9jTgsB0mNQDAHbY0QMAeJjRwwB3GNaCwHjY1ELAdFjUwwB2mNHDAHTY1AMAdljVAwBxGNXDQHfY0cNAdhjWgwB12NaDQHlY1ANAsljV0cNAd5jWgsBwGNUDAHdY04LAsFjV0cLAsJjWEcBFYHrB0xBTVNIRUxMIE1PQklMRSBQSE9ORQMKrOcHUFBFUiBCT0FSRAUOz+gHSU5HIEhBTkRTIFNJR04DD9vnB1NTSUNBTCBCVUlMRElORwIRmkdFQVIgU0NSRUVOIFNZTUJPTAIQ++YHSU5LSU5HIEJFRVIgTVVHUwkHwvIHR0xBU1NFUwMGy+kHUEJPQVJEAhXX6gdPQ0sgRkFDRSBFSUdIVCBPQ0xPQ0sQB+PqBy1USElSVFkMDNrqB0xFVkVOIE9DTE9DSxEH5uoHLVRISVJUWQsL1OoHRklWRSBPQ0xPQ0sPB+DqBy1USElSVFkMCtPqB09VUiBPQ0xPQ0sPB9/qBy1USElSVFkLC9jqB05JTkUgT0NMT0NLDwfk6gctVEhJUlRZCwrQ6gdPTkUgT0NMT0NLDgfc6gctVEhJUlRZCwzW6gdTRVZFTiBPQ0xPQ0sQB+LqBy1USElSVFkMCdXqB0lYIE9DTE9DSw4H4eoHLVRISVJUWQsK2eoHVEVOIE9DTE9DSw4H5eoHLVRISVJUWQwL0uoHSFJFRSBPQ0xPQ0sQB97qBy1USElSVFkMDNvqB1dFTFZFIE9DTE9DSxEH5+oHLVRISVJUWQ0I0eoHTyBPQ0xPQ0sOB93qBy1USElSVFkFGMFSV0lTRSBDTE9TRUQgQ0lSQ0xFIEFSUk9XCw+yRE9OVE9VUiBJTlRFR1JBTAoog+oHRE9XTldBUkRTIEFORCBVUFdBUkRTIE9QRU4gQ0lSQ0xFIEFSUk9XUwoT809HQVBQRUQgQ0lSQ0xFIEFSUk9XCgixRElOVEVHUkFMChG7Q09QRU4gQ0lSQ0xFIEFSUk9XCiDY6wdSSUdIVCBBTkQgTEVGVCBTRU1JQ0lSQ0xFIEFSUk9XUw8mgeoHV0FSRFMgQU5EIExFRlRXQVJEUyBPUEVOIENJUkNMRSBBUlJPV1M1GYLqByBXSVRIIENJUkNMRUQgT05FIE9WRVJMQVkKFLdDVE9QIFNFTUlDSVJDTEUgQVJST1cLIO5WUklBTkdMRS1IRUFERUQgT1BFTiBDSVJDTEUgQVJST1cDBdBAU0UgVVAFBtXpB0QgQk9PSwcYzVRJTlRFUlNFQ1RJT04gV0lUSCBTRVJJRlMHDZDqB0xPQ0sgV0lUSCBLRVkHGerpB01BSUxCT1ggV0lUSCBMT1dFUkVEIEZMQUcUC+vpB1JBSVNFRCBGTEFHBwbPVVNVQlNFVA0M0VUgT1IgRVFVQUwgVE8JBtBVUEVSU0VUDwzSVSBPUiBFUVVBTCBUTwcIguYHVU1CUkVMTEEIEMxUTklPTiBXSVRIIFNFUklGUxgS0FQgQU5EIFNNQVNIIFBST0RVQ1QDAoFMVUQFD6nmByBXSVRIIExJR0hUTklORwsEp+YHUkFJTgsEqOYHU05PVwsHquYHVE9STkFETwMHofIHV04gRkFDRQED5fMHT0FUAgez9QdDS1JPQUNIBAr45gdUQUlMIEdMQVNTAwTl8gdPTlVUAgSwTUZGSU4CApn1B0lOAg6l6QdMTElTSU9OIFNZTUJPTAMCOk9OBQfURCBFUVVBTFMGBKFBU0lHTgIUgQZNQklOSU5HIEFDVVRFIEFDQ0VOVBYGlwYgQkVMT1cQCcEGVE9ORSBNQVJLDwzJOy1HUkFWRS1BQ1VURRAGxztNQUNST04QDdM1VkVSVElDQUwtTElORQsUzAZMTU9TVCBFUVVBTCBUTyBBQk9WRRoF/TtCRUxPVwsN50FOTlVJVFkgU1lNQk9MDBfUQVRJQ0xPQ0tXSVNFIEFSUk9XIEFCT1ZFGAzaQVJJTkcgT1ZFUkxBWQsN8EFTVEVSSVNLIEFCT1ZFEwXZBkJFTE9XCgu7pgRCSU5EVSBCRUxPVwsEhgZSRVZFDwauBiBCRUxPVw8HyzstTUFDUk9ODArGBklER0UgQUJPVkURBaoGQkVMT1cKC5AGQ0FORFJBQklORFUMA4wGUk9ODwasBiBCRUxPVwsGpwZFRElMTEELEIIGSVJDVU1GTEVYIEFDQ0VOVBsGrQYgQkVMT1cLFNVBTE9DS1dJU0UgQVJST1cgQUJPVkUUDNlBUklORyBPVkVSTEFZCwqTBk9NTUEgQUJPVkUVBpUGIFJJR0hUEAWmBkJFTE9XDA+m/ANOSk9JTklORyBNQUNST04bBq38AyBCRUxPVwsWhQlZUklMTElDIERBU0lBIFBORVVNQVRBExXxzAJIVU5EUkVEIE1JTExJT05TIFNJR04bDogJVEhPVVNBTkRTIFNJR04TBvzMAktBVllLQRMI9ltMRVRURVIgQRoC4FtCRRsG/ltJRyBZVVMaA/FbQ0hFGgLjW0RFGwT4W0pFUlYaAp7NAkVGGwHnW0wbAehbTRsB6VtOGwHsW1IbAe1bUxwD9VstVEUaBPRbRklUQRoD4ltHSEUaAu9bSEEcB/jMAlJEIFNJR04aAfXMAkkbAfdbRRsJ/FtPVElGSUVEIEEjB/9bQklHIFlVUyMBn80CRRoC5ltLQRoK/VtMSVRUTEUgWVVTGgz5W01PTk9HUkFQSCBVSxoB6ltPGwT7zAJNRUdBGgLrW1BFGgPyW1NIQRwD81tDSEEbCPrMAk9GVCBTSUdOGgLuW1RFGwLwW1NFGgH3zAJVGwv0zAJLUkFJTklBTiBJRRoC4VtWRRoD+ltZQVQbA/nMAkVSVRsB9swCSRsB+1tVGgLlW1pFGwLkW0hFEw2JCU1JTExJT05TIFNJR04TDoQJUEFMQVRBTElaQVRJT04VBf3MAllFUk9LFAeHCU9LUllUSUUUDYYJU0lMSSBQTkVVTUFUQRMlj8EHU01BTEwgTEVUVEVSIEJZRUxPUlVTU0lBTi1VS1JBSU5JQU4gSRMR8MwCVEVOIE1JTExJT05TIFNJR04UFfLMAkhPVVNBTkQgTUlMTElPTlMgU0lHThQEgwlJVExPGAqu/AMgTEVGVCBIQUxGGQqv/ANSSUdIVCBIQUxGEwXvzAJWWk1FVAoN+ztERUxFVElPTiBNQVJLDBTo0QJWQU5BR0FSSSBESUdJVCBFSUdIVBsE5dECRklWRRwD5NECT1VSGwTp0QJOSU5FGwPh0QJPTkUbBefRAlNFVkVOHALm0QJJWBsF49ECVEhSRUUcAuLRAldPGwTg0QJaRVJPFQjq0QJMRVRURVIgQRwC7NECS0EcAu3RAk5BHALu0QJQQRwC79ECUkEcAevRAlUcAvDRAlZJFQ3x0QJTSUdOIEFWQUdSQUhBCwiIBklBRVJFU0lTEwakBiBCRUxPVxQU3DVXSVRIIFJBSVNFRCBMRUZUIERPVBMFsTUtUklORwsIhwZPVCBBQk9WRRMF+DsgTEVGVBQF2AZSSUdIVA4FowZCRUxPVxMF+jsgTEVGVA0P3TUtQU5ELVJJTkcgQkVMT1cNEME7VEVEIEFDVVRFIEFDQ0VOVBEMwDtHUkFWRSBBQ0NFTlQMEYsGVUJMRSBBQ1VURSBBQ0NFTlQSCec1UkNIIEFCT1ZFFgXmNUJFTE9XEQXdBkJSRVZFFgbcBiBCRUxPVxEFzzVDQVJPThIPzTtJUkNVTUZMRVggQUJPVkURDI8GR1JBVkUgQUNDRU5UEQ7hBklOVkVSVEVEIEJSRVZFHwb8OyBCRUxPVxEIswZMT1cgTElORREG3gZNQUNST04XBt8GIEJFTE9XEQ+4NU9QRU4gTUFSSyBCRUxPVxIHvwZWRVJMSU5FERG8NVBBUkVOVEhFU0VTIEFCT1ZFEg7JNUxVUyBTSUdOIEFCT1ZFGwXKNUJFTE9XERbrNVJJR0hUV0FSRFMgQVJST1cgQUJPVkUiBeIGQkVMT1cTCNoGTkcgQkVMT1cRBeAGVElMREUWCqL8AyBMRUZUIEhBTEYXCqP8A1JJR0hUIEhBTEYRE44GVkVSVElDQUwgTElORSBBQk9WRR8FyAZCRUxPVxoO5kFTVFJPS0UgT1ZFUkxBWRATsDVEIENJUkNVTUZMRVggQUNDRU5UDA3bNVdOIFRBQ0sgQUJPVkUUBZ4GQkVMT1cOC7M1V0FSRFMgQVJST1cKEN1BRU5DTE9TSU5HIENJUkNMRRoK4EEgQkFDS1NMQVNIFAffQURJQU1PTkQUBuNBS0VZQ0FQFAbiQVNDUkVFThUF3kFRVUFSRRQY5EFVUFdBUkQgUE9JTlRJTkcgVFJJQU5HTEULEOg1UVVBTFMgU0lHTiBBQk9WRRYFxwZCRUxPVwoH0gZGRVJNQVRBCwjaNUxBVCBTSUdOCw7cQU9VUiBET1RTIEFCT1ZFChWAwAdHTEFHT0xJVElDIExFVFRFUiBBWlUcB6jA", + "B0JJRyBZVVMdA4HAB1VLWRwGncAHQ0hSSVZJHAaMwAdESkVSVkkdBITAB09CUk8cBKrAB0ZJVEEdBJfAB1JJVFUcB4PAB0dMQUdPTEkcBJjAB0hFUlUcAYvAB0kdC4rAB05JVElBTCBJWkhFHQ6pwAdPVEFURUQgQklHIFlVUyQJp8AHU01BTEwgWVVTHQOJwAdaSEUcBI3AB0tBS08cB47AB0xKVURJSkUcB4/AB01ZU0xJVEUcBZDAB05BU0hJHAORwAdPTlUcBpLAB1BPS09KSRwFk8AHUklUU0kcA57AB1NIQR4Cm8AHVEEdBJTAB0xPVk8dCKTAB01BTEwgWVVTHAOcwAdUU0kdBZXAB1ZSSURPHAOWwAdVS1UcBILAB1ZFREUcBKHAB1lBVEkdA6DAB0VSSR8Bn8AHVR4DhcAHU1RVHQGmwAdPHQGjwAdVHAaIwAdaRU1MSkEdBobAB0hJVkVURQsR66YEUkFOVEhBIERJR0lUIEZJVkUZA+qmBE9VUhgD56YET05FGAPspgRTSVgYBemmBFRIUkVFGQLopgRXTxgE5qYEWkVSTxII8KYETEVUVEVSIEEZAvGmBEtBGQLypgROQRkC9KYEUEEZAvOmBFZJDQzPBlBIRU1FIEpPSU5FUg0JgAZWRSBBQ0NFTlQWBpYGIEJFTE9XEAnABlRPTkUgTUFSSw8MyDstQUNVVEUtR1JBVkUQBsU7TUFDUk9OEA3RNVZFUlRJQ0FMLUxJTkUME8QGRUVLIERJQUxZVElLQSBUT05PUxAHwwZLT1JPTklTEBHEpAdNVVNJQ0FMIFBFTlRBU0VNRRgJw6QHVEVUUkFTRU1FGQbCpAdSSVNFTUUQC8IGUEVSSVNQT01FTkkQDcUGWVBPR0VHUkFNTUVOSQoQywZIT01PVEhFVElDIEFCT1ZFDAiJBk9LIEFCT1ZFDAKbBlJOCgiyNUlORklOSVRZDAyRBlZFUlRFRCBCUkVWRRgGrwYgQkVMT1cVCuM1SURHRSBBQk9WRRoFugZCRUxPVxMRxzVET1VCTEUgQVJDSCBBQk9WRR8FqwZCRUxPVwsH0DtTIEJFTE9XCiiaYUtBVEFLQU5BLUhJUkFHQU5BIFNFTUktVk9JQ0VEIFNPVU5EIE1BUkscEZlhVk9JQ0VEIFNPVU5EIE1BUksMD/c7VllLQSBBQk9WRSBMRUZUFwX2O1JJR0hUChzbO0xBVElOIExFVFRFUiBTTUFMTCBDQVBJVEFMIEclAd47TCUB3ztNJQHhO04lAeI7UhAO4wZTTUFMTCBMRVRURVIgQR4P8jsgV0lUSCBESUFFUkVTSVMeAdQ7RR4E5ztMUEhBHgHVO08eAdY7Vh0B6DtCHgPpO0VUQR0B6AZDHgjXOyBDRURJTExBHQHpBkQdAeQGRR4C7ztTSB4C2TtUSB0B6ztGHhXTO0xBVFRFTkVEIE9QRU4gQSBBQk9WRR0B2jtHHQHqBkgdAeUGSR4I2DtOU1VMQVIgRCUBzDVHJQHNNVIlAc41VB0B3DtLHQHdO0weGew7IFdJVEggRE9VQkxFIE1JRERMRSBUSUxERR4F5TtPTkcgUx0B6wZNHQHgO04dAeYGTx4P8zsgV0lUSCBESUFFUkVTSVMkG+07TElHSFQgQ0VOVFJBTElaQVRJT04gU1RST0tFHQHuO1AdAewGUh4GyjsgQkVMT1cfB+M7Uk9UVU5EQR0B5DtTHgTqO0NIV0EdAe0GVB4NwDVVUk5FRCBXIEJFTE9XHQHnBlUeD/Q7IFdJVEggRElBRVJFU0lTJBvwO0xJR0hUIENFTlRSQUxJWkFUSU9OIFNUUk9LRR0B7gZWHQHxO1ceBr81IEJFTE9XHQHvBlgdAeY7WgsPmgZFRlQgQU5HTEUgQUJPVkUVBckGQkVMT1cVDek1Q0VOVFJFRCBBQk9WRRAK1kFSUk9XIEFCT1ZFFQXuQUJFTE9XFAr+O0hFQUQgQUJPVkUZBdQGQkVMT1cPD9EGSEFMRiBSSU5HIEFCT1ZFGQWcBkJFTE9XEQvQQVJQT09OIEFCT1ZFDxbBNVBBUkVOVEhFU0lTIEFCT1ZFIExFRlQbCsM1QkVMT1cgTEVGVA8R4UFSSUdIVCBBUlJPVyBBQk9WRRsFzQZCRUxPVw8K4DVUQUNLIEFCT1ZFFAWYBkJFTE9XDhPqQVdBUkRTIEFSUk9XIE9WRVJMQVkUG+1BSEFSUE9PTiBXSVRIIEJBUkIgRE9XTldBUkRTCxGg/ANJR0FUVVJFIExFRlQgSEFMRhwGp/wDIEJFTE9XEwqh/ANSSUdIVCBIQUxGHQao/AMgQkVMT1cNHrk1SFQgQ0VOVFJBTElaQVRJT04gU1RST0tFIEJFTE9XCxrrQU9ORyBET1VCTEUgU09MSURVUyBPVkVSTEFZDw+4BlNPTElEVVMgT1ZFUkxBWRANtgZUUk9LRSBPVkVSTEFZDxXSQVZFUlRJQ0FMIExJTkUgT1ZFUkxBWQwGsgZXIExJTkUKBoQGTUFDUk9OEAaxBiBCRUxPVxEJpPwDTEVGVCBIQUxGGgar/AMgQkVMT1cRCqX8A1JJR0hUIEhBTEYbBqz8AyBCRUxPVxAGxDstQUNVVEUWBtg1LUdSQVZFEQXMO0JSRVZFEQXGO0dSQVZFEQ3VNVZFUlRJQ0FMLUxJTkULD+I1SU5VUyBTSUdOIEFCT1ZFFQWgBkJFTE9XCg/KBk5PVCBUSUxERSBBQk9WRQsQxjVVTUJFUiBTSUdOIEFCT1ZFCgaoBk9HT05FSxAGzjsgQUJPVkULE/aGBExEIFBFUk1JQyBMRVRURVIgQU4cA/eGBERPSRwF+YYETkVOT0UcA/qGBFNJSRwE+IYEWkFUQQsOtzVQRU4gTUFSSyBCRUxPVwsHhQZWRVJMSU5FChahBlBBTEFUQUxJWkVEIEhPT0sgQkVMT1cMD7s1UkVOVEhFU0VTIEFCT1ZFFgW9NUJFTE9XFge+NU9WRVJMQVkLDsg1TFVTIFNJR04gQUJPVkUUBZ8GQkVMT1cKFKIGUkVUUk9GTEVYIEhPT0sgQkVMT1cMFeVBVkVSU0UgU09MSURVUyBPVkVSTEFZEQ2UBkQgQ09NTUEgQUJPVkULENdBSUdIVCBBUlJPVyBBQk9WRRYF70FCRUxPVxUK0AZIRUFEIEFCT1ZFGxf/O05EIERPV04gQVJST1dIRUFEIEJFTE9XHhLWBlVQIEFSUk9XSEVBRCBCRUxPVxoF1QZCRUxPVxAP1wZIQUxGIFJJTkcgQUJPVkUaBbkGQkVMT1cSC9FBUlBPT04gQUJPVkUQF8I1UEFSRU5USEVTSVMgQUJPVkUgUklHSFQcC8Q1QkVMT1cgUklHSFQQCuE1VEFDSyBBQk9WRRUFmQZCRUxPVw8h7EFXQVJEUyBIQVJQT09OIFdJVEggQkFSQiBET1dOV0FSRFMMCIoGTkcgQUJPVkUPBaUGQkVMT1cPB9hBT1ZFUkxBWQoN5TVTRUFHVUxMIEFCT1ZFEgW8BkJFTE9XCwnZNUhBUlAgU0lHTgwTtwZPUlQgU09MSURVUyBPVkVSTEFZEQ21BlRST0tFIE9WRVJMQVkQFdNBVkVSVElDQUwgTElORSBPVkVSTEFZCwrCO05BS0UgQkVMT1cLC+Q1UVVBUkUgQUJPVkURBbsGQkVMT1cSDcU1UkFDS0VUUyBBQk9WRQshujVUUk9ORyBDRU5UUkFMSVpBVElPTiBTVFJPS0UgQkVMT1cLDsM7VVNQRU5TSU9OIE1BUksKENtBVEhSRUUgRE9UUyBBQk9WRQsEgwZJTERFDwawBiBCRUxPVxAPqfwDTEVGVCBIQUxGIEJFTE9XEAe0Bk9WRVJMQVkQEKr8A1JJR0hUIEhBTEYgQkVMT1cLEss1UklQTEUgQUNVVEUgQUNDRU5UEQO0NURPVBEI6EFVTkRFUkRPVAsRkgZVUk5FRCBDT01NQSBBQk9WRQoN9TtVUCBUQUNLIEFCT1ZFEgWdBkJFTE9XDBHqNVdBUkRTIEFSUk9XIEFCT1ZFGAXOBkJFTE9XCwfRO1IgQUJPVkULB9I7UyBBQk9WRQoTjQZWRVJUSUNBTCBMSU5FIEFCT1ZFGAWpBkJFTE9XEwW+BlRJTERFEgvQNS1MSU5FLUFDVVRFHQbWNS1HUkFWRRgF0jVHUkFWRR0G1zUtQUNVVEUYBtQ1TUFDUk9OChHpQVdJREUgQlJJREdFIEFCT1ZFDxX5O0lOVkVSVEVEIEJSSURHRSBCRUxPVwwPtjVHR0xZIExJTkUgQkVMT1cKB70GWCBBQk9WRQwF0wZCRUxPVwsItTUtWCBCRUxPVwoM2wZaSUdaQUcgQUJPVkURBc87QkVMT1cDAoRMRVQDAixNQQQJQEVSQ0lBTCBBVAsK0kBNSU5VUyBTSUdOAwTt8wdQQVNTBAaBRExFTUVOVAQOhEdPU0lUSU9OIFNZTUJPTAQH3OsHUkVTU0lPTgILiucHTkZFVFRJIEJBTEwEC5bsB09VTkRFRCBGQUNFBAmV7AdVU0VEIEZBQ0UDFe1UR1JVRU5UIFdJVEggRE9UIEFCT1ZFAwqyRklDQUwgVEFQRVIDCIxMSlVOQ1RJT04DDqftB1NUUlVDVElPTiBTSUdODQb36AdXT1JLRVIDD4tEVEFJTlMgQVMgTUVNQkVSDA+zRU5PUk1BTCBTVUJHUk9VUBsMtUUgT1IgRVFVQUwgVE8JG/pFV0lUSCBMT05HIEhPUklaT05UQUwgU1RST0tFDgf9RU9WRVJCQVIOKPtFVkVS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RVhURU5ERUQgQkhBTEUeCoW2BCBXSVRIIEhPT0sQEPESSElHSCBTUEFDSU5HIERPVBAUgBJJTlZFUlRFRCBDQU5EUkFCSU5EVRAFibYETUlORFUQBbwSTlVLVEEQCPjRAlBVU0hQSUtBEBiItgRSRVZFUlNFRCBOSU5FLUxJS0UgQkhBTEUQB/zRAlNJRERIQU0REvLRAlBBQ0lORyBDQU5EUkFCSU5EVRAGzRJWSVJBTUESBYMSU0FSR0EQF4a2BFdFU1RFUk4gRklWRS1MSUtFIEJIQUxFGA+HtgROSU5FLUxJS0UgQkhBTEUME9ISVFJFU1MgU0lHTiBBTlVEQVRUQRcG0RJVREFUVEELDb4SVk9XRUwgU0lHTiBBQRcByBJJFwHMElUXAc8SVxcB/9ECWRYIxRJDQU5EUkEgRR0G1RJMT05HIEUdAckSTxYBxxJFFgG/EkkXAcASSRYByxJPFwG6EkUXArsST0UWD84SUFJJU0hUSEFNQVRSQSBFFgfGElNIT1JUIEUcAcoSTxYBwRJVFwHWEkUXAcISVRgB1xJFFgniElZPQ0FMSUMgTB8B4xJMHgHDElIfAcQSUgMQFElDRSBDT05UUk9MIEZPVVIPAxFPTkUPBpABU1RSSU5HDwUTVEhSRUUQAhJXTwEIqAFJQUVSRVNJUwMVw5gHR09OQUwgQ1JPU1NIQVRDSCBGSUxMAwqARk1FVEVSIFNJR04EDMRFT05EIE9QRVJBVE9SCBeg6QdTSEFQRSBXSVRIIEEgRE9UIElOU0lERQgGnO8HVEFSR0VUCBaZVldJVEggQk9UVE9NIEhBTEYgQkxBQ0sND5ZWTEVGVCBIQUxGIEJMQUNLDRCXVlJJR0hUIEhBTEYgQkxBQ0sNDphWVE9QIEhBTEYgQkxBQ0sCCIBNRSBGQUNFLTEJAYFNMgkBgk0zCQGDTTQJAYRNNQkBhU02Aw7y7QdTRUwgTE9DT01PVElWRQIQz0RGRkVSRU5DRSBCRVRXRUVOAgk4R0lUIEVJR0hUCwaJ4gcgQ09NTUEMCY9JRlVMTCBTVE9QBgQ1RklWRQoGhuIHIENPTU1BCwmMSUZVTEwgU1RPUAcDNE9VUgoGheIHIENPTU1BCwmLSUZVTEwgU1RPUAYEOU5JTkUKBoriByBDT01NQQsJkElGVUxMIFNUT1AGAzFPTkUJBoLiByBDT01NQQoJiElGVUxMIFNUT1AGBTdTRVZFTgsGiOIHIENPTU1BDAmOSUZVTEwgU1RPUAcCNklYCQaH4gcgQ09NTUEKCY1JRlVMTCBTVE9QBgUzVEhSRUULBoTiByBDT01NQQwJiklGVUxMIFNUT1AHAjJXTwkGg+IHIENPTU1BCgmJSUZVTEwgU1RPUAYEMFpFUk8KBoHiByBDT01NQQsJgOIHRlVMTCBTVE9QAw2FpgdSQU0gRk9SIEVBUlRIEAmDpgdMWSBIRUFWRU4UBISmB1VNQU4LDIxNR1JFQVRFUiBZQU5HFAKPTUlOCw6BpgdIRUFWRU5MWSBFQVJUSAwKgqYHVU1BTiBFQVJUSAsLjk1MRVNTRVIgWUFORxMCjU1JTgIOsUZNRU5TSU9OIE9SSUdJTgIkh09OR0JBVCBDSVJDTEVEIFNBTlMtU0VSSUYgRElHSVQgRUlHSFQhBIRPRklWRSIDg09PVVIhBIhPTklORSEDgE9PTkUhBYZPU0VWRU4iAoVPSVghBYJPVEhSRUUiAoFPV08hBIviB1pFUk8bColPTlVNQkVSIFRFTggc/U5ORUdBVElWRSBDSVJDTEVEIERJR0lUIEVJR0hUHwT6TkZJVkUgA/lOT1VSHwT+Tk5JTkUfA/ZOT05FHwX8TlNFVkVOIAL7TklYHwX4TlRIUkVFIAL3TldPGQr/Tk5VTUJFUiBURU4ZFpFPU0FOUy1TRVJJRiBESUdJVCBFSUdIVCoEjk9GSVZFKwONT09VUioEkk9OSU5FKgOKT09ORSoFkE9TRVZFTisCj09JWCoFjE9USFJFRSsCi09XTyoEjOIHWkVSTyQKk09OVU1CRVIgVEVOAhyTR1JFQ1QgQ1VSUkVOVCBTWU1CT0wgRk9STSBUV08HA6/nB0hJVAIKzU1TQUJMRUQgQ0FSBBql7AdQUE9JTlRFRCBCVVQgUkVMSUVWRUQgRkFDRQ0EnuwHRkFDRQMbgkdDT05USU5VT1VTIFVOREVSTElORSBTWU1CT0wDC/jyB0dVSVNFRCBGQUNFAwvq9QdUT1JURUQgRkFDRQIIg2BUVE8gTUFSSwIV2LIEVkVTIEFLVVJVIERJR0lUIEVJR0hUEgTVsgRGSVZFEwPUsgRPVVISBNmyBE5JTkUSA9GyBE9ORRIF17IEU0VWRU4TAtayBElYEgXTsgRU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RRYC9klXTw8K/klOVU1CRVIgVEVOCAr0VE9MT04gRVFVQUwICb9PVVJMWSBMT09QBwahQERBR0dFUggI6lVPV04gVEFDSwcQvEBFWENMQU1BVElPTiBNQVJLBx6fQEhJR0gtUkVWRVJTRUQtOSBRVU9UQVRJT04gTUFSSwgFwFxZUEhFTgcIrERJTlRFR1JBTAsI0kVSU0VDVElPTgcdlVNMRUZUIEFSQyBHUkVBVEVSLVRIQU4gQlJBQ0tFVAgK01RPR0lDQUwgQU5EDwLUVE9SCQaXQFcgTElORQoRnkAtOSBRVU9UQVRJT04gTUFSSwsZwlxSRVZFUlNFRC05IFFVT1RBVElPTiBNQVJLBxOiVU5FU1RFRCBHUkVBVEVSLVRIQU4OCaFVTEVTUy1USEFOFw6jVSBXSVRIIFVOREVSQkFSBw6XXE9CTElRVUUgSFlQSEVOBwT6U1BMVVMIB7tVUkVDRURFUwkDs0BJTUUMD55gIFFVT1RBVElPTiBNQVJLBw3HQFFVRVNUSU9OIE1BUksHG5ZTUklHSFQgQVJDIExFU1MtVEhBTiBCUkFDS0VUBxD9VVNPTElEVVMgT1BFUkFUT1IIEs5UUVVBUkUgSU5URVJTRUNUSU9ODgXPVFVOSU9OCAzJXFRBQ0tFRCBDT01NQQkN7FVST0tFIE5PVCBTSUdOCAXQRVVCU0VUCQa8VUNDRUVEUwkG0UVQRVJTRVQJDcRcU1BFTlNJT04gTUFSSwcF00VVTklPTggG61VQIFRBQ0sHDPhHVkVSVElDQUwgQkFSExblVSBET1VCTEUgTEVGVCBUVVJOU1RJTEUbD6tFUklHSFQgVFVSTlNUSUxFFA7jVUxFRlQgVFVSTlNUSUxFEASWQExJTkUHDcz8A1dBVlkgT1ZFUkxJTkUGD99TLUVOREVEIE1VTFRJTUFQBx2aVUxJTkUgRVFVQUwgVE8gT1IgR1JFQVRFUi1USEFOGAmZVUxFU1MtVEhBTgwgnFVTTEFOVEVEIEVRVUFMIFRPIE9SIEdSRUFURVItVEhBTiAJm1VMRVNTLVRIQU4UGPpVR1JFQVRFUi1USEFOIE9SIEVRVUFMIFRPFBX5VUxFU1MtVEhBTiBPUiBFUVVBTCBUTwcQgkJTVFJVQ0sgQ0FQSVRBTCBDFgW+QkdBTU1BFgGNQkgWAZVCThYBmUJQFwG/QkkWAZpCURYBnUJSFgGkQloOEMVCSVRBTElDIENBUElUQUwgRBUHxkJTTUFMTCBEGwHHQkUbAchCSRsByUJKDg/AQk4tQVJZIFNVTU1BVElPTg4LvUJTTUFMTCBHQU1NQRQCvEJQSQYNok1EIEZFTUFMRSBTSUdOCAmjTU1BTEUgU0lHTggG/FdTWU1CT0wDBenmB0dITlVUAgvK6gdWRSBPRiBQRUFDRQIMhEZXTiBBUlJPV0hFQUQFCf9SRklTSCBUQUlMBRfxRVJJR0hUIERJQUdPTkFMIEVMTElQU0lTBQSkRVRBQ0sJEvFVIFdJVEggQ0lSQ0xFIEJFTE9XBCT3mActRkFDSU5HIFNOQUtFIEhFQUQgV0lUSCBDTE9TRUQgTU9VVEgcCvOYB09QRU4gTU9VVEgFEfibB1BPSU5USU5HIEFJUlBMQU5FDwrjmAdUT01JQyBCT01CDgv7mAdFTkVSR1kgV0FWRQ4E/JsHRlJPRw4KmpkHUkFDSU5HIENBUg8Lu+oHRUQgVFJJQU5HTEUPBOiYB0lGTEUPCtmYB09DS0VUIFNISVAOEr3qB1NNQUxMIFJFRCBUUklBTkdMRQ8LhJgHVElDSyBGSUdVUkUOHehTVFJJQU5HTEUgV0lUSCBMRUZUIEhBTEYgQkxBQ0scEOlTUklHSFQgSEFMRiBCTEFDSwQQiPIHV0FSRCBGQUNJTkcgSE9PSxQJivIHIFdJVEggRE9UEAyJ8gdOT1RDSEVEIEhPT0scCYvyByBXSVRIIERPVAgIlFxTIEFOQ09SQQsEk0NSUk9XDxu39wcgQU5EIFJJR0hUIE9ORSBFSUdIVEggQkxPQ0sQCKdDRlJPTSBCQVIQGvVDTEVGVFdBUkRTIE9GIFVQV0FSRFMgQVJST1cQBpNSVE8gQkFSEBW1Q1dJVEggQ09STkVSIExFRlRXQVJEUxUN30NET1VCTEUgU1RST0tFFRWX8AdFUVVJTEFURVJBTCBBUlJPV0hFQUQVEYhSSE9SSVpPTlRBTCBTVFJPS0UVGIvwB0xBUkdFIFRSSUFOR0xFIEFSUk9XSEVBRBUZh/AHTUVESVVNIFRSSUFOR0xFIEFSUk9XSEVBRBUMm/EHTk9UQ0hFRCBUQUlMFRuT8AdTTUFMTCBFUVVJTEFURVJBTCBBUlJPV0hFQUQbEoPwB1RSSUFOR0xFIEFSUk9XSEVBRBUNskNUSVAgTEVGVFdBUkRTGQqzQ1JJR0hUV0FSRFMKC4dWQkxBQ0sgQVJST1cVB7PxByBUTyBCQVIQE4tXQ0lSQ0xFRCBXSElURSBBUlJPVwoQv/AHQ09NUFJFU1NFRCBBUlJPVwoM40NEQVNIRUQgQVJST1cLC9NDT1VCTEUgQVJST1cKEbfwB0ZJTkdFUi1QT1NUIEFSUk9XCj/lUkhBUlBPT04gV0lUSCBCQVJCIExFRlQgQkVTSURFIERPV05XQVJEUyBIQVJQT09OIFdJVEggQkFSQiBSSUdIVCgf71JVUFdBUkRTIEhBUlBPT04gV0lUSCBCQVJCIFJJR0hUIQjhUkZST00gQkFSIQbZUlRPIEJBUiAFw0NXQVJEUxwO3VJSSUdIVCBGUk9NIEJBUiIG1VJUTyBCQVIhBcJDV0FSRFMLCsfwB0VBVlkgQVJST1cQEMPwB0NPTVBSRVNTRUQgQVJST1cKDcpDUEFJUkVEIEFSUk9XUwoP8U9RVUFEUlVQTEUgQVJST1cKBu/sB1JPQ0tFVAoQ0/AHU0FOUy1TRVJJRiBBUlJPVwsMu/AHUVVBUkVEIEFSUk9XChKT8QdUUklBTkdMRSBBUlJPV0hFQUQSDeNWLUhFQURFRCBBUlJPVx8rg1cgTEVGVFdBUkRTIE9GIFVQV0FSRFMgVFJJQU5HTEUtSEVBREVEIEFSUk9XIAbzVlRPIEJBUiAPq/AHV0lUSCBCT0xEIFNIQUZUJRj9VkRPVUJMRSBIT1JJWk9OVEFMIFNUUk9LRSULr/AHSEVBVlkgU0hBRlQlEqBXTE9ORyBUSVAgTEVGVFdBUkRTLgqhV1JJR0hUV0FSRFMlDKfwB01FRElVTSBTSEFGVCUMo/AHTkFSUk9XIFNIQUZUJRCz8AdWRVJZIEhFQVZZIFNIQUZUGgztVkRBU0hFRCBBUlJPVxoNh1dQQUlSRUQgQVJST1dTGgzNVlpJR1pBRyBBUlJPVw0Ji1JQTEUgQVJST1cLD6FDV08gSEVBREVEIEFSUk9XDSbvVy1IRUFERUQgQVJST1cgV0lUSCBUUklBTkdMRSBBUlJPV0hFQURTCgvpQ1dISVRFIEFSUk9XFRqX8QcgV0lUSElOIFRSSUFOR0xFIEFSUk9XSEVBRAoMr0NaSUdaQUcgQVJST1cBC69B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IERBU0gDBIBAUVVBRAMFgkBTUEFDRQIRlwFEIE9GIEdVQVJERUQgQVJFQQcECkxJTkUHBhlNRURJVU0HBY5EUFJPT0YKC5cBVEVDVEVEIEFSRUEHDYcBU0VMRUNURUQgQVJFQQcEA1RFWFQICwRSQU5TTUlTU0lPThMGFyBCTE9DSwQamuoHV0lUSCBMRUZUV0FSRFMgQVJST1cgQUJPVkUCAQVRAwQFVUlSWQIKhkdURVIgU1lNQk9MAgaJTlZFTE9QRQgb6ekHIFdJVEggRE9XTldBUkRTIEFSUk9XIEFCT1ZFDgmE6wdMSUdIVE5JTkcBAgpPTAIBGU0CAQRUAQKXAVBBARTVRVFVQUwgQU5EIFBBUkFMTEVMIFRPBhDdRFRPIEJZIERFRklOSVRJT04JD91FT1IgR1JFQVRFUi1USEFODAncRUxFU1MtVEhBTgwI3kVQUkVDRURFUwwI30VTVUNDRUVEUwUH1URTIENPTE9OBwQ9U0lHTgsWwFYgQUJPVkUgTEVGVFdBUkRTIEFSUk9XEgnxVFBMVVMgU0lHThIQ8VJSSUdIVFdBUkRTIEFSUk9XEg7zVFRJTERFIE9QRVJBVE9SDRPjU05EIFNMQU5URUQgUEFSQUxMRUwgEeRTIFdJVEggVElMREUgQUJPVkUMEK5VV0lUSCBCVU1QWSBBQk9WRREJ5lRET1QgQkVMT1cRDpZXSU5GSU5JVFkgQUJPVkUaBflXQkVMT1cRIfdUVFdPIERPVFMgQUJPVkUgQU5EIFRXTyBET1RTIEJFTE9XBw3uVFdJVEggQVNURVJJU0sDC9pESUFOR1VMQVIgVE8ECc1EVkFMRU5UIFRPCxT4VFdJVEggRk9VUiBET1RTIEFCT1ZFARCrRlJBU0UgVE8gVEhFIExFRlQNBaZGUklHSFQCC/BXSVMgRk9STSBPTkUKA/FXVFdPAhfzU1JPUi1CQVJSRUQgQkxBQ0sgQ0lSQ0xFEwfxU0RJQU1PTkQTBu9TU1FVQVJFDQzyU1dISVRFIENJUkNMRRMH8FNESUFNT05EEwbuU1NRVUFSRQEChwFTQQIBG0MDAxtBUEUCDq5CVElNQVRFRCBTWU1CT0wIAdlEUwECF1RCAgzlJkhJT1BJQyBDT0xPTgso3SZNQklOSU5HIEdFTUlOQVRJT04gQU5EIFZPV0VMIExFTkdU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AYYlTxQBhyVBEwGBJVUTAoglV0EVAYslQRQBjSVFFQGMJUUUAYolSRMC0FtZQRUB01tBFAHVW0UVAdRbRRQB0ltJFAHWW08UAdFbVRIC6CVZQRQB6yVBEwHtJUUUAewlRRMB6iVJEwHuJU8UAe8lQRMB6SVVEgLYJVpBFAHbJUETAd0lRRQB3CVFEwLgJUhBFQHjJUEUAeUlRRUB5CVFFAHiJUkUAeYlTxQB4SVVFALnJVdBEwHaJUkTAd4lTxQBi1tBEwHZJVUTAt8lV0ETArBbWkEVAbNbQRQBtVtFFQG0W0UUAbJbSRQBtltPFAGxW1UJEZYnVE9OQUwgTUFSSyBDSElSRVQUBZEnREVSRVQZBpgnLUhJREVUFQSUJ0lGQVQUBZcnSElERVQUBZUnS0VOQVQVA5knVVJUFAaSJ1JJS1JJSxQMkydTSE9SVCBSSUtSSUsUBZAnWUlaRVQJCeEmV09SRFNQQUNFAgEDWAENh0JVTEVSIENPTlNUQU5UAgXInQdOT01JQQIHrEFSTyBTSUdOBA6gQS1DVVJSRU5DWSBTSUdOBAvw5wdQRUFOIENBU1RMRQkL5OcHUE9TVCBPRkZJQ0UBDbLmB1ZFUkdSRUVOIFRSRUUBBblEWENFU1MDDSFMQU1BVElPTiBNQVJLDA3JQFFVRVNUSU9OIE1BUksCEoKcB1BMT1NJT04gQVQgSE9SSVpPTgoH/ZsHRlJBTUUtMRAB/psHMhAB/5sHMwMQkewHUkVTU0lPTkxFU1MgRkFDRQIf+A1URU5ERUQgQVJBQklD", + "LUlORElDIERJR0lUIEVJR0hUHAT1DUZJVkUdA/QNT1VSHAT5DU5JTkUcA/ENT05FHAX3DVNFVkVOHQL2DUlYHAXzDVRIUkVFHQLyDVdPHATwDVpFUk8DE/3oB1JBVEVSUkVTVFJJQUwgQUxJRU4EILTvB0VNRUxZIEhFQVZZIEZJVkUgU1BPS0VEIEFTVEVSSVNLEAun7wdHUkVFSyBDUk9TUxAHru8HU0FMVElSRRESuu8HSVggU1BPS0VEIEFTVEVSSVNLEAyJ7wdXSElURSBDSVJDTEUWBpPvB1NRVUFSRQECwegHWUUDB9PoB0dMQVNTRVMDAcDoB1MAF/nyB0ZBQ0UgSE9MRElORyBCQUNLIFRFQVJTBQeG6QdNQVNTQUdFBQSm8gdQQUxNBRiL7AdTQVZPVVJJTkcgREVMSUNJT1VTIEZPT0QGELHsB0NSRUFNSU5HIElOIEZFQVIFD5jsB1RIUk9XSU5HIEEgS0lTUwUU6fUHV0lUSCBCQUdTIFVOREVSIEVZRVMKCpPsB0NPTEQgU1dFQVQMCKDyB1dCT1kgSEFUCg7k9QdESUFHT05BTCBNT1VUSAobq/IHRklOR0VSIENPVkVSSU5HIENMT1NFRCBMSVBTCgyV8gdIRUFELUJBTkRBR0UKD6TsB0xPT0sgT0YgVFJJVU1QSAoMt+wHTUVESUNBTCBNQVNLCwbQ8wdPTk9DTEUKD8XsB05PIEdPT0QgR0VTVFVSRQoKxuwHT0sgR0VTVFVSRQsRqPIHTkUgRVlFQlJPVyBSQUlTRUQLHOL1B1BFTiBFWUVTIEFORCBIQU5EIE9WRVIgTU9VVEgPBa7sB01PVVRIFA+w7AcgQU5EIENPTEQgU1dFQVQVCK7yB1ZPTUlUSU5HChjz8gdQQVJUWSBIT1JOIEFORCBQQVJUWSBIQVQLCuP1B0VFS0lORyBFWUULDPryB0xFQURJTkcgRVlFUwoMxOwHUk9MTElORyBFWUVTChCb7AdTVFVDSy1PVVQgVE9OR1VFGhid7AcgQU5EIFRJR0hUTFktQ0xPU0VEIEVZRVMfC5zsB1dJTktJTkcgRVlFCgyC7AdURUFSUyBPRiBKT1kLCpLyB0hFUk1PTUVURVIKGvTyB1VORVZFTiBFWUVTIEFORCBXQVZZIE1PVVRICQm27AdPVVQgTU9VVEgDC7tCU0lNSUxFIFNJR04DBO3nB1RPUlkCA9rzB0lSWQIFxvMHTEFGRUwDCMLmB0xFTiBMRUFGBCavUklORyBESUFHT05BTCBDUk9TU0lORyBOT1JUSCBFQVNUIEFSUk9XGg+sUlJJU0lORyBESUFHT05BTBEf3k1JTiBXSElURSBDSVJDTEUgSU4gQkxBQ0sgU1FVQVJFAgTq6AdNSUxZAgqrTFJTSSBTWU1CT0wCDoXnB1RIRVIgQ0hSSVNUTUFTAga36wdYIElDT04EB+DpB01BQ0hJTkUBC6jsB0VBUkZVTCBGQUNFAwS29QdUSEVSAgnATE1BTEUgU0lHTgMXqgFJTklORSBPUkRJTkFMIElORElDQVRPUgIEuvIHTkNFUgIKoecHUlJJUyBXSEVFTAQB9E1ZAQEMRgEa0ecHSUVMRCBIT0NLRVkgU1RJQ0sgQU5EIEJBTEwCCe/1B0dIVCBDTE9VRAMIkkBVUkUgREFTSAcFh0BTUEFDRQIKxOsHTEUgQ0FCSU5FVAUGwekHRk9MREVSBQkcU0VQQVJBVE9SAwie5wdNIEZSQU1FUwUJ/ekHUFJPSkVDVE9SAgnG9QdOR0VSUFJJTlQDEY1USVRFIFBBUlQgSU5URUdSQUwCAqXqB1JFBAeS7QcgRU5HSU5FBgvv8wdYVElOR1VJU0hFUgQH6PMHQ1JBQ0tFUgQNh+cHV09SSyBTUEFSS0xFUggBhucHUwMOx/IHU1QgUExBQ0UgTUVEQUwGDL1MUVVBUlRFUiBNT09OEgeT5gcgU1lNQk9MEwmb5gdXSVRIIEZBQ0UGDuhAU1RST05HIElTT0xBVEUCAp/oB1NIBBfl5gcgQ0FLRSBXSVRIIFNXSVJMIERFU0lHTgQDyUtFWUUEEaPnB0lORyBQT0xFIEFORCBGSVNIAw3K6AdURUQgSEFORCBTSUdOAgutXFZFIERPVCBNQVJLCQvZQFBVTkNUVUFUSU9OAQvzTUxBRyBJTiBIT0xFAwWp8wdNSU5HTwMKlpkHUFBJTkcgQklSRAMG//IHVCBTSE9FBAXT9QdCUkVBRAQE5UdORVNTAgqcTUVVUi1ERS1MSVMDCqrpB1hFRCBCSUNFUFMCCb7pB09QUFkgRElTSwMCwp0HUkEFB+ZOTCBIRUFSVAMDmE1XRVIGDrTnByBQTEFZSU5HIENBUkRTCA/VQFVOQ1RVQVRJT04gTUFSSwIKs+wHVVNIRUQgRkFDRQMCiPUHVEUCAbD1B1kDCM/yB0lORyBESVNDBwiF6wdFTlZFTE9QRQcG+O0HU0FVQ0VSDQf7mQcgU1lNQk9MDgrKmAdXSVRIIEJFQU1TEgnLmAdPVVQgQkVBTVMBAqvmB09HAwKB5gdHWQIEwOsHTERFUgQMrfUHSU5HIEhBTkQgRkFOAgTV9QdORFVFAgK28wdPVAQG4+gHUFJJTlRTAgWARFIgQUxMAwOpRUNFUwML9OYHSyBBTkQgS05JRkUOC/3mByBXSVRIIFBMQVRFBA6QXEVEIFBBUkFHUkFQSE9TBAPcVUlORwMGDE0gRkVFRAkFDCAoRkYpAwTMnQdUVU5BBgjg8gdFIENPT0tJRQIG8k1VTlRBSU4DGaNOUiBCQUxMT09OLVNQT0tFRCBBU1RFUklTSwUUpU5DTFVCLVNQT0tFRCBBU1RFUklTSwYjlFdPUk5FUiBBUlJPV1MgQ0lSQ0xJTkcgQU5USUNMT0NLV0lTRQUI20BET1QgTUFSSwkL2EBQVU5DVFVBVElPTgULwOYHTEVBRiBDTE9WRVIFEsbvB1BPSU5URUQgQkxBQ0sgU1RBUgUYok5URUFSRFJPUC1TUE9LRUQgQVNURVJJU0sEDYVALVBFUi1FTSBTUEFDRQQHnERUSCBST09UAgaK8wdYIEZBQ0UBFd9CUkFDVElPTiBOVU1FUkFUT1IgT05FCQXEQFNMQVNIAwu6nQdHSUxFIFNZTUJPTAMMvusHTUUgV0lUSCBBTiBYCwe86wdQSUNUVVJFCwW96wdUSUxFUwIL9vIHRUVaSU5HIEZBQ0UDDqNBTkNIIEZSQU5DIFNJR04JA9/mB0lFUwIK5OYHSUVEIFNIUklNUAIHuOgHT0cgRkFDRQMUpegHTlQtRkFDSU5HIEJBQlkgQ0hJQ0sGJqxPVElMVEVEIFNIQURPV0VEIFdISVRFIFJJR0hUV0FSRFMgQVJST1cDAqJGV04FGKbsB0lORyBGQUNFIFdJVEggT1BFTiBNT1VUSAEBHFMCAehASQEI/U1VRUwgUFVNUAIIiEtMTCBCTE9DSwULleYHTU9PTiBTWU1CT0wKCZ3mB1dJVEggRkFDRQUK109PVVRFUiBKT0lOBQQuU1RPUAQPhv4DV0lEVEggQU1QRVJTQU5ECwmH/gNQ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EALjIVVOEAPVIVZJThAC8yFXRRAD7iFYQU4QAvchWU4QA9YhWkVOEQPfIUhBUgkbvTlNVEFWUlVMSSBDQVBJVEFMIExFVFRFUiBBRU4iAro5SU4iAZA5TiEDkTlCQU4hA6o5Q0FOIgOtOUhBUiMCqTlJTiICrDlJTCEDkzlET04hBbg5RUxJRkkiAZQ5TiECtjlGSSEDkjlHQU4iA6Y5SEFOIQOwOUhBRSMBtDlSJAa+OUQgU0lHTiIBsTlFIgKyOUlFIgK1OU9FIQKYOUlOIQSvOUpIQU4iAqs5SUwhA5k5S0FOIgOlOUhBUiELvzlMQUJJQUwgU0lHTiMBmjlTIQObOU1BTiEDnDlOQVIhAp05T04hA545UEFSIgOkOUhBUiEDpzlRQVIhA6A5UkFFIQOhOVNBTiIDqDlISU4hA5c5VEFOIwGiOVIiCbk5VVJORUQgR0FOIQKjOVVOIQOVOVZJTiECszlXRSEDrjlYQU4hArc5WU4hA5Y5WkVOIgOfOUhBUgkT+yFQQVJBR1JBUEggU0VQQVJBVE9SCRCtWlNNQUxMIExFVFRFUiBBRU4XAYBaThYDgVpCQU4WA5paQ0FOFwOdWkhBUhgCmVpJThcCnFpJTBYDg1pET04WAoRaRU4WA4JaR0FOFwOWWkhBThYDoFpIQUUYAaRaUhcBoVpFFwKiWklFFwKlWk9FFgKIWklOFgSfWkpIQU4XAptaSUwWA4laS0FOFwOVWkhBUhYDilpMQVMWA4taTUFOFgOMWk5BUhYCjVpPThYDjlpQQVIXA5RaSEFS", + "FgOXWlFBUhYDkFpSQUUWA5FaU0FOFwOYWkhJThYDh1pUQU4YAZJaUhYCk1pVThYDhVpWSU4WAqNaV0UWA55aWEFOFgKnWllOFgOGWlpFThcDj1pIQVICD7BBUk1BTiBQRU5OWSBTSUdOAgeTYFRBIE1BUksBBPvoB0hPU1QBC7dCSU1FTCBTWU1CT0wCCdr1B05HRVIgUk9PVAIKkvMHUkFGRkUgRkFDRQMB5+gHTAQIyu0HUyBTWU1CT0wBHIBYTEFHT0xJVElDIENBUElUQUwgTEVUVEVSIEFaVRoHqFhCSUcgWVVTGwOBWFVLWRoOr1hDQVVEQVRFIENIUklWSRsFnVhIUklWSRoGjFhESkVSVkkbBIRYT0JSTxsEh1haRUxPGgSqWEZJVEEbBJdYUklUVRoHg1hHTEFHT0xJGgSYWEhFUlUaAYtYSRsLilhOSVRJQUwgSVpIRRsOqVhPVEFURUQgQklHIFlVUyIJp1hTTUFMTCBZVVMbA4lYWkhFHQSrWElUU0EaBI1YS0FLTxoQrlhMQVRJTkFURSBNWVNMSVRFGwaOWEpVRElKRRoHj1hNWVNMSVRFGgWQWE5BU0hJGgORWE9OVRsCmVhUVRoCmlhQRRsFklhPS09KSRoFk1hSSVRTSRoDnlhTSEEcAptYVEEeA6xYUElDGwSUWExPVk8bCKRYTUFMTCBZVVMjCqVYIFdJVEggVEFJTBsJolhQSURFUlkgSEEaDK1YVFJPS1VUQVNUSSBBGwKcWFNJGwWVWFZSSURPGgOWWFVLVRoEglhWRURFGgShWFlBVEkbA6BYRVJJHQGfWFUcA4VYU1RVGwGmWE8bAaNYVRoGiFhaRU1MSkEbBoZYSElWRVRFCxCwWFNNQUxMIExFVFRFUiBBWlUYB9hYQklHIFlVUxkDsVhVS1kYDt9YQ0FVREFURSBDSFJJVkkZBc1YSFJJVkkYBrxYREpFUlZJGQS0WE9CUk8ZBLdYWkVMTxgE2lhGSVRBGQTHWFJJVFUYB7NYR0xBR09MSRgEyFhIRVJVGAG7WEkZC7pYTklUSUFMIElaSEUZDtlYT1RBVEVEIEJJRyBZVVMgCddYU01BTEwgWVVTGQO5WFpIRRsE21hJVFNBGAS9WEtBS08YEN5YTEFUSU5BVEUgTVlTTElURRkGvlhKVURJSkUYB79YTVlTTElURRgFwFhOQVNISRgDwVhPTlUZAslYVFUYAspYUEUZBcJYT0tPSkkYBcNYUklUU0kYA85YU0hBGgLLWFRBHAPcWFBJQxkExFhMT1ZPGQjUWE1BTEwgWVVTIQrVWCBXSVRIIFRBSUwZCdJYUElERVJZIEhBGAzdWFRST0tVVEFTVEkgQRkCzFhTSRkFxVhWUklETxgDxlhVS1UYBLJYVkVERRgE0VhZQVRJGQPQWEVSSRsBz1hVGgO1WFNUVRkB1lhPGQHTWFUYBrhYWkVNTEpBGQa2WEhJVkVURQMK2/IHU1MgT0YgTUlMSwIK5lNFSUNIIFNUQVJLAhKQ5gdPQkUgV0lUSCBNRVJJRElBTlMDA+TzB1ZFUwMJn+YHV0lORyBTVEFSAQfF8gdPQUwgTkVUAwGQ6AdUAgX98gdHR0xFUwIEzOcHTEZFUgIG/e4HTkdHT05HAgO/9QdPU0UCBY3zB1JJTExBAhCwhgRUSElDIExFVFRFUiBBSFNBDwW0hgRJSFZVUw4HsYYEQkFJUktBTg4Es4YEREFHUw4DuYYERUlTDgXGhgRGQUlIVQ4EsoYER0lCQQ4Et4YESEFHTA8EyIYEV0FJUg4Fx4YESUdHV1MPA7aGBFVKQQ4DvoYESkVSDgW6hgRLVVNNQQ4Fu4YETEFHVVMOBbyGBE1BTk5BDga9hgROQVVUSFMPC8qGBElORSBIVU5EUkVEEgLBhgRUWQ4FyYYET1RIQUwOCMCGBFBBSVJUSFJBDgi1hgRRQUlSVEhSQQ4FwoYEUkFJREEOBcOGBFNBVUlMDgXEhgRURUlXUw8FuIYESElVVEgOBL+GBFVSVVMOBcWGBFdJTkpBAQ2T5wdSQURVQVRJT04gQ0FQAxPXpgROVEhBIEFVIExFTkdUSCBNQVJLCAiFpgRMRVRURVIgQRABhqYEQRABkKYESRABlKYEVQ8CrKYEQkEQAq2mBEhBDwKapgRDQRACm6YESEEPAqamBERBEAKhpgREQRECoqYESEEQAqemBEhBDwKPpgRFRQ8Cl6YER0EQApimBEhBDwK5pgRIQQ8Bh6YESRABiKYESQ8CnKYESkEQAp2mBEhBDwKVpgRLQRAClqYESEEPArKmBExBEAKzpgRMQQ8CrqYETUEPAqimBE5BEAKZpgRHQRACo6YETkEQAp6mBFlBDwKTpgRPTw8CqqYEUEEQAqumBEhBDwKwpgRSQQ8CuKYEU0EQAramBEhBEAK3pgRTQQ8CpKYEVEEQAqWmBEhBEAKfpgRUQRECoKYESEEPAYmmBFUQAYqmBFUPArWmBFZBEA3epgRFRElDIEFOVVNWQVJBFQ/fpgRET1VCTEUgQU5VU1ZBUkEQCIymBE9DQUxJQyBMGAHhpgRMFwGLpgRSGAHgpgRSDwKvpgRZQQgC0KYET00IDYKmBFNJR04gQU5VU1ZBUkEOB72mBFZBR1JBSEENC4GmBENBTkRSQUJJTkRVDheApgRPTUJJTklORyBBTlVTVkFSQSBBQk9WRQ0FvKYETlVLVEENBd2mBFBMVVRBDQbNpgRWSVJBTUEPBYOmBFNBUkdBCA2+pgRWT1dFTCBTSUdOIEFBFAHIpgRJFAHMpgRVEwLHpgRFRRMBv6YESRQBwKYESRMCy6YET08TAcGmBFUUAcKmBFUTCeKmBFZPQ0FMSUMgTBwB46YETBsBw6YEUhwBxKYEUgMDx+YHUEVTAwlgVkUgQUNDRU5UAjKMVUVBVEVSLVRIQU4gQUJPVkUgRE9VQkxFLUxJTkUgRVFVQUwgQUJPVkUgTEVTUy1USEFOEyGSVUxFU1MtVEhBTiBBQk9WRSBET1VCTEUtTElORSBFUVVBTBMQ+FJSSUdIVFdBUkRTIEFSUk9XExeQVVNJTUlMQVIgQUJPVkUgTEVTUy1USEFOGwiOVU9SIEVRVUFMFDCUVUxBTlRFRCBFUVVBTCBBQk9WRSBMRVNTLVRIQU4gQUJPVkUgU0xBTlRFRCBFUVVBTA4SilVORCBOT1QgQVBQUk9YSU1BVEURGIhVU0lOR0xFLUxJTkUgTk9UIEVRVUFMIFRPDRClVUJFU0lERSBMRVNTLVRIQU4OD+lEVVQgTk9UIEVRVUFMIFRPGArnRUlWQUxFTlQgVE8ND6dVQ0xPU0VEIEJZIENVUlZFHBSpVSBBQk9WRSBTTEFOVEVEIEVRVUFMDRXbRUVRVUFMIFRPIE9SIExFU1MtVEhBTg0OhlVPUiBBUFBST1hJTUFURRAI5URFUVVBTCBUTxMK80RJVkFMRU5UIFRPEAn3RExFU1MtVEhBThAQ/lRTTEFOVEVEIEVRVUFMIFRPIA+CVSBXSVRIIERPVCBBQk9WRS8FhFUgTEVGVCoGgFVJTlNJREUODOdEVkVSIEVRVUFMIFRPERGkVUxBUFBJTkcgTEVTUy1USEFODQQ+U0lHTg0S+lRXSVRIIENJUkNMRSBJTlNJREUSA9dFRE9UEhP8VFFVRVNUSU9OIE1BUksgQUJPVkUDGcSCBEVLIEFDUk9QSE9OSUMgQVRUSUMgRklGVFkcCNGCBCBTVEFURVJTHQfKggRUQUxFTlRTHgfHggRIT1VTQU5EJQjWggQgU1RBVEVSUxkCw4IEVkUbCMWCBCBIVU5EUkVEIwjTggQgU1RBVEVSUyQHzIIEVEFMRU5UUxwHz4IEU1RBVEVSUxwHyIIEVEFMRU5UUx0HxoIESE9VU0FORCQIzoIEIFRBTEVOVFMXC8KCBE9ORSBEUkFDSE1BGwTBggRIQUxGHA7SggRVTkRSRUQgU1RBVEVSUyMHy4IEVEFMRU5UUxsHwIIEUVVBUlRFUhsQ1IIEVEhPVVNBTkQgU1RBVEVSUyQHzYIEVEFMRU5UUxcI14IEVEVOIE1OQVMbB9CCBFNUQVRFUlMbB8mCBFRBTEVOVFMcD9WCBEhPVVNBTkQgU1RBVEVSUxEW74IEQ0FSWVNUSUFOIEZJVkUgSFVORFJFRBIU3YIEWVJFTkFJQyBUV08gRFJBQ0hNQVMREfOCBERFTFBISUMgRklWRSBNTkFTERfsggRFUElEQVVSRUFOIEZJVkUgSFVORFJFRBwD24IEVFdPHwneggQgRFJBQ0hNQVMRFNiCBEhFUkFFVU0gT05FIFBMRVRIUk9OFA3oggRNSU9OSUFOIEZJRlRZHAPaggRPTkUcA+KCBFRFThEN44IETUVTU0VOSUFOIFRFThET8IIETkFYSUFOIEZJVkUgSFVORFJFRBET9IIEU1RSQVRJQU4gRklGVFkgTU5BUxEO6YIEVEhFU1BJQU4gRklGVFkcCu6CBFZFIEhVTkRSRUQfCPKCBFRIT1VTQU5EGgPZggRPTkUdCOqCBCBIVU5EUkVEHgjxggRUSE9VU0FORBoD5IIEVEVOGwXlggRISVJUWRwL64IEUkVFIEhVTkRSRUQbAtyCBFdPEg/mggRST0VaRU5JQU4gRklGVFkhD+eCBCBBTFRFUk5BVEUgRk9STR4C34IEVkUgCO2CBCBIVU5EUkVEHAPgggRURU4fD+GCBCBBTFRFUk5BVEUgRk9STQcJhwdOTyBURUxFSUEHCoeDBFJPVVJBIFNJR04ICYaDBFRBQkUgU0lHTgYL0AdCRVRBIFNZTUJPTAYi/gdDQVBJVEFMIERPVFRFRCBMVU5BVEUgU0lHTUEgU1lNQk9MDgrPB0tBSSBTWU1CT0wODJEHTEVUVEVSIEFMUEhBGguJPiBXSVRIIERBU0lBJQmNPiBBTkQgT1hJQS4TjT8gQU5EIFBST1NHRUdSQU1NRU5JKguPPlBFUklTUE9NRU5JNROPPyBBTkQgUFJPU0dFR1JBTU1FTkkrDYk/Uk9TR0VHUkFNTUVOSSoFiz5WQVJJQS8Tiz8gQU5EIFBST1NHRUdSQU1NRU5JIAa5P01BQ1JPTiAEuz9PWElBIA68P1BST1NHRUdSQU1NRU5JIQSIPlNJTEklCYw+IEFORCBPWElBLhOMPyBBTkQgUFJPU0dFR1JBTU1FTkkqC44+UEVSSVNQT01FTkk1E44/IEFORCBQUk9TR0VHUkFNTUVOSSsNiD9ST1NHRUdSQU1NRU5JKgWKPlZBUklBLxOKPyBBTkQgUFJPU0dFR1JBTU1FTkkgBYYHVE9OT1MgBbo/VkFSSUEhBbg/UkFDSFkWDPIGUkNIQUlDIFNBTVBJFQSSB0JFVEEVA6cHQ0hJFQWUB0RFTFRBFQeVB0VQU0lMT04cC5k+IFdJVEggREFTSUEnCZ0+IEFORCBPWElBLAWbPlZBUklBIgTJP09YSUEiBZg+UFNJTEknCZw+IEFORCBPWElBLAWaPlZBUklBIgWIB1RPTk9TIgXIP1ZBUklBFgKXB1RBGAupPiBXSVRIIERBU0lBIwmtPiBBTkQgT1hJQSwTnT8gQU5EIFBST1NHRUdSQU1NRU5JKAuvPlBFUklTUE9NRU5JMxOfPyBBTkQgUFJPU0dFR1JBTU1FTkkpDZk/Uk9TR0VHUkFNTUVOSSgFqz5WQVJJQS0Tmz8gQU5EIFBST1NHRUdSQU1NRU5JHgTLP09YSUEeDsw/UFJPU0dFR1JBTU1FTkkfBKg+U0lMSSMJrD4gQU5EIE9YSUEsE5w/IEFORCBQUk9TR0VHUkFNTUVOSSgLrj5QRVJJU1BPTUVOSTMTnj8gQU5EIFBST1NHRUdSQU1NRU5JKQ2YP1JPU0dFR1JBTU1FTkkoBao+VkFSSUEtE5o/IEFORCBQUk9TR0VHUkFNTUVOSR4FiQdUT05PUx4Fyj9WQVJJQRUFkwdHQU1NQRUE8AZIRVRBFQSZB0lPVEEZC7k+IFdJVEggREFTSUEkCb0+IEFORCBPWElBKQu/PlBFUklTUE9NRU5JKQW7PlZBUklBIAiqB0lBTFlUSUtBHwbZP01BQ1JPTh8E2z9PWElBHwW4PlBTSUxJJAm8PiBBTkQgT1hJQSkLvj5QRVJJU1BPTUVOSSkFuj5WQVJJQR8FigdUT05PUx8F2j9WQVJJQSAF2D9SQUNIWRUFmgdLQVBQQRUFmwdMQU1EQRUCnAdNVRUCnQdOVRUFqQdPTUVHQRoL6T4gV0lUSCBEQVNJQSUJ7T4gQU5EIE9YSUEuE60/IEFORCBQUk9TR0VHUkFNTUVOSSoL7z5QRVJJU1BPTUVOSTUTrz8gQU5EIFBST1NHRUdSQU1NRU5JKw2pP1JPU0dFR1JBTU1FTkkqBes+VkFSSUEvE6s/IEFORCBQUk9TR0VHUkFNTUVOSSAE+z9PWElBIA78P1BST1NHRUdSQU1NRU5JIQToPlNJTEklCew+IEFORCBPWElBLhOsPyBBTkQgUFJPU0dFR1JBTU1FTkkqC+4+UEVSSVNQT01FTkk1E64/IEFORCBQUk9TR0VHUkFNTUVOSSsNqD9ST1NHRUdSQU1NRU5JKgXqPlZBUklBLxOqPyBBTkQgUFJPU0dFR1JBTU1FTkkgBY8HVE9OT1MgBfo/VkFSSUEXBZ8HSUNST04cC8k+IFdJVEggREFTSUEnCc0+IEFORCBPWElBLAXLPlZBUklBIgT5P09YSUEiBcg+UFNJTEknCcw+IEFORCBPWElBLAXKPlZBUklBIgWMB1RPTk9TIgX4P1ZBUklBFRL2BlBBTVBIWUxJQU4gRElHQU1NQRYCpgdISRYBoAdJFgKoB1NJFQOhB1JITxgL7D8gV0lUSCBEQVNJQRUD+gdTQU4WAvcHSE8WBKMHSUdNQRUDpAdUQVUWBJgHSEVUQRUHpQdVUFNJTE9OHAvZPiBXSVRIIERBU0lBJwndPiBBTkQgT1hJQSwL3z5QRVJJU1BPTUVOSSwF2z5WQVJJQSMIqwdJQUxZVElLQSIG6T9NQUNST04iBOs/T1hJQSIFjgdUT05PUyIF6j9WQVJJQSMF6D9SQUNIWRUCngdYSRUD/wZZT1QVBJYHWkVUQQ8S+QdVTkFURSBTSUdNQSBTWU1CT0wOI/8HUkVWRVJTRUQgRE9UVEVEIExVTkFURSBTSUdNQSBTWU1CT0wXE/0HTFVOQVRFIFNJR01BIFNZTUJPTA4M9AdUSEVUQSBTWU1CT0wGBf4/REFTSUELCd4/IEFORCBPWElBEAvfP1BFUklTUE9NRU5JEAXdP1ZBUklBBxHuP0lBTFlUSUtBIEFORCBPWElBFAvBP1BFUklTUE9NRU5JFAXtP1ZBUklBEAWFB1RPTk9TBwv7ggRSQUNITUEgU0lHTgYPgIMERklWRSBPQk9MUyBTSUdOBw7/ggRPVVIgT0JPTFMgU0lHTgYLiIMER1JBTU1BIFNJR04GDo2DBElORElDVElPTiBTSUdOCBydpAdTVFJVTUVOVEFMIE5PVEFUSU9OIFNZTUJPTC0xJAGjpAcxJAGkpAcyJAGlpAczJAGmpAc0JAGnpAc3JAGopAc4JAGppAc5IwGepAcyJAGqpAczJAGrpAc0JAGspAc1JAGtpAc2JAGupAc3JAGvpAc5IwKwpAczMCQBsaQHMiQBsqQHNiQBs6QHNyQBtKQHOCQBtaQHOSMBn6QHNCQBtqQHMCQBt6QHMiQBuKQHMyQBuaQHNSQBuqQHNyQBu6QHOCQBvKQHOSMBoKQHNSQBvaQHMCQBvqQHMSQBv6QHMiQBwKQHMyQBwaQHNCMBoaQHNyMBoqQHOAYK1wdLQUkgU1lNQk9MCArwB1BQQSBTWU1CT0wHBr0/T1JPTklTBxCCgwRZQVRIT1MgQkFTRSBTSUdOBhTYB0xFVFRFUiBBUkNIQUlDIEtPUFBBDQfcB0RJR0FNTUEN", + "Bd4HS09QUEENBeAHU0FNUEkOEqY6TUFMTCBDQVBJVEFMIEdBTU1BGwWnOkxBTURBGwXl1gJPTUVHQRsCqDpQSRwCqjpTSRsDqTpSSE8OBdoHVElHTUENA/MHWU9UBwmDgwRJVFJBIFNJR04HEfUGT1dFUiBOVU1FUkFMIFNJR04HFPUHVU5BVEUgRVBTSUxPTiBTWU1CT0wNDPIHU0lHTUEgU1lNQk9MBg2BgwRNRVRSRVRFUyBTSUdOBw3FpAdVU0lDQUwgTEVJTU1BBgz0Bk5VTUVSQUwgU0lHTgYJ/IIET0JPTCBTSUdOBwz1ggRORSBIQUxGIFNJR04TD/aCBCBBTFRFUk5BVEUgRk9STQoMi4MEUVVBUlRFUiBTSUdOBwqEgwRVTktJQSBTSUdOBwP9P1hJQQYLwD9QRVJJU1BPTUVOSQcJ1QdISSBTWU1CT0wHCNYHSSBTWU1CT0wHDb4/Uk9TR0VHUkFNTUVOSQcEvz9TSUxJCwnOPyBBTkQgT1hJQRALzz9QRVJJU1BPTUVOSRAFzT9WQVJJQQYN/gZRVUVTVElPTiBNQVJLBh72B1JFVkVSU0VEIExVTkFURSBFUFNJTE9OIFNZTUJPTAcJ8QdITyBTWU1CT0wKEvwHV0lUSCBTVFJPS0UgU1lNQk9MBg2MgwRTSU5VU09JRCBTSUdOBx/8Bk1BTEwgRE9UVEVEIExVTkFURSBTSUdNQSBTWU1CT0wMDLEHTEVUVEVSIEFMUEhBGAuBPiBXSVRIIERBU0lBIwmFPiBBTkQgT1hJQSwShT8gQU5EIFlQT0dFR1JBTU1FTkkoC4c+UEVSSVNQT01FTkkzEoc/IEFORCBZUE9HRUdSQU1NRU5JKAWDPlZBUklBLRKDPyBBTkQgWVBPR0VHUkFNTUVOSSgNgT9ZUE9HRUdSQU1NRU5JHgaxP01BQ1JPTh4E8T5PWElBIhK0PyBBTkQgWVBPR0VHUkFNTUVOSR4Ltj9QRVJJU1BPTUVOSSkStz8gQU5EIFlQT0dFR1JBTU1FTkkfBIA+U0lMSSMJhD4gQU5EIE9YSUEsEoQ/IEFORCBZUE9HRUdSQU1NRU5JKAuGPlBFUklTUE9NRU5JMxKGPyBBTkQgWVBPR0VHUkFNTUVOSSgFgj5WQVJJQS0Sgj8gQU5EIFlQT0dFR1JBTU1FTkkoDYA/WVBPR0VHUkFNTUVOSR4FrAdUT05PUx4F8D5WQVJJQSMSsj8gQU5EIFlQT0dFR1JBTU1FTkkfBbA/UkFDSFkeDbM/WVBPR0VHUkFNTUVOSRQM2QdSQ0hBSUMgS09QUEEbBfMGU0FNUEkTBLIHQkVUQRMDxwdDSEkTBbQHREVMVEEUBt0HSUdBTU1BEwe1B0VQU0lMT04aC5E+IFdJVEggREFTSUElCZU+IEFORCBPWElBKgWTPlZBUklBIATzPk9YSUEgBZA+UFNJTEklCZQ+IEFORCBPWElBKgWSPlZBUklBIAWtB1RPTk9TIAXyPlZBUklBFAK3B1RBFguhPiBXSVRIIERBU0lBIQmlPiBBTkQgT1hJQSoSlT8gQU5EIFlQT0dFR1JBTU1FTkkmC6c+UEVSSVNQT01FTkkxEpc/IEFORCBZUE9HRUdSQU1NRU5JJgWjPlZBUklBKxKTPyBBTkQgWVBPR0VHUkFNTUVOSSYNkT9ZUE9HRUdSQU1NRU5JHAT1Pk9YSUEgEsQ/IEFORCBZUE9HRUdSQU1NRU5JHAvGP1BFUklTUE9NRU5JJxLHPyBBTkQgWVBPR0VHUkFNTUVOSR0EoD5TSUxJIQmkPiBBTkQgT1hJQSoSlD8gQU5EIFlQT0dFR1JBTU1FTkkmC6Y+UEVSSVNQT01FTkkxEpY/IEFORCBZUE9HRUdSQU1NRU5JJgWiPlZBUklBKxKSPyBBTkQgWVBPR0VHUkFNTUVOSSYNkD9ZUE9HRUdSQU1NRU5JHAWuB1RPTk9THAX0PlZBUklBIRLCPyBBTkQgWVBPR0VHUkFNTUVOSRwNwz9ZUE9HRUdSQU1NRU5JEwvCB0ZJTkFMIFNJR01BEwWzB0dBTU1BEwTxBkhFVEETBLkHSU9UQRcLsT4gV0lUSCBEQVNJQSIJtT4gQU5EIE9YSUEnC7c+UEVSSVNQT01FTkknBbM+VkFSSUEeCMoHSUFMWVRJS0EmCdM/IEFORCBPWElBKwvXP1BFUklTUE9NRU5JKwWQB1RPTk9TKwXSP1ZBUklBHQbRP01BQ1JPTh0E9z5PWElBHQvWP1BFUklTUE9NRU5JHgSwPlNJTEkiCbQ+IEFORCBPWElBJwu2PlBFUklTUE9NRU5JJwWyPlZBUklBHQWvB1RPTk9THQX2PlZBUklBHgXQP1JBQ0hZEwW6B0tBUFBBFATfB09QUEETBbsHTEFNREETArwHTVUTAr0HTlUTBckHT01FR0EYC+E+IFdJVEggREFTSUEjCeU+IEFORCBPWElBLBKlPyBBTkQgWVBPR0VHUkFNTUVOSSgL5z5QRVJJU1BPTUVOSTMSpz8gQU5EIFlQT0dFR1JBTU1FTkkoBeM+VkFSSUEtEqM/IEFORCBZUE9HRUdSQU1NRU5JKA2hP1lQT0dFR1JBTU1FTkkeBP0+T1hJQSIS9D8gQU5EIFlQT0dFR1JBTU1FTkkeC/Y/UEVSSVNQT01FTkkpEvc/IEFORCBZUE9HRUdSQU1NRU5JHwTgPlNJTEkjCeQ+IEFORCBPWElBLBKkPyBBTkQgWVBPR0VHUkFNTUVOSSgL5j5QRVJJU1BPTUVOSTMSpj8gQU5EIFlQT0dFR1JBTU1FTkkoBeI+VkFSSUEtEqI/IEFORCBZUE9HRUdSQU1NRU5JKA2gP1lQT0dFR1JBTU1FTkkeBc4HVE9OT1MeBfw+VkFSSUEjEvI/IEFORCBZUE9HRUdSQU1NRU5JHg3zP1lQT0dFR1JBTU1FTkkVBb8HSUNST04aC8E+IFdJVEggREFTSUElCcU+IEFORCBPWElBKgXDPlZBUklBIAT5Pk9YSUEgBcA+UFNJTEklCcQ+IEFORCBPWElBKgXCPlZBUklBIAXMB1RPTk9TIAX4PlZBUklBExL3BlBBTVBIWUxJQU4gRElHQU1NQRQCxgdISRQBwAdJFALIB1NJEwPBB1JITxYL5T8gV0lUSCBEQVNJQRwF5D9QU0lMSRMF4QdTQU1QSRUB+wdOFAL4B0hPFATDB0lHTUEUBdsHVElHTUETA8QHVEFVFAS4B0hFVEETB8UHVVBTSUxPThoL0T4gV0lUSCBEQVNJQSUJ1T4gQU5EIE9YSUEqC9c+UEVSSVNQT01FTkkqBdM+VkFSSUEhCMsHSUFMWVRJS0EpCeM/IEFORCBPWElBLgvnP1BFUklTUE9NRU5JLgWwB1RPTk9TLgXiP1ZBUklBIAbhP01BQ1JPTiAE+z5PWElBIAvmP1BFUklTUE9NRU5JIQTQPlNJTEklCdQ+IEFORCBPWElBKgvWPlBFUklTUE9NRU5JKgXSPlZBUklBIAXNB1RPTk9TIAX6PlZBUklBIQXgP1JBQ0hZEwK+B1hJEwS2B1pFVEEMI/0GUkVWRVJTRUQgRE9UVEVEIExVTkFURSBTSUdNQSBTWU1CT0wVE/sGTFVOQVRFIFNJR01BIFNZTUJPTAca5jpVQlNDUklQVCBTTUFMTCBMRVRURVIgQkVUQR0D6jpDSEkdBec6R0FNTUEdA+k6UEhJHQPoOlJITwcNoIMEWU1CT0wgVEFVIFJITwYL+oIEVEFMRU5UIFNJR04HC9EHSEVUQSBTWU1CT0wIDv6CBFJFRSBPQk9MUyBTSUdODA34ggRRVUFSVEVSUyBTSUdOBwSEB09OT1MHEYmDBFJZQkxJT04gQkFTRSBTSUdOBw39ggRXTyBPQk9MUyBTSUdOCgv3ggRUSElSRFMgU0lHTgYi0wdVUFNJTE9OIFdJVEggQUNVVEUgQU5EIEhPT0sgU1lNQk9MExnUB0RJQUVSRVNJUyBBTkQgSE9PSyBTWU1CT0wTC9IHSE9PSyBTWU1CT0wGBe8/VkFSSUEHFoCkB09DQUwgTk9UQVRJT04gU1lNQk9MLTEdAYmkBzAdAYqkBzEdAYukBzIdAYykBzMdAY2kBzQdAY6kBzUdAY+kBzYdAZCkBzcdAZGkBzgdAZKkBzkcAYGkBzIdAZOkBzAdAZSkBzEdAZWkBzIdAZakBzMdAZekBzQcAYKkBzMcAYOkBzQcAYSkBzUdAZikBzAdAZmkBzEdAZqkBzIdAZukBzMdAZykBzQcAYWkBzYcAYakBzccAYekBzgcAYikBzkGC4WDBFhFU1RFUyBTSUdOBgn5ggRZRUFSIFNJR04HDPoGUE9HRUdSQU1NRU5JBgmKgwRaRVJPIFNJR04EB8/mB04gQVBQTEUGBNfpB0JPT0sGBZrpB0hFQVJUBgXX8gdTQUxBRAMH9vQHWSBIRUFSVAIMrOwHSU1BQ0lORyBGQUNFAyC47AdOTklORyBDQVQgRkFDRSBXSVRIIFNNSUxJTkcgRVlFUwkEgOwHRkFDRQ0hqvIHIFdJVEggT05FIExBUkdFIEFORCBPTkUgU01BTEwgRVlFEwyB7AdTTUlMSU5HIEVZRVMUCKnyB1RBUiBFWUVTAgjSV09VUCBNQVJLBgkdU0VQQVJBVE9SAwqX6QdXSU5HIEhFQVJUAQEdUwELskFVQVJBTkkgU0lHTgQFgukHRFNNQU4CB67zB0lERSBET0cDA7jnB1RBUgIY8BVKQVJBVEkgQUJCUkVWSUFUSU9OIFNJR04JC+4VRElHSVQgRUlHSFQPBOsVRklWRRAD6hVPVVIPBO8VTklORQ8D5xVPTkUPBe0VU0VWRU4QAuwVSVgPBekVVEhSRUUQAugVV08PBOYVWkVSTwkIhRVMRVRURVIgQREBhhVBEQGQFUkRAZQVVRACrBVCQRECrRVIQRACmhVDQRECmxVIQRACphVEQRECoRVEQRICohVIQRECpxVIQRABjxVFEAKXFUdBEQKYFUhBEAK5FUhBEAGHFUkRAYgVSRACnBVKQRECnRVIQRAClRVLQREClhVIQRACshVMQRECsxVMQRACrhVNQRACqBVOQRECmRVHQRECoxVOQRECnhVZQRABkxVPEAKqFVBBEQKrFUhBEAKwFVJBEAK4FVNBEQK2FUhBEQK3FVNBEAKkFVRBEQKlFUhBEQKfFVRBEgKgFUhBEAGJFVURAYoVVRACtRVWQREIjBVPQ0FMSUMgTBkB4RVMGAGLFVIZAeAVUhACrxVZQRAD+RVaSEEJAtAVT00JCvEVUlVQRUUgU0lHTgkNghVTSUdOIEFOVVNWQVJBDwe9FVZBR1JBSEEOC4EVQ0FORFJBQklORFUPEf4VSVJDTEUgTlVLVEEgQUJPVkUOBvwVTUFEREFIDgW8FU5VS1RBDgb7FVNIQUREQQ8E+hVVS1VODhX9FVRIUkVFLURPVCBOVUtUQSBBQk9WRQ8V/xVXTy1DSVJDTEUgTlVLVEEgQUJPVkUOBs0VVklSQU1BEAWDFVNBUkdBCQ6NFVZPV0VMIENBTkRSQSBFFgGRFU8PB74VU0lHTiBBQRUByBVJFQHMFVUUCMUVQ0FORFJBIEUbAckVTxQBxxVFFAG/FUkVAcAVSRQByxVPFAHBFVUVAcIVVRQJ4hVWT0NBTElDIEwdAeMVTBwBwxVSHQHEFVICF6i7BE5KQUxBIEdPTkRJIERJR0lUIEVJR0hUFASluwRGSVZFFQOkuwRPVVIUBKm7BE5JTkUUA6G7BE9ORRQFp7sEU0VWRU4VAqa7BElYFAWjuwRUSFJFRRUCorsEV08UBKC7BFpFUk8OCOC6BExFVFRFUiBBFgHhugRBFgHougRJFgHrugRVFQLuugRCQRYC77oESEEVAvu6BENBFgL8ugRIQRUC+LoEREEWAoK7BERBFwKDuwRIQRYC+boESEEVAue6BEVFFQL2ugRHQRYC97oESEEVAoe7BEhBFQHiugRJFgHjugRJFQKAuwRKQRYCgbsESEEVAvG6BEtBFgLyugRIQRUC9boETEEWAv+6BExBFQLwugRNQRUC+roETkEWAoS7BEdBFQLqugRPTxUChbsEUEEWAoa7BEhBFQKIuwRSQRUCibsEU0EVAvO6BFRBFgL0ugRIQRYC/boEVEEXAv66BEhBFQHkugRVFgHlugRVFQLtugRWQRUC7LoEWUEOApi7BE9NDg2VuwRTSUdOIEFOVVNWQVJBEweWuwRWSVNBUkdBDgaXuwRWSVJBTUEPDIq7BE9XRUwgU0lHTiBBQRoBkbsESRoBlLsEVRkCkLsERUUZAYu7BEkaAYy7BEkZApO7BE9PGQGNuwRVGgGOuwRVAhj2FFJNVUtISSBBQkJSRVZJQVRJT04gU0lHTgoE8RREREFLCQvuFERJR0lUIEVJR0hUDwTrFEZJVkUQA+oUT1VSDwTvFE5JTkUPA+cUT05FDwXtFFNFVkVOEALsFElYDwXpFFRIUkVFEALoFFdPDwTmFFpFUk8JCPQURUsgT05LQVIJA/IUSVJJCQiFFExFVFRFUiBBEQGGFEERAZAUSREBlBRVEAKsFEJBEQKtFEhBEAKaFENBEQKbFEhBEAKmFERBEQKhFERBEgKiFEhBEQKnFEhBEAKPFEVFEALeFEZBEAKXFEdBEQKYFEhBEgLaFEhBEAK5FEhBEAGHFEkRAYgUSRACnBRKQRECnRRIQRAClRRLQREClhRIQRIC2RRIQRACshRMQRECsxRMQRACrhRNQRACqBROQRECmRRHQRECoxROQRECnhRZQRACkxRPTxACqhRQQRECqxRIQRACsBRSQREC3BRSQRACuBRTQRECthRIQRACpBRUQRECpRRIQRECnxRUQRICoBRIQRABiRRVEQGKFFUQArUUVkEQAq8UWUEQAtsUWkEJD4EUU0lHTiBBREFLIEJJTkRJDgWCFEJJTkRJDgW8FE5VS1RBDgXRFFVEQUFUDgbNFFZJUkFNQRAFgxRTQVJHQQ4G9RRZQUtBU0gJBfAUVElQUEkJA/MUVVJBCQ2+FFZPV0VMIFNJR04gQUEVAcgUSRUBzBRVFALHFEVFFAG/FEkVAcAUSRQCyxRPTxQBwRRVFQHCFFUDIqzCBVVORyBLSEVNQSBDT05TT05BTlQgU0lHTiBNRURJQUwgSEEjAq7CBVJBIwKrwgVWQSMCqsIFWUENC7jCBURJR0lUIEVJR0hUEwS1wgVGSVZFFAO0wgVPVVITBLnCBU5JTkUTA7HCBU9ORRMFt8IFU0VWRU4UArbCBUlYEwWzwgVUSFJFRRQCssIFV08TBLDCBVpFUk8NCIDCBUxFVFRFUiBBFAKXwgVCQRUCmMIFSEEUAobCBUNBFQKHwgVIQRQCksIFREEVAo3CBURBFgKOwgVIQRUCk8IFSEEUAoPCBUdBFQKEwgVIQRQCisIFSEEUAojCBUpBFQKJwgVIQRQCgcIFS0EVAoLCBUhBFAKcwgVMQRQCmcIFTUEUApTCBU5BFQKFwgVHQRQClcIFUEEVApbCBUhBFAKbwgVSQRQCncIFU0EUApDCBVRBFQKRwgVIQRUCi8IFVEEWAozCBUhBFAKPwgVWQRQCmsIFWUENDa3CBVNJR04gQU5VU1ZBUkESCK/CBVRIT0xIT01BDRGpwgVWT1dFTCBMRU5HVEggTUFSSxMHnsIFU0lHTiBBQRkBpcIFSRkBqMIFVRgBo8IFRRkBpMIFRRgBn8IFSRkBoMIFSRgBpsIFTxkBp8IFTxgBocIFVRkBosIFVQAF4VdIQURFUwIHrvUHSVIgUElDSwUFikBTUEFDRQQDh+kHQ1VUBArI9QdZIENSRUFUVVJFAhTt/wNMRldJRFRIIEJMQUNLIFNRVUFSRQoP7P8DRE9XTldBUkRTIEFSUk9XChTo/wNGT1JNUyBMSUdIVCBWRVJUSUNBTAoNoP8DSEFOR1VMIEZJTExFUhEI", + "wv8DTEVUVEVSIEEZAcP/A0UYB7r/A0NISUVVQ0gZBLj/A0lFVUMYAcf/A0UZAcb/A08ZAdr/A1UYBb7/A0hJRVVIGAHc/wNJGQS3/wNFVU5HGAe7/wNLSElFVUtIGQWh/wNJWUVPSx4Fo/8DLVNJT1MYBbH/A01JRVVNGAWk/wNOSUVVTh0Gpf8DLUNJRVVDHgWm/wNISUVVSBgBzP8DTxkBz/8DRRgHvf8DUEhJRVVQSBkEsv8DSUVVUB0FtP8DLVNJT1MYBan/A1JJRVVMHQaw/wMtSElFVUgeBqr/A0tJWUVPSx4Fq/8DTUlFVU0eB6//A1BISUVVUEgfBKz/A0lFVVAeBK3/A1NJT1MeB67/A1RISUVVVEgYBLX/A1NJT1MZCbn/A1NBTkdDSUVVQx0Gov8DS0lZRU9LHQWz/wNQSUVVUB0Etv8DU0lPUx0GqP8DVElLRVVUGAe8/wNUSElFVVRIGQWn/wNJS0VVVBgB0/8DVRgCzf8DV0EaAc7/A0UZAdX/A0UaAdT/A08ZAdb/A0kYAsT/A1lBGgHF/wNFGQHL/wNFGgHK/wNPGQHb/wNJGQHS/wNPGQHX/wNVChHk/gNJREVPR1JBUEhJQyBDT01NQRYJ4f4DRlVMTCBTVE9QChHx/gNLQVRBS0FOQSBMRVRURVIgQRoB9P4DRRoCiv8DSEEbAY3/A0UbAYv/A0kbAY7/A08bAYz/A1UaAfL+A0kaAvb+A0tBGwH5/gNFGwH3/gNJGwH6/gNPGwH4/gNVGgKP/wNNQRsBkv8DRRsBkP8DSRsBk/8DTxsBkf8DVRoBnf8DThsBhf8DQRsBiP8DRRsBhv8DSRsBif8DTxsBh/8DVRoB9f4DTxoCl/8DUkEbAZr/A0UbAZj/A0kbAZv/A08bAZn/A1UaAvv+A1NBGwH+/gNFGwH8/gNJGwbn/gNNQUxMIEEgAer+A0UgAej+A0kgAev+A08gAu/+A1RVIAHp/gNVIALs/gNZQSEB7v4DTyEB7f4DVRsB//4DTxsB/f4DVRoCgP8DVEEbAYP/A0UbAYH/A0kbAYT/A08bAYL/A1UaAfP+A1UaApz/A1dBGwHm/gNPGgKU/wNZQRsBlv8DTxsBlf8DVRMK5f4DTUlERExFIERPVBMWn/8DU0VNSS1WT0lDRUQgU09VTkQgTUFSSxMRnv8DVk9JQ0VEIFNPVU5EIE1BUksSHvD+Ay1ISVJBR0FOQSBQUk9MT05HRUQgU09VTkQgTUFSSwoT4v4DTEVGVCBDT1JORVIgQlJBQ0tFVA4L6f8DV0FSRFMgQVJST1cKFOP+A1JJR0hUIENPUk5FUiBCUkFDS0VUDwvr/wNXQVJEUyBBUlJPVwoN6v8DVVBXQVJEUyBBUlJPVwoM7v8DV0hJVEUgQ0lSQ0xFAgfU5gdNQlVSR0VSAwOo6gdNRVIGCZJNIEFORCBQSUNLCwatTFNJQ0tMRQsG4O0HV1JFTkNIAwKs9QdTQQQIuegHVEVSIEZBQ0UCKJ7yB05EIFdJVEggSU5ERVggQU5EIE1JRERMRSBGSU5HRVJTIENST1NTRUQQGPD1B0ZJTkdFUiBBTkQgVEhVTUIgQ1JPU1NFRAQD3OgHQkFHBgK+8gdMTAQFnfIHU0hBS0UDH9UiR1VMIENIT1NFT05HIENFT05HQ0hJRVVNQ0hJRVVDSBwE0CJJRVVDGwS+IlNJT1McCdEiU0FOR0NJRVVDIAS/IlNJT1MRBo4iSElFVUNIFwbTIi1ISUVVSBgH0iJLSElFVUtIEwzUIlRVRVVNQ0hJRVVDSBkEziJJRVVDGAS8IlNJT1MZCc8iU0FOR0NJRVVDHQS9IlNJT1MRBIwiSUVVQxUGzSItSUVVTkcQBt8iRklMTEVSEAWSIkhJRVVIFQX70gItU0lPUxAFiyJJRVVORxUIySItQ0hJRVVDSBcEyCJJRVVDFgX30gJISUVVSBYGwSJLSVlFT0sWBcMiTUlFVU0WB8YiUEFOU0lPUxcGyyJISUVVUEgXBMQiSUVVUBYF9tICUklFVUwWBMUiU0lPUxYHyiJUSElFVVRIFwXCIklLRVVUEA2dIktBUFlFT1VOTUlFVU0YB9ciUEhJRVVQSBkEqyJJRVVQGAWbIlJJRVVMGAqsIlNTQU5HUElFVVARBo8iSElFVUtIEQWAIklZRU9LFgfaIi1USUtFVVQQBYYiTUlFVU0VB+/SAi1LSVlFT0sWBZwiUElFVVAWBPHSAlNJT1MWBvDSAlRJS0VVVBAFgiJOSUVVThUG3CItQ0lFVUMWBd0iSElFVUgWBpMiS0lZRU9LFgWWIlBJRVVQFgTbIlNJT1MWBpUiVElLRVVUEAfAIlBBTlNJT1MRBpEiSElFVVBIFwb60gItSElFVUgYBdYiUElFVVARBIciSUVVUBUIqCItQ0hJRVVDSBcEpyJJRVVDFgX00gJISUVVSBYH89ICS0hJRVVLSBcFniJJWUVPSxYFnyJOSUVVThYHqiJQSElFVVBIFgShIlNJT1MaBqYiLUNJRVVDGwaiIktJWUVPSxsFpCJQSUVVUBsH8tICVEhJRVVUSBwFoyJJS0VVVBcIpSJTQU5HU0lPUxYHqSJUSElFVVRIFwWgIklLRVVUEAWFIlJJRVVMFQbt0gItQ0lFVUMWBZoiSElFVUgWDevSAktBUFlFT1VOUElFVVAXBu7SAkhJRVVLSBcF5NICSVlFT0sWBejSAk1JRVVNFgWYIk5JRVVOFgXp0gJQSUVVUBYE7NICU0lPUxcK5dICU0FOR0tJWUVPSxsF6tICUElFVVAbBufSAlRJS0VVVBYG5tICVElLRVVUEASJIlNJT1MUCLciLUNISUVVQ0gWBLYiSUVVQxUFuyJISUVVSBUFtSJJRVVORxUHuCJLSElFVUtIFgWtIklZRU9LFQWxIk1JRVVNFQWuIk5JRVVOFQe6IlBISUVVUEgWBLIiSUVVUBoHsyItS0lZRU9LFQWwIlJJRVVMFQm0IlNTQU5HU0lPUxUHuSJUSElFVVRIFgWvIklLRVVUEQmNIlNBTkdDSUVVQxoG+NICLUhJRVVIFQXYIkhJRVVIFQXHIklFVU5HFQaBIktJWUVPSxUFlCJOSUVVThUFiCJQSUVVUBUFmSJSSUVVTBUEiiJTSU9TGQb10gItUElFVVAVB/nSAlRISUVVVEgWBYQiSUtFVVQVC/zSAllFT1JJTkhJRVVIEAeQIlRISUVVVEgRBYMiSUtFVVQWBuPSAi1DSUVVQxcGlyJLSVlFT0sXBeDSAk1JRVVNFwXh0gJQSUVVUBcF3iJSSUVVTBcE4tICU0lPUxAL2SJZRU9SSU5ISUVVSBIGzCJTSUVVTkcHFK9gRE9VQkxFIERPVCBUT05FIE1BUksHBuRiRklMTEVSBxG+I0pPTkdTRU9ORyBDSElFVUNIEgS9I0lFVUMWBvevAy1QSUVVUBcK+K8DU1NBTkdQSUVVUBEFwiNISUVVSBYG9yMtTUlFVU0XBfUjTklFVU4XBfgjUElFVVAXBfYjUklFVUwRBbwjSUVVTkcWCO8jLUtISUVVS0gYBewjSVlFT0sXC+0jU1NBTkdLSVlFT0sRDeIjS0FQWUVPVU5NSUVVTRkH9CNQSElFVVBIGgTmI0lFVVAZBd2vA1JJRVVMEga/I0hJRVVLSBIFqCNJWUVPSxcI/CMtQ0hJRVVDSBgF/iNISUVVSBgH/SNLSElFVUtIGAX6I05JRVVOGAX7I1BJRVVQGAXDI1JJRVVMGASqI1NJT1McB8QjLUtJWUVPSxEFtyNNSUVVTRYI4CMtQ0hJRVVDSBgE4q8DSUVVQxcF4SNISUVVSBcG2iNLSVlFT0sXBd6vA05JRVVOFwffI1BBTlNJT1MYBNwjSUVVUBwF4a8DLVNJT1MXBdsjUklFVUwXBN0jU0lPUxgJ368DU0FOR05JRVVOHATeI1NJT1MRBasjTklFVU4WCMyvAy1DSElFVUNIGASsI0lFVUMXBa0jSElFVUgXBsUjS0lZRU9LFwfII1BBTlNJT1MXBcuvA1JJRVVMFwTHI1NJT1MXB8kjVEhJRVVUSBgFxiNJS0VVVBEH6yNQQU5TSU9TGA70rwMtS0FQWUVPVU5QSUVVUBkF868DUElFVVASBsEjSElFVVBIGAbzIy1QSUVVUBkE+q8DU0lPUxkH+68DVEhJRVVUSBIEuCNJRVVQFgjprwMtQ0hJRVVDSBgE6K8DSUVVQxcF5SNISUVVSBcF5a8DTUlFVU0XB+QjUEhJRVVQSBcF4yNSSUVVTBwI5K8DLVBISUVVUEgXBLkjU0lPUxsH568DLVRJS0VVVBcG468DVElLRVVUEQWvI1JJRVVMFga2Iy1ISUVVSBcN1SNLQVBZRU9VTlBJRVVQGAbYI0hJRVVLSBgFsCNJWUVPSx0G1q8DLUhJRVVIHgTMI1NJT1MXBbEjTUlFVU0cBtivAy1ISUVVSB0G0SNLSVlFT0sdBNIjU0lPUxcFzSNOSUVVThcH1yNQQU5TSU9TGAa1I0hJRVVQSBgEsiNJRVVQHAbUIy1ISUVVSB0H2q8DUEhJRVVQSB0E0yNTSU9THQbZrwNUSUtFVVQXBLMjU0lPUxgK1a8DU0FOR0tJWUVPSxwE1iNTSU9TFwe0I1RISUVVVEgYBc4jSUtFVVQdBs8jLUhJRVVIFwvZI1lFT1JJTkhJRVVIIgbcrwMtSElFVUgZBtuvA1NJRVVORxEEuiNTSU9TFQjwrwMtQ0hJRVVDSBcE768DSUVVQxYF8q8DSElFVUgWDeuvA0tBUFlFT1VOUElFVVAXBecjSVlFT0sWBeqvA01JRVVNFgfurwNQQU5TSU9TFwTqI0lFVVAWBekjUklFVUwWB/GvA1RISUVVVEgXBegjSUtFVVQSCfmvA1NBTkdDSUVVQxYF7iNJRVVORxYGqSNLSVlFT0sWBeCvA01JRVVNFgX/I05JRVVOFgXmrwNQSUVVUBYF0CNSSUVVTBsI168DLUtISUVVS0gWBLsjU0lPUxoH7K8DLUtJWUVPSxsG7a8DVElLRVVUFgbNrwNUSUtFVVQcBs6vAy1QSUVVUBYI7iNZRVNJRVVORxEHwCNUSElFVVRIEgWuI0lLRVVUFwjTrwMtQ0hJRVVDSBkE0q8DSUVVQxgGyiNLSVlFT0sYBc+vA1BJRVVQGAXLI1JJRVVMGATQrwNTSU9THAfRrwMtS0lZRU9LGAfUrwNUSElFVVRIEQv5I1lFT1JJTkhJRVVIEwbwI1NJRVVORxkG9q8DLUhJRVVIGgfvI0tISUVVS0gbBewjSVlFT0saBfWvA01JRVVNGgfyI1BBTlNJT1MaBPEjU0lPUxsK7SNTQU5HS0lZRU9LCArhIlVOR1NFT05HIEESA6MjLUVVEwH2Ik8TAfciVRIB4iJFEgSeI1JBRUEWAsWvAy1BFwHGrwNFGAGfI08XAaEjSRcBoCNVEQHmIkUSAeUiTxMD/CItRVUUAfoiTxQB+yJVEgHzIlUTArmvAy1BFAG7rwNFFQG6rwNPFQGWI1UUAbyvA08UAZUjVREG4CJGSUxMRVIRAfUiSRICmCMtQRQEnSNSQUVBEwKcI0VVEwHErwNJEwGaI08UAsGvAy1JEwGbI1UTApkjWUEVAr2vAy1PFQG+rwNFFAHArwNFFQG/rwNPFAHCrwNPFAHDrwNVEQHpIk8SAoAjLUUUAf8iTxMBgiNPFAKxrwMtSRMBgyNVEwKmI1lBFQGnI0UUAYEjRRUBsK8DTxIB7CJFEQqiI1NTQU5HQVJBRUERAe4iVRICiSMtQRQBiiNFEwWLI0VPLUVVEwO2rwNJLUkTAY0jVRMCjCNZRRUBta8DTxEC6iJXQRMB6yJFEgHwIkUTAe8iTxIB8SJJEQLjIllBEwL4Ii1PFAGkI1UUAvkiWU8TAeQiRRIB6CJFEwHnIk8UAv0iLU8VAf4iVRUCpSNZQRIB9CJJEwKXIy1VEgHtIk8TArKvAy1BFQGzrwNFFAK0rwNFTxQBiCNJFAGHI08UAoQjWUEWAYUjRRUChiNFTxIB8iJVEwKOIy1BFQG3rwNFFAGQI0UVAY8jTxQBlCNJFAG4rwNPFAGTI1UUApIjWUUWAZEjTwcIz2JMRVRURVIgQQ8B0GJFDwSNY1JBRUETAY5jRQ4HymJDSElFVUNIDwTIYklFVUMOAdRiRQ8B02JPDwHhYlUOBc5iSElFVUgOAeNiSQ8Ex2JFVU5HDg3xYktBUFlFT1VOTUlFVU0WB4RjUEhJRVVQSBcE+GJJRVVQFgr5YlNTQU5HUElFVVAPBstiSElFVUtIDwWxYklZRU9LFAWzYi1TSU9TDgXBYk1JRVVNEwjwYi1QQU5TSU9TFQTuYklFVVAUBO9iU0lPUw4FtGJOSUVVThMGtWItQ0lFVUMUBbZiSElFVUgUB+hiUEFOU0lPUxQE52JTSU9TFAbmYlRJS0VVVA4B12JPDwHaYkUOB/9iUEFOU0lPUw8GzWJISUVVUEgPBMJiSUVVUBMG9mItQ0lFVUMUBvJiS0lZRU9LFATEYlNJT1MYB/RiLUtJWUVPSxkG9WJUSUtFVVQUB/diVEhJRVVUSBUF82JJS0VVVA4FuWJSSUVVTBMGwGItSElFVUgUBrpiS0lZRU9LGgXpYi1TSU9TFAW7Yk1JRVVNFAfsYlBBTlNJT1MVBr9iSElFVVBIFQS8YklFVVAZBetiLVNJT1MUBL1iU0lPUxQHvmJUSElFVVRIFQXqYklLRVVUFAvtYllFT1JJTkhJRVVIDgTFYlNJT1MSBv5iLUNJRVVDEwb6YktJWUVPSxMF+2JOSUVVThMF/WJQSUVVUBMG/GJUSUtFVVQPCcliU0FOR0NJRVVDEwWFY0hJRVVIEwWAY0lFVU5HEwayYktJWUVPSxMF5WJOSUVVThMFw2JQSUVVUBMExmJTSU9TEwa4YlRJS0VVVA4HzGJUSElFVVRIDwW3YklLRVVUDgHcYlUOAthiV0EQAdliRQ8B3mJFEAHdYk8PAd9iSQ4C0WJZQRAB0mJFDwHWYkUQAdViTxEIhmNSSU5ISUVVSBAGgWNTSUVVTkcWCINjLVBBTlNJT1MXBIJjU0lPUw8B4mJJDwHbYk8QAoljLUkRAodjWUETAYhjRQ8B4GJVEAKMYy1JEQKLY1lFEwGKY08HFK5gU0lOR0xFIERPVCBU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Uk9LRSBBTkQgVFdPIERPVFMgQUJPVkUMCdlWRCBTQUxUSVJFByWoT09OQ0FWRS1QT0lOVEVEIEJMQUNLIFJJR0hUV0FSRFMgQVJST1cGJ6BPREFTSEVEIFRSSUFOR0xFLUhFQURFRCBSSUdIVFdBUkRTIEFSUk9XBwyXT0lWSVNJT04gU0lHTgcKsukHT0xMQVIgU0lHTggi3k5VQkxFIENPTU1BIFFVT1RBVElPTiBNQVJLIE9STkFNRU5UDSTdTlRVUk5FRCBDT01NQSBRVU9UQVRJT04gTUFSSyBPUk5BTUVOVAgom/AHV05XQVJEUyBBUlJPVyBXSVRIIEVRVUlMQVRFUkFMIEFSUk9XSEVBRBsbn/AHTEFSR0UgRVFVSUxBVEVSQUwgQVJST1dIRUFEBhjP7wdFSUdIVCBQT0lOVEVEIEJMQUNLIFNUQVIUDdHvB1BJTldIRUVMIFNUQVIUFrhOUkVDVElMSU5FQVIgQkxBQ0sgU1RBUgwPvu8HU1BPS0VEIEFTVEVSSVNLDCLLTlRFQVJEUk9QLVNQT0tFRCBQUk9QRUxMRVIgQVNURVJJU0sHCvDvB1FVQUxTIFNJR04HGOJOWENMQU1BVElPTiBNQVJLIE9STkFNRU5UFwbXTlNZTUJPTAYXyu8HRklWRSBQT0lOVEVEIEJMQUNLIFNUQVILD7LvB1NQT0tFRCBBU1RFUklTSwcbpE5PVVIgQkFMTE9PTi1TUE9LRUQgQVNURVJJU0sGC5pOR1JFRUsgQ1JPU1MGH+NOSEVBUlQgRVhDTEFNQVRJT04gTUFSSyBPUk5BTUVOVAcOl/cHT1JJWk9OVEFMIEZJTEwGFPnsB0lOVEVSUk9CQU5HIE9STkFNRU5UBgzVVkxBUkdFIENJUkNMRQgJx+oHVElOIENST1NTByPwTkVGVC1QT0lOVElORyBBTkdMRSBCUkFDS0VUIE9STkFNRU5UGhfuTlFVT1RBVElPTiBNQVJLIE9STkFNRU5UCiaY8AdXQVJEUyBBUlJPVyBXSVRIIEVRVUlMQVRFUkFMIEFSUk9XSEVBRBsbnPAHTEFSR0UgRVFVSUxBVEVSQUwgQVJST1dIRUFEBxjz7AdJR0FUVVJFIE9QRU4gRVQgT1JOQU1FTlQHJ+BOT1cgRE9VQkxFIENPTU1BIFFVT1RBVElPTiBNQVJLIE9STkFNRU5UCiTfTlNJTkdMRSBDT01NQSBRVU9UQVRJT04gTUFSSyBPUk5BTUVOVAkorU9FUiBSSUdIVC1TSEFET1dFRCBXSElURSBSSUdIVFdBUkRTIEFSUk9XBgqWT01JTlVTIFNJR04HD5ZOVUxUSVBMSUNBVElPTiBYBhCaT05PUlRIIEVBU1QgQVJST1cRDObsB1BPSU5USU5HIEJVRBoJ3uwHVklORSBMRUFGDBHk7AdXRVNUIFBPSU5USU5HIEJVRBoJ3OwHVklORSBMRUFGBhGcTk9QRU4gQ0VOVFJFIENST1NTBxKuTlVUTElORUQgQkxBQ0sgU1RBUgcU1lZWQUwgV0lUSCBPVkFMIElOU0lERQYJlU9QTFVTIFNJR04GJfFOUklHSFQtUE9JTlRJTkcgQU5HTEUgQlJBQ0tFVCBPUk5BTUVOVBsX705RVU9UQVRJT04gTUFSSyBPUk5BTUVOVAsLmU9XQVJEUyBBUlJPVxYbmvAHIFdJVEggRVFVSUxBVEVSQUwgQVJST1dIRUFEHBue8AdMQVJHRSBFUVVJTEFURVJBTCBBUlJPV0hFQUQHHJxPT1VORC1USVBQRUQgUklHSFRXQVJEUyBBUlJPVwYHrO8HU0FMVElSRQgd++wHTlMtU0VSSUYgSU5URVJST0JBTkcgT1JOQU1FTlQHGvHsB0NSSVBUIExJR0FUVVJFIEVUIE9STkFNRU5UByPcTklOR0xFIENPTU1BIFFVT1RBVElPTiBNQVJLIE9STkFNRU5UDSTbTlRVUk5FRCBDT01NQSBRVU9UQVRJT04gTUFSSyBPUk5BTUVOVAgUzO8HWCBQT0lOVEVEIEJMQUNLIFNUQVIKD7jvB1NQT0tFRCBBU1RFUklTSwcPmE9PVVRIIEVBU1QgQVJST1cRDOfsB1BPSU5USU5HIEJVRBoJ3+wHVklORSBMRUFGDBHl7AdXRVNUIFBPSU5USU5HIEJVRBoJ3ewHVklORSBMRUFGBwbITlBBUktMRQYhu09URUFSRFJPUC1TSEFOS0VEIFJJR0hUV0FSRFMgQVJST1cQDr1OUE9LRUQgQVNURVJJU0sWEcNOUElOV0hFRUwgQVNURVJJU0sHH55PUklBTkdMRS1IRUFERUQgUklHSFRXQVJEUyBBUlJPVwcY0+8HV0VMVkUgUE9JTlRFRCBCTEFDSyBTVEFSFQ3U7wdQSU5XSEVFTCBTVEFSBiuuT1VQUEVSIFJJR0hULVNIQURPV0VEIFdISVRFIFJJR0hUV0FSRFMgQVJST1cIJpnwB1dBUkRTIEFSUk9XIFdJVEggRVFVSUxBVEVSQUwgQVJST1dIRUFEGRud8AdMQVJHRSBFUVVJTEFURVJBTCBBUlJPV0hFQUQGDNpOVkVSVElDQUwgQkFSBh29T1dFREdFLVRBSUxFRCBSSUdIVFdBUkRTIEFSUk9XBwuH7wdISVRFIENJUkNMRQwW201ET1dOLVBPSU5USU5HIFRSSUFOR0xFDAaR7wdTUVVBUkUSI4WcByBDT05UQUlOSU5HIEJMQUNLIFZFUlkgU01BTEwgU1FVQVJFBxuUT0lERS1IRUFERUQgUklHSFRXQVJEUyBBUlJPVwICwJ0HQkUDF6ILUkVXIEFDQ0VOVCBBVE5BSCBIQUZVS0gOBacLREFSR0EPA60LRUhJDgeRC0VUTkFIVEEOBpwLR0VSRVNIFAedCyBNVVFEQU0RBp4LU0hBWUlNDgSsC0lMVVkOCKQLTUFIQVBBS0gPBaULRVJLSEEUB6YLIEtFRlVMQQ8EowtVTkFIDgOrC09MRQ4GmQtQQVNIVEEQA6ELWkVSDgWoC1FBRE1BEAmfC1JORVkgUEFSQQ4FlwtSRVZJQQ4FkgtTRUdPTA8JkwtIQUxTSEVMRVQODqALVEVMSVNIQSBHRURPTEEWBqkLUUVUQU5BEAObC1ZJUg8FlgtJUEVIQQ4OqgtZRVJBSCBCRU4gWU9NTxADmgtUSVYOC5ULWkFRRUYgR0FET0wUBZQLUUFUQU4QA5gLUlFBDwSuC0lOT1IHC9ALTEVUVEVSIEFMRUYSC7D2AyBXSVRIIE1BUElRGAWu9gNQQVRBSBgGr/YDUUFNQVRTEA6g9gNURVJOQVRJVkUgQVlJThoJqfYDUExVUyBTSUdODwPiC1lJTg4D0QtCRVQRDLH2AyBXSVRIIERBR0VTSBcEzPYDUkFGRQ4F0wtEQUxFVBMMs/YDIFdJVEggREFHRVNIDgnaC0ZJTkFMIEtBRhcMuvYDIFdJVEggREFHRVNIFAPdC01FTRQD3wtOVU4UAuMLUEUWDMP2AyBXSVRIIERBR0VTSBQF5QtUU0FESQ4F0gtHSU1FTBMMsvYDIFdJVEggREFHRVNIDgLU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7JsBR0FUSEVSSU5HIFRPR0VUSEVSDgTVmwFSQUNFDw7NmwFFQVQgUE9TU0VTU0lPThUD4ZsBV0VSFAzbmwFSRVBPTkRFUkFOQ0UTBtmbAVRBTUlORw0Qx5sBSE9MRElORyBUT0dFVEhFUg0I6ZsBSU5DUkVBU0UPB96bAUZMVUVOQ0UPCfybAU5FUiBUUlVUSBAG2JsBT0NFTkNFDQr7mwFMSU1JVEFUSU9ODQfOmwFNT0RFU1RZDwvamwFVVEggQ09STkVSUw0L5psBT0JTVFJVQ1RJT04OCeWbAVBQT1NJVElPThAH7psBUkVTU0lPTg0FypsBUEVBQ0UOB+KbAVJPR1JFU1MODe2bAVVTSElORyBVUFdBUkQNB+CbAVJFVFJFQVQQA9ebAVVSTg8I8JsBVk9MVVRJT04NE/2bAVNNQUxMIFBSRVBPTkRFUkFOQ0UTBsibAVRBTUlORw4O1psBUExJVFRJTkcgQVBBUlQOCcubAVRBTkRTVElMTA0R3JsBVEhFIEFCWVNNQUwgV0FURVISA8abAVJNWRMO8psBT1VTSU5HIFRIVU5ERVIRCPGbAUNBVUxEUk9OEgzdmwFMSU5HSU5HIEZJUkUSDsCbAVJFQVRJVkUgSEVBVkVOEQbkmwFGQU1JTFkRC/ibAUdFTlRMRSBXSU5EEQv5mwFKT1lPVVMgTEFLRREW85sBS0VFUElORyBTVElMTCBNT1VOVEFJThEP9ZsBTUFSUllJTkcgTUFJREVOEQ/BmwFSRUNFUFRJVkUgRUFSVEgRCPebAVdBTkRFUkVSEgPvmwFFTEwOB8mbAVJFQURJTkcNB8SbAVdBSVRJTkcOEtGbAU9SSyBPTiBUSEUgREVDQVlFRA0Ow5sBWU9VVEhGVUwgRk9MTFkBB7rmB0lCSVNDVVMCFIbqB0dIIEJSSUdIVE5FU1MgU1lNQk9MBQyBAU9DVEVUIFBSRVNFVAUMoU1WT0xUQUdFIFNJR04EDODoBy1IRUVMRUQgU0hPRQULhO0HU1BFRUQgVFJBSU4QEYXtByBXSVRIIEJVTExFVCBOT1NFAgn+8gdLSU5HIEJPT1QCCtXtB05EVSBURU1QTEUCCpvzB1BQT1BPVEFNVVMCE59hUkFHQU5BIERJR1JBUEggWU9SSQkOnWFJVEVSQVRJT04gTUFSSwkIwmBMRVRURVIgQREJn+IGUkNIQUlDIFdVGAKB4AZZRRAC8GBCQREB+WBFEQHzYEkRAfxgTxEB9mBVEALgYERBEQHnYEURAeJgSREB6WBPEQHlYFUQAchgRRACzGBHQREB0mBFEQHOYEkRAdRgTxEB0GBVEALvYEhBEQH4YEURAfJgSREB+2BPEQH1YFUQAcRgSRACy2BLQREB0WBFEQHNYEkRAdNgTxEBz2BVEAL+YE1BEQGBYUURAf9gSREBgmFPEQGAYVUQAZNhThEB6mBBEQHtYEURAetgSREB7mBPEQHsYFUQAcpgTxAC8WBQQREB+mBFEQH0YEkRAf1gTxEB92BVEAKJYVJBEQGMYUURAYphSREBjWFPEQGLYVUQAtVgU0ERAdtgRREB12BJEQbBYE1BTEwgQRYBx2BFFgHDYEkWApVhS0EXAZZhRRcBsuIGTxYByWBPFgLjYFRVFgHFYFUWAo5hV0EXAdHiBkUXAdDiBkkXAdLiBk8WAoNhWUEXAYdhTxcBhWFVEQHdYE8RAdlgVRAC32BUQREB5mBFEQHhYEkRAehgTxEB5GBVEAHGYFUQApRhVlUQAo9hV0ERAZFhRREBkGFJEQGSYU8QAoRhWUERAYhhTxEBhmFVEALWYFpBEQHcYEURAdhgSREB3mBPEQHaYFUJFZ5hVk9JQ0VEIElURVJBVElPTiBNQVJLAgvsTVNUT1JJQyBTSVRFAQSq6gdPQ0hPAgLz6gdMRQMZ6OwHTE9XIFFVSUxUIFNRVUFSRSBPUk5BTUVOVBwQ6ewHIElOIEJMQUNLIFNRVUFSRQIIu0RNT1RIRVRJQwIH7+YHTkVZIFBPVAUDnegHQkVFAgKd9QdPSwIBgQFQAgyVQFJJWk9OVEFMIEJBUgwMo1ZMQUNLIEhFWEFHT04RB8NXT0NUQUdPTgsJk5gHQ0FQQUNJVE9SCwimQEVMTElQU0lTCwaFmQdMQURERVIMDa9HSU5FIEVYVEVOU0lPThAUkZkHV0lUSCBGT1VSIFRJQ0sgTUFSS1MVEJKcB1RIUkVFIFRJQ0sgTUFSS1MWCI+cB0lDSyBNQVJLCxWpTU1BTEUgV0lUSCBTVFJPS0UgU0lHTgsVgfcHT05FIEVJR0hUSCBCTE9DSy0xMzU4HAH29gcyHAH39gczHAH49gc0HAH59gc1HAH69gc2HAH79gc3CwqbmQdSQUNJTkcgQ0FSDA+JmAdFU0lTVE9SIFNFR01FTlQLC7pHU0NBTiBMSU5FLTEVAbtHMxUBvEc3FQG9RzkLB/5WVEFCIEtFWQ4HCVVMQVRJT04VBIgBIFNFVBYSiQFXSVRIIEpVU1RJRklDQVRJT04MDKXtB1JBRkZJQyBMSUdIVAsLsJ0HWklHWkFHIExJTkUDAo7oB1NFBQW06AcgRkFDRQYGx+cHUkFDSU5HAgbl5wdTUElUQUwCCpVMVCBCRVZFUkFHRQQDreYHRE9HBAa25gdQRVBQRVIEB+hMU1BSSU5HUwMC6OcHRUwCB5tGVVJHTEFTUwkS80cgV0lUSCBGTE9XSU5HIFNBTkQDAoJGU0UFCeDnByBCVUlMRElORw4B2OcHUwYL4ecHV0lUSCBHQVJERU4BC7RBUllWTklBIFNJR04BAQlUAgGJAUoCAYgBUwELl/IHVUdHSU5HIEZBQ0UCE6/pB05EUkVEIFBPSU5UUyBTWU1CT0wCCa/sB1NIRUQgRkFDRQIB1u0HVAEHu/UHWUFDSU5USAIE2ldHSUVBBgn57gcgRk9STSBUV08CBJBAUEhFTgYHw0AgQlVMTEVUBw6aXFdJVEggRElBRVJFU0lTBgYtLU1JTlVTBgunQEFUSU9OIFBPSU5UAwmSXE9ESUFTVE9MRQIPjkdTVEVSRVNJUyBTWU1CT0wAFJ/yB0kgTE9WRSBZT1UgSEFORCBTSUdOAQjo5gdDRSBDUkVBTQUDyvMHVUJFBBXS5wdIT0NLRVkgU1RJQ0sgQU5EIFBVQ0sEBfhNU0tBVEUBC+FEREVOVElDQUwgVE8MFeVTIEFORCBTTEFOVEVEIFBBUkFMTEVMCg7nVFdJVEggRE9UIEFCT1ZFBg2q9QdGSUNBVElPTiBDQVJEAx+YY09HUkFQSElDIEFOTk9UQVRJT04gQk9UVE9NIE1BUksXCp5jRUFSVEggTUFSSxcKmWNGSVJTVCBNQVJLGAiVY09VUiBNQVJLGwecY1RIIE1BUksXC51jSEVBVkVOIE1BUksXDJBjTElOS0lORyBNQVJLFwifY01BTiBNQVJLGAqXY0lERExFIE1BUksXCJJjT05FIE1BUksXDJFjUkVWRVJTRSBNQVJLFwuaY1NFQ09ORCBNQVJLFwqbY1RISVJEIE1BUksZCJRjUkVFIE1BUksYB5ZjT1AgTUFSSxgHk2NXTyBNQVJLDAyGYENMT1NJTkcgTUFSSw0EgWBPTU1BDBOsYERFUEFSVElORyBUT05FIE1BUksOIvFfU0NSSVBUSU9OIENIQVJBQ1RFUiBBQk9WRSBUTyBCRUxPVysQ819NSURETEUgQU5EIEJFTE9XIg30X0ZVTEwgU1VSUk9VTkQiFf5fSE9SSVpPTlRBTCBSRUZMRUNUSU9OIhjyX0xFRlQgVE8gTUlERExFIEFORCBSSUdIVCoF8F9SSUdIVCII+19PVkVSTEFJRCII/19ST1RBVElPTiIL72NTVUJUUkFDVElPTiQR9V9SUk9VTkQgRlJPTSBBQk9WRTAF9l9CRUxPVzAE919MRUZUMQn6X09XRVIgTEVGVDYF/V9SSUdIVDAF/F9SSUdIVDAK+F9VUFBFUiBMRUZUNgX5X1JJR0hUDBKtYEVOVEVSSU5HIFRPTkUgTUFSSwwJgmBGVUxMIFNUT1AMD79gSEFMRiBGSUxMIFNQQUNFDA6FYElURVJBVElPTiBNQVJLDA+qYExFVkVMIFRPTkUgTUFSSwwLh2BOVU1CRVIgWkVSTwwQq2BSSVNJTkcgVE9ORSBNQVJLDAWAYFNQQUNFDA/2pgdUQUxMWSBNQVJLIEZJVkUYA/WmB09VUhcD8qYHT05FFwX0pgdUSFJFRRgC86YHV08NI7dgRUxFR1JBUEggTElORSBGRUVEIFNFUEFSQVRPUiBTWU1CT0wWEMNlU1lNQk9MIEZPUiBBUFJJTCIFx2VVR1VTVCEJ52dEQVkgRUlHSFQqA/FnRUVOJgXqZ0xFVkVOJQfuZ0ZJRlRFRU4nAuRnVkUmA+NnT1VSKQTtZ1RFRU4lBOhnTklORSkE8mdURUVOJQPgZ09ORSUF5mdTRVZFTioE8GdURUVOJgLlZ0lYKATvZ1RFRU4lA+lnVEVOJgfsZ0hJUlRFRU4qAf1nWSsE/mctT05FJwPiZ1JFRSYF62dXRUxWRSgD82dOVFkrBvtnLUVJR0hULAT4Z0ZJVkUtA/dnT1VSLAT8Z05JTkUsA/RnT05FLAX6Z1NFVkVOLQL5Z0lYLAX2Z1RIUkVFLQL1Z1dPJwHhZ08iB8tlRUNFTUJFUiEIwWVGRUJSVUFSWSEK4GZIT1VSIEVJR0hUKwPqZkVFTicF42ZMRVZFTiYH52ZGSUZURUVOKALdZlZFJwPcZk9VUioE5mZURUVOJgThZk5JTkUqBOtmVEVFTiYD2WZPTkUmBd9mU0VWRU4rBOlmVEVFTicC3mZJWCkE6GZURUVOJgPiZlRFTicH5WZISVJURUVOKAPbZlJFRScF5GZXRUxWRSkD7GZOVFksBfBmLUZPVVItA+1mT05FLQXvZlRIUkVFLgLuZldPKAHaZk8mBNhmWkVSTyEHwGVKQU5VQVJZIgPGZVVMWSMCxWVORSEFwmVNQVJDSCMBxGVZIQjKZU5PVkVNQkVSIQfJZU9DVE9CRVIhCchlU0VQVEVNQkVSDBO+YFZBUklBVElPTiBJTkRJQ0FUT1IBB7dFTUFHRSBPRgga00QgT1IgQVBQUk9YSU1BVEVMWSBFUVVBTCBUTwIB/+gHUAMawJAERVJJQUwgQVJBTUFJQyBMRVRURVIgQUxFUEgZA8+QBFlJThgEwZAEQkVUSBgGw5AEREFMRVRIGAXCkARHSU1FTBgCxJAESEUaAseQBFRIGATKkARLQVBIGAbLkARMQU1FREgYA8yQBE1FTRgDzZAETlVOGALQkARQRRgE0pAEUU9QSBgE05AEUkVTSBgF0ZAEU0FESEUaBM6QBE1FS0gZA9SQBEhJThgD1ZAEVEFXGQPIkARFVEgYA8WQBFdBVxgEyZAEWU9ESBgFxpAEWkFZSU4RCtiQBE5VTUJFUiBPTkUbCN2QBCBIVU5EUkVEHAjekARUSE9VU0FORBgD25AEVEVOGwnfkAQgVEhPVVNBTkQZBNqQBEhSRUUZBdyQBFdFTlRZGgHZkARPEQzXkARTRUNUSU9OIFNJR04BCeXpB05CT1ggVFJBWQIP6OkHQ09NSU5HIEVOVkVMT1BFBQ7cU1BMRVRFIElORklOSVRZAxba6wdSRUFTRSBGT05UIFNJWkUgU1lNQk9MCAThU1MgQVMFBIZETUVOVAIBhAFEAwKEAUVYBRf19QcgUE9JTlRJTkcgQVQgVEhFIFZJRVdFUgMOuUFJQU4gUlVQRUUgU0lHTgQbtNkHQyBTSVlBUSBBTFRFUk5BVEUgTEFLSCBNQVJLDBGu2QdGUkFDVElPTiBPTkUgSEFMRhkHrdkHUVVBUlRFUhUOr9kHVEhSRUUgUVVBUlRFUlMMCaDZB0xBS0ggTUFSSwwUsdkHTlVNQkVSIEFMVEVSTkFURSBPTkUdDLPZB1RFTiBUSE9VU0FO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lgRPAw2AR0VSVElPTiBTWU1CT0wCBqtEVEVHUkFMCBiVVCBBUk9VTkQgQSBQT0lOVCBPUEVSQVRPUgoRj1RWRVJBR0UgV0lUSCBTTEFTSAkJrkdFWFRFTlNJT04JEo5UV0lUSCBET1VCTEUgU1RST0tFDgyZVElOVEVSU0VDVElPTg4Zl1RMRUZUV0FSRFMgQVJST1cgV0lUSCBIT09LDgebVE9WRVJCQVIOCphUVElNRVMgU0lHTg4InFRVTkRFUkJBUhADmlRJT04EB7pFUkNBTEFURQULvFRJT1IgUFJPRFVDVAUY+f8DTElORUFSIEFOTk9UQVRJT04gQU5DSE9SFwn6/wNTRVBBUkFUT1IXCvv/A1RFUk1JTkFUT1IGGqRNT0NLRUQgRkVNQUxFIEFORCBNQUxFIFNJR04FBr1AUk9CQU5HBQepRFNFQ1RJT04MFslUIEFCT1ZFIEJBUiBBQk9WRSBVTklPThMFx1RVTklPTg0jy1RCRVNJREUgQU5EIEpPSU5FRCBXSVRIIElOVEVSU0VDVElPTg0IwFRXSVRIIERPVBILxFRMT0dJQ0FMIEFORBIHw1RPVkVSQkFSAhONmQdWRVJTRSBCTEFDSyBESUFNT05EDgyPmQdTTUFMTCBTUVVBUkUJBdhLVUxMRVQICrH3B0NIRUNLIE1BUksNDZb3B0VSIEJPQVJEIEZJTEwIIrT3B0RPV05XQVJEUyBBUlJPVyBXSVRIIFRJUCBMRUZUV0FSRFMIDJD3B01FRElVTSBTSEFERQgM2UtXSElURSBDSVJDTEUFFKEBVEVEIEVYQ0xBTUFUSU9OIE1BUksJC5hcSU5URVJST0JBTkcJBr5ETEFaWSBTCgnFXE9XIEtBVllLQRMSxlwgV0lUSCBLQVZZS0EgQUJPVkUJCKdCT0hNIFNJR04JCedNUEVOVEFHUkFNCQ2/AVFVRVNUSU9OIE1BUksJCNRAVU5ERVJUSUUDC+RASVNJQkxFIFBMVVMKCeNAU0VQQVJBVE9SCgXiQFRJTUVTAQTHnQdSRU5FAgLBnQdJUwEO7ucHWkFLQVlBIExBTlRFUk4ADoPnB0pBQ0stTy1MQU5URVJOAhL7TVBBTkVTRSBCQU5LIFNZTUJPTAkG7+cHQ0FTVExFCQWO5wdET0xMUwkG+ugHR09CTElOCRqEYElORFVTVFJJ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Q0lSQ0xFDAbr7wdTUVVBUkUGBu9LQ0lSQ0xFBgnZT0RPV04gVEFDSwYM4u8HR1JFRU4gQ0lSQ0xFDAbp7wdTUVVBUkUGFp5UTEVGVCBUUklBTkdMRSBPUEVSQVRPUgYhvZYET05FIERPVCBPVkVSIFRXTyBET1RTIFBVTkNUVUFUSU9OCh+/lgRSSU5HIE9WRVIgVFdPIFJJTkdTIFBVTkNUVUFUSU9OBwzg7wdSQU5HRSBDSVJDTEUNB7bqB0RJQU1PTkQNBufvB1NRVUFSRQYN4+8HUFVSUExFIENJUkNMRQ0G6u8HU1FVQVJFBgq06gdSRUQgQ0lSQ0xFCgbl7wdTUVVBUkUGHPxVVFJJUExFIFZFUlRJQ0FMIEJBUiBPUEVSQVRPUgcgvJYEV08gRE9UUyBPVkVSIE9ORSBET1QgUFVOQ1RVQVRJT04KH76WBFJJTkdTIE9WRVIgT05FIFJJTkcgUFVOQ1RVQVRJT04HFa+cB1lQRSBQSUVDRSBDRU5UUkUgT0YgSxsBspwHWBsBs5wHWRsPtJwHWiBXSVRIIENST1NTQkFSEgefnAdST1NTQkFSGRCgnAcgV0lUSCBMT1dFUiBTVEVNHwrAnAdVUFBFUiBTVEVNEROinAdESUFHT05BTCBMT1dFUiBMRUZUIAWsnAdSSUdIVBoKu5wHVVBQRVIgTEVGVCQPuJwHIEFORCBMT1dFUiBMRUZUIAWrnAdSSUdIVCUQqpwHIEFORCBMT1dFUiBSSUdIVBEInpwHTEVGVCBBUk0SFbCcB09XRVIgSEFMRiBWRVJURVggT0YgTSYBwpwHVxcXrpwHTEVGVCBBTkQgVVBQRVIgTEVGVCBBUkMdAr6cB1JDHAa9nAdDT1JORVIdBb+cB1JPVENIFxm3nAdSSUdIVCBBTkQgVVBQRVIgUklHSFQgQVJDHgLDnAdSQyAKxZwHIFdJVEggVEFJTB0GxJwHQ09STkVSHgXGnAdST1RDSBcIvJwHVEVSTUlOQUwRFbWcB1JBSVNFRCBVUFBFUiBMRUZUIEFSQxIIpZwHSUdIVCBBUk0RFK2cB1NIT1JUIExPV0VSIFRFUk1JTkFMFw6jnAdVUFBFUiBURVJNSU5BTBIDqZwHVEVNFQ66nAcgV0lUSCBDUk9TU0JBUhsNtpwHTEVGVCBDUk9TU0JBUiAFuZwHSk9JTlQbDqicB1JJR0hUIENST1NTQkFSFQPQnActMTIYAsycBzM0FgHPnAcyFwHOnAczGAHLnAc0GQHInAc1FgHNnAczFwHKnAc0FgHJnAc0FwHHnAc1ERahnAdVUFBFUiBIQUxGIFZFUlRFWCBPRiBNJgGxnAdXFwianAdMRUZUIEFSQxwGm5wHQ09STkVSHQWdnAdST1RDSBcJpJwHUklHSFQgQVJDHQannAdDT1JORVIeBaacB1JPVENIFwicnAdURVJNSU5BTBELwZwHVkVSVEVYIE9GIFYGB9hPVVAgVEFDSwYN4e8HWUVMTE9XIENJUkNMRQ0G6O8HU1FVQVJFBQarVVIgVEhBTgsMrVUgT1IgRVFVQUwgVE8DBr5BSSBTSUdOAg++TFNUIFFVQVJURVIgTU9PThEHl+YHIFNZTUJPTBIJnOYHV0lUSCBGQUNFAhRBVElOIENBUElUQUwgTEVUVEVSIEEWC8EBIFdJVEggQUNVVEUcBYICQlJFVkUhCq49IEFORCBBQ1VURSYJtj1ET1QgQkVMT1cmBbA9R1JBVkUmCrI9SE9PSyBBQk9WRSYFtD1USUxERRwFzQNDQVJPTh0JwgFJUkNVTUZMRVgmCqQ9IEFORCBBQ1VURSsJrD1ET1QgQkVMT1crBaY9R1JBVkUrCqg9SE9PSyBBQk9WRSsFqj1USUxERRwJxAFESUFFUkVTSVMlC94DIEFORCBNQUNST04dCKYET1QgQUJPVkUlC+ADIEFORCBNQUNST04gBaA9QkVMT1ceCoAEVUJMRSBHUkFWRRwFwAFHUkFWRRwKoj1IT09LIEFCT1ZFHA6CBElOVkVSVEVEIEJSRVZFHAaAAk1BQ1JPThwGhAJPR09ORUscCsUBUklORyBBQk9WRSYK+gMgQU5EIEFDVVRFIQWAPEJFTE9XHAa6BFNUUk9LRRwFwwFUSUxERRYBss4CQRYBxgFFFwv8AyBXSVRIIEFDVVRFHQbiA01BQ1JPThYIiQNGUklDQU4gRBYE7VhMUEhBFgrCzwJOR0xJQ0FOQSBXFgG0zgJPFgG2zgJVFgG4zgJWFxS6zgIgV0lUSCBIT1JJWk9OVEFMIEJBUhYBvM4CWRUBQkIWD4I8IFdJVEggRE9UIEFCT1ZFIAWEPEJFTE9XHAiWzwJGTE9VUklTSBwEgQNIT09LHAqGPExJTkUgQkVMT1ccBsMEU1RST0tFHAaCA1RPUEJBUhYDtM8CRVRBFgfGzgJST0tFTiBMFQFDQxYLhgIgV0lUSCBBQ1VURRwDks8CQkFSHAWMAkNBUk9OHQbHAUVESUxMQSMKiDwgQU5EIEFDVVRFHQmIAklSQ1VNRkxFWBwJigJET1QgQUJPVkUcBIcDSE9PSxwMxM8CUEFMQVRBTCBIT09LHAa7BFNUUk9LRRYCs88CSEkWD9DPAkxPU0VEIElOU1VMQVIgRxYC7s4CT04WCKzOAlVBVFJJTExPHguuzgIgV0lUSCBDT01NQRUBREQWC44CIFdJVEggQ0FST04dBpA8RURJTExBHQ+SPElSQ1VNRkxFWCBCRUxPVxwJijxET1QgQUJPVkUgBYw8QkVMT1ccBIoDSE9PSxwKjjxMSU5FIEJFTE9XHBTHzwJTSE9SVCBTVFJPS0UgT1ZFUkxBWR0N8gNNQUxMIExFVFRFUiBaKgvFAyBXSVRIIENBUk9OHQWQAlRST0tFHAaLA1RPUEJBUhYL0s8CT1VCTEUgVEhPUk4cBNTPAldZTk4WAfEDWhcLxAMgV0lUSCBDQVJPThUBRUUWC8kBIFdJVEggQUNVVEUcBZQCQlJFVkUcBZoCQ0FST04dBqgERURJTExBIwqcPCBBTkQgQlJFVkUdCcoBSVJDVU1GTEVYJgq+PSBBTkQgQUNVVEUrCcY9RE9UIEJFTE9XKwXAPUdSQVZFKwrCPUhPT0sgQUJPVkUrBcQ9VElMREUnBZg8QkVMT1ccCcsBRElBRVJFU0lTHQiWAk9UIEFCT1ZFIAW4PUJFTE9XHgqEBFVCTEUgR1JBVkUcBcgBR1JBVkUcCro9SE9PSyBBQk9WRRwOhgRJTlZFUlRFRCBCUkVWRRwGkgJNQUNST04iCpY8IEFORCBBQ1VURScFlDxHUkFWRRwGmAJPR09ORUscBsYEU1RST0tFHAW8PVRJTERFIQaaPCBCRUxPVxYQpM4CR1lQVE9MT0dJQ0FMIEFJTiQDos4CTEVGFgLKAk5HFgKpA1NIFgHqzgJUFwHQAUgWArcDWkgYCbgDIFJFVkVSU0VEGQruA1dJVEggQ0FST04VAUZGFg+ePCBXSVRIIERPVCBBQk9WRRwEkQNIT09LHAaYzwJTVFJPS0UVAUdHFgv0AyBXSVRIIEFDVVRFHAWeAkJSRVZFHAXmA0NBUk9OHQaiAkVESUxMQR0JnAJJUkNVTUZMRVgcCaACRE9UIEFCT1ZFHASTA0hPT0scBqA8TUFDUk9OHA6gzwJPQkxJUVVFIFNUUk9LRRwG5ANTVFJPS0UWBJQDQU1NQRYCogNIQRYIus8CTE9UVEFMIEEdAbzPAkkdBMEEU1RPUB0Bvs8CVRUBSEgWEao8IFdJVEggQlJFVkUgQkVMT1ccBZ4EQ0FST04dBqg8RURJTExBHQmkAklSQ1VNRkxFWBwJ51hERVNDRU5ERVIdCKY8SUFFUkVTSVMdCKI8T1QgQUJPVkUgBaQ8QkVMT1ccBKrPAkhPT0scBqYCU1RST0tFFgX1WEFMRiBIFgOmzgJFTkcWBPYDV0FJUhUBSUkWC80BIFdJVEggQUNVVEUcBawCQlJFVkUcBc8DQ0FST04dCc4BSVJDVU1GTEVYHAnPAURJQUVSRVNJUyUKrjwgQU5EIEFDVVRFHQiwAk9UIEFCT1ZFIAXKPUJFTE9XHgqIBFVCTEUgR1JBVkUcBcwBR1JBVkUcCsg9SE9PSyBBQk9WRRwOigRJTlZFUlRFRCBCUkVWRRwGqgJNQUNST04cBq4CT0dPTkVLHAaXA1NUUk9LRRwFqAJUSUxERSEGrDwgQkVMT1cWCPnOAk5TVUxBUiBEHQH7zgJGHQH9zgJHHQGCzwJSHQGEzwJTHQGGzwJUFgOWA09UQRYB7M4CUxUBSkoWELQCIFdJVEggQ0lSQ1VNRkxFWB0Lss8CUk9TU0VELVRBSUwcBsgEU1RST0tFFQFLSxYLsDwgV0lUSCBBQ1VURRwF6ANDQVJPTh0GtgJFRElMTEEcCelYREVTQ0VOREVSHQ7CzgJJQUdPTkFMIFNUUk9LRR0IsjxPVCBCRUxPVxwEmANIT09LHAq0PExJTkUgQkVMT1ccDqLPAk9CTElRVUUgU1RST0tFHAbAzgJTVFJPS0UiFMTOAiBBTkQgRElBR09OQUwgU1RST0tFFQFMTBYLuQIgV0lUSCBBQ1VURRwDvQRCQVIdA63PAkVMVBwFvQJDQVJPTh0GuwJFRElMTEEdD7w8SVJDVU1GTEVYIEJFTE9XHAm2PERPVCBCRUxPVyULuDwgQU5EIE1BQ1JPTh4I4FhVQkxFIEJBUhwLyM4CSElHSCBTVFJPS0UcCro8TElORSBCRUxPVxwKvwJNSURETEUgRE9UIwXiWFRJTERFHA7IA1NNQUxMIExFVFRFUiBKHQXBAlRST0tFFgXazwJBTUJEQRsM3M8CIFdJVEggU1RST0tFFgHHA0oVAU1NFgu+PCBXSVRIIEFDVVRFHAnAPERPVCBBQk9WRSAFwjxCRUxPVxwE7lhIT09LFg3WzwJJRERMRSBTQ09UUyBTGwn6PS1XRUxTSCBMTCIB/D1WFQFOThYLwwIgV0lUSCBBQ1VURRwFxwJDQVJPTh0GxQJFRElMTEEdD8o8SVJDVU1GTEVYIEJFTE9XHAmQzwJERVNDRU5ERVIdCMQ8T1QgQUJPVkUgBcY8QkVMT1ccBfgDR1JBVkUcCZ0DTEVGVCBIT09LHQnIPElORSBCRUxPVx0NoARPTkcgUklHSFQgTEVHHA6kzwJPQkxJUVVFIFNUUk9LRRwOywNTTUFMTCBMRVRURVIgShwF0QFUSUxERRYBygNKFQFPTxYL0wEgV0lUSCBBQ1VURRwFzgJCUkVWRRwF0QNDQVJPTh0J1AFJUkNVTUZMRVgmCtA9IEFORCBBQ1VURSsJ2D1ET1QgQkVMT1crBdI9R1JBVkUrCtQ9SE9PSyBBQk9WRSsF1j1USUxERRwJ1gFESUFFUkVTSVMlC6oEIEFORCBNQUNST04dCK4ET1QgQUJPVkUlC7AEIEFORCBNQUNST04gBcw9QkVMT1ceCtACVUJMRSBBQ1VURSMFjARHUkFWRRwF0gFHUkFWRRwKzj1IT09LIEFCT1ZFHgKgA1JOIAraPSBBTkQgQUNVVEUlCeI9RE9UIEJFTE9XJQXcPUdSQVZFJQrePUhPT0sgQUJPVkUlBeA9VElMREUcDo4ESU5WRVJURUQgQlJFVkUcE8rOAkxPTkcgU1RST0tFIE9WRVJMQVkeAszOAk9QHAbMAk1BQ1JPTiIK0jwgQU5EIEFDVVRFJwXQPEdSQVZFHQufA0lERExFIFRJTERFHAbqA09HT05FSyIL7AMgQU5EIE1BQ1JPThwG2AFTVFJPS0UiCv4DIEFORCBBQ1VURRwF1QFUSUxERSEKzDwgQU5EIEFDVVRFJgnOPERJQUVSRVNJUyYGrARNQUNST04WAaIDSRYLwM8CTEQgUE9MSVNIIE8WBLbPAk1FR0EWAc7OAk8WBZADUEVOIEUaAYYDTxYBogRVFQFQUBYL1DwgV0lUSCBBQ1VURRwJ1jxET1QgQUJPVkUcCNLOAkZMT1VSSVNIHASkA0hPT0scDdTOAlNRVUlSUkVMIFRBSUwdBeNYVFJPS0UiEtDOAiBUSFJPVUdIIERFU0NFTkRFUhYazs8CSEFSWU5HRUFMIFZPSUNFRCBGUklDQVRJVkUVAVFRFhXYzgIgV0lUSCBESUFHT05BTCBTVFJPS0UcGNbOAlNUUk9LRSBUSFJPVUdIIERFU0NFTkRFUhUBUlIWCNrOAiBST1RVTkRBFwrUAldJVEggQUNVVEUcBdgCQ0FST04dBtYCRURJTExBHAnYPERPVCBBQk9WRSAF2jxCRUxPVyUL3DwgQU5EIE1BQ1JPTh4KkARVQkxFIEdSQVZFHA6SBElOVkVSVEVEIEJSRVZFHArePExJTkUgQkVMT1ccDqbPAk9CTElRVUUgU1RST0tFHAbMBFNUUk9LRRwE5FhUQUlMFgjLzwJBTVMgSE9SThYSvs4CRVZFUlNFRCBDIFdJVEggRE9UHgGOA0UeBvXPAkhBTEYgSB4Gq88CT1BFTiBFFgrczgJVTSBST1RVTkRBFQFTUxYL2gIgV0lUSCBBQ1VURSEO5DwgQU5EIERPVCBBQk9WRRwF4AJDQVJPTiEO5jwgQU5EIERPVCBBQk9WRR0G3gJFRElMTEEdCdwCSVJDVU1GTEVYHQqYBE9NTUEgQkVMT1ccD8zPAkRJQUdPTkFMIFNUUk9LRR0I4DxPVCBBQk9WRSAF4jxCRUxPVyUO6DwgQU5EIERPVCBBQk9WRRwExc8CSE9PSxwOqM8C", + "T0JMSVFVRSBTVFJPS0UcFMnPAlNIT1JUIFNUUk9LRSBPVkVSTEFZHQn+WFdBU0ggVEFJTBYHi88CQUxUSUxMTxYEjwNDSFdBFwaszwJSSVBUIEcWBp49SEFSUCBTFgjYzwJJR01PSUQgUxYOrs8CTUFMTCBDQVBJVEFMIEkbEMoEUSBXSVRIIEhPT0sgVEFJTBUBVFQWC+QCIFdJVEggQ0FST04dBuICRURJTExBHQ/wPElSQ1VNRkxFWCBCRUxPVx0KmgRPTU1BIEJFTE9XHA++BERJQUdPTkFMIFNUUk9LRR0I6jxPVCBBQk9WRSAF7DxCRUxPVxwErANIT09LHAruPExJTkUgQkVMT1ccDq4DUkVUUk9GTEVYIEhPT0scBuYCU1RST0tFFgTeAUhPUk4aDOTOAiBXSVRIIFNUUk9LRSYS5s4CIFRIUk9VR0ggREVTQ0VOREVSFgi8A09ORSBGSVZFGgOEA1NJWBoDpwNUV08WB6rOAlJFU0lMTE8WB+9YVVJORUQgQR0E8FhMUEhBHAGNzwJIHAn+zgJJTlNVTEFSIEccAbDPAkscAYDPAkwcAZwDTRwBsc8CVBwBxQRWFgGozgJaFQFVVRYExAQgQkFSFwraAVdJVEggQUNVVEUcBewCQlJFVkUcBdMDQ0FST04dCdsBSVJDVU1GTEVYJgb2PCBCRUxPVxwJ3AFESUFFUkVTSVMlCtcDIEFORCBBQ1VURSoF2QNDQVJPTioF2wNHUkFWRSoG1QNNQUNST04mBfI8QkVMT1cdCOQ9T1QgQkVMT1ceCvACVUJMRSBBQ1VURSMFlARHUkFWRRwF2QFHUkFWRRwK5j1IT09LIEFCT1ZFHgKvA1JOIAroPSBBTkQgQUNVVEUlCfA9RE9UIEJFTE9XJQXqPUdSQVZFJQrsPUhPT0sgQUJPVkUlBe49VElMREUcDpYESU5WRVJURUQgQlJFVkUcBuoCTUFDUk9OIg76PCBBTkQgRElBRVJFU0lTHAbyAk9HT05FSxwK7gJSSU5HIEFCT1ZFHAa4zwJTVFJPS0UcBegCVElMREUhCvg8IEFORCBBQ1VURSIF9DxCRUxPVxYGsQNQU0lMT04VAVZWFhXezgIgV0lUSCBESUFHT05BTCBTVFJPS0UdCP48T1QgQkVMT1ccBLIDSE9PSxwF/DxUSUxERRYD6M4CRU5EFgvizgJJU0lHT1RISUMgWhYJms8CT0xBUFVLIEFFHQKczwJPRR0Cns8CVUUWAeDOAlkVAVdXFguCPSBXSVRIIEFDVVRFHAr0AkNJUkNVTUZMRVgcCYQ9RElBRVJFU0lTHQiGPU9UIEFCT1ZFIAWIPUJFTE9XHAWAPUdSQVZFHATyWEhPT0sWA/cDWU5OFQFYWBYPjD0gV0lUSCBESUFFUkVTSVMdCIo9T1QgQUJPVkUVAVlZFgvdASBXSVRIIEFDVVRFHAr2AkNJUkNVTUZMRVgcCfgCRElBRVJFU0lTHQiOPU9UIEFCT1ZFIAX0PUJFTE9XHAXyPUdSQVZFHASzA0hPT0sgBvY9IEFCT1ZFHAT+PUxPT1AcBrIETUFDUk9OHAbOBFNUUk9LRRwF+D1USUxERRYDnARPR0gVAVpaFgv5AiBXSVRIIEFDVVRFHAX9AkNBUk9OHQmQPUlSQ1VNRkxFWBwJ61hERVNDRU5ERVIdCPsCT1QgQUJPVkUgBZI9QkVMT1ccBKQESE9PSxwKlD1MSU5FIEJFTE9XHAzGzwJQQUxBVEFMIEhPT0scBrUDU1RST0tFHQn/WFdBU0ggVEFJTA8KsgJJR0FUVVJFIElKFwLSAk9FBwSdTlJPU1MGG//PAkVQSUdSQVBISUMgTEVUVEVSIEFSQ0hBSUMgTRgH/s8CSSBMT05HQRkJ/c8CTlZFUlRFRCBNGAr7zwJSRVZFUlNFRCBGIQH8zwJQGAr3zwJTSURFV0FZUyBJBgqlOkxFVFRFUiBBSU4ODcIDTFZFT0xBUiBDTElDSw0TrQVCSURFTlRBTCBQRVJDVVNTSVZFDwyYBUxBQklBTCBDTElDSxYKrAVQRVJDVVNTSVZFDQzAA0RFTlRBTCBDTElDSw0MlAVHTE9UVEFMIFNUT1AZDKEFIFdJVEggU1RST0tFDRWWBUlOVkVSVEVEIEdMT1RUQUwgU1RPUCIKjr4HIFdJVEggQ1VSTCgGvgNTVFJPS0UNDcEDTEFURVJBTCBDTElDSw0blQVQSEFSWU5HRUFMIFZPSUNFRCBGUklDQVRJVkUND8MDUkVUUk9GTEVYIENMSUNLHBSKvgcgV0lUSCBSRVRST0ZMRVggSE9PSw8PqgNWRVJTRUQgRVNIIExPT1AWGKIFR0xPVFRBTCBTVE9QIFdJVEggU1RST0tFDQ+PzwJTSU5PTE9HSUNBTCBET1QODoA6TUFMTCBDQVBJVEFMIEEcAYE6RRsBmQVCHAeDOkFSUkVEIEIbAYQ6QxsBhTpEGwGHOkUcAoY6VEgcAqM6WkgbAbDOAkYbAeIERxwKmwUgV0lUSCBIT09LGwGcBUgbAeoESRwJgQVOVkVSVEVEIFIbAYo6ShsBizpLGwGfBUwcCoS+ByBXSVRIIEJFTFQiBow6U1RST0tFGwGNOk0bAfQEThsBjzpPHAH2BEUcBZA6UEVOIE8cAZU6VRsBmDpQGwGvzwJRGwGABVIcD8bWAiBXSVRIIFJJR0hUIExFRxwJjjpFVkVSU0VEIE4kAZk6UhwC9s4CVU0bAbHOAlMbAZs6VBwH+1hVUk5FRCBFIgGCvgdHIgGQvgdLIgH6zwJNIgGaOlIbAZw6VRsBoDpWGwGhOlcbAY8FWRsBojpaDgqXBVRSRVRDSEVEIEMYCo++ByBXSVRIIENVUkwND7sDVFdPIFdJVEggU1RST0tFDRikOlZPSUNFRCBMQVJZTkdFQUwgU1BJUkFOVA0EvwNXWU5ODQKmA1lSBiL7OlNNQUxMIENBUElUQUwgTEVUVEVSIEkgV0lUSCBTVFJPS0UbDf46VSBXSVRIIFNUUk9LRQwIYUxFVFRFUiBBFA+x1gIgUkVWRVJTRUQtU0NIV0EVCuEBV0lUSCBBQ1VURRoFgwJCUkVWRR8Krz0gQU5EIEFDVVRFJAm3PURPVCBCRUxPVyQFsT1HUkFWRSQKsz1IT09LIEFCT1ZFJAW1PVRJTERFGgXOA0NBUk9OGwniAUlSQ1VNRkxFWCQKpT0gQU5EIEFDVVRFKQmtPURPVCBCRUxPVykFpz1HUkFWRSkKqT1IT09LIEFCT1ZFKQWrPVRJTERFGgnkAURJQUVSRVNJUyML3wMgQU5EIE1BQ1JPThsIpwRPVCBBQk9WRSML4QMgQU5EIE1BQ1JPTh4FoT1CRUxPVxwKgQRVQkxFIEdSQVZFGgXgAUdSQVZFGgqjPUhPT0sgQUJPVkUaDoMESU5WRVJURUQgQlJFVkUaBoECTUFDUk9OGgaFAk9HT05FSxoOjztSRVRST0ZMRVggSE9PSxsOmj1JR0hUIEhBTEYgUklORxwI5QFORyBBQk9WRSQK+wMgQU5EIEFDVVRFHwWBPEJFTE9XGgblWFNUUk9LRRoF4wFUSUxERRQBs84CQRQB5gFFFQv9AyBXSVRIIEFDVVRFGwbjA01BQ1JPThQE0QRMUEhBGBSQOyBXSVRIIFJFVFJPRkxFWCBIT09LFArDzwJOR0xJQ0FOQSBXFAG1zgJPFAG3zgJVFAG5zgJWFRS7zgIgV0lUSCBIT1JJWk9OVEFMIEJBUhQBvc4CWRMBYkIUD4M8IFdJVEggRE9UIEFCT1ZFHgWFPEJFTE9XGgiXzwJGTE9VUklTSBoE0wRIT09LGgqHPExJTkUgQkVMT1caDOw6TUlERExFIFRJTERFGgyAO1BBTEFUQUwgSE9PSxoGgANTVFJPS0UaBoMDVE9QQkFSFAuw1gJBUlJFRCBBTFBIQRoBs9YCRRoB9QRPFQrN1gJTRUxJTkUgRVNIFAO1zwJFVEEUDLLWAkxBQ0tMRVRURVIgRR8BvdYCTyAMvtYCIFdJVEggU1RST0tFFAyXOk9UVE9NIEhBTEYgTxQHx84CUk9LRU4gTBMBY0MUC4cCIFdJVEggQUNVVEUaA5PPAkJBUhoFjQJDQVJPThsG5wFFRElMTEEhCok8IEFORCBBQ1VURRsJiQJJUkNVTUZMRVgbA9UEVVJMGgmLAkRPVCBBQk9WRRoEiANIT09LGgyUzwJQQUxBVEFMIEhPT0saDp2+B1JFVFJPRkxFWCBIT09LGga8BFNUUk9LRRQC09YCSEkWFNXWAiBXSVRIIExPVyBMRUZUIFNFUklGIArU1gJSSUdIVCBSSU5HFA/RzwJMT1NFRCBJTlNVTEFSIEcaBfcET01FR0EbBZoFUEVOIEUaD94EUkVWRVJTRUQgT1BFTiBFFALvzgJPThQIrc4CVUFUUklMTE8cC6/OAiBXSVRIIENPTU1BEwFkRBQLjwIgV0lUSCBDQVJPThsGkTxFRElMTEEbD5M8SVJDVU1GTEVYIEJFTE9XGwOhBFVSTBoJizxET1QgQUJPVkUeBY08QkVMT1caBNcESE9PSx4JkTsgQU5EIFRBSUwaCo88TElORSBCRUxPVxoUpb4HTUlELUhFSUdIVCBMRUZUIEhPT0sdCe06RExFIFRJTERFGgyBO1BBTEFUQUwgSE9PSxoUyM8CU0hPUlQgU1RST0tFIE9WRVJMQVkbBZECVFJPS0UaBNYEVEFJTBsFjANPUEJBUhQJuARCIERJR1JBUEgUBJ89RUxUQRUKpAVaSCBESUdSQVBIHxKSvgcgV0lUSCBQQUxBVEFMIEhPT0slDpm+B1JFVFJPRkxFWCBIT09LFAixAk9UTEVTUyBJGwG3BEocDN8EIFdJVEggU1RST0tFKAmEBSBBTkQgSE9PSxUGyNYCVUJMRSBSGxLK1gIgV0lUSCBDUk9TU0VELVRBSUwaBdPPAlRIT1JOGgTVzwJXWU5OFALxzgJVTRQB8wNaFQijBSBESUdSQVBIHQqlBSBXSVRIIENVUkwjDubWAlJFVFJPRkxFWCBIT09LFgrGA1dJVEggQ0FST04TAWVFFAvpASBXSVRIIEFDVVRFGgWVAkJSRVZFGgWbAkNBUk9OGwapBEVESUxMQSEKnTwgQU5EIEJSRVZFGwnqAUlSQ1VNRkxFWCQKvz0gQU5EIEFDVVRFKQnHPURPVCBCRUxPVykFwT1HUkFWRSkKwz1IT09LIEFCT1ZFKQXFPVRJTERFJQWZPEJFTE9XGgnrAURJQUVSRVNJUxsIlwJPVCBBQk9WRR4FuT1CRUxPVxwKhQRVQkxFIEdSQVZFGgi01gJGTE9VUklTSBoF6AFHUkFWRRoKuz1IT09LIEFCT1ZFGg6HBElOVkVSVEVEIEJSRVZFGgaTAk1BQ1JPTiAKlzwgQU5EIEFDVVRFJQWVPEdSQVZFGgX4WE5PVENIGgaZAk9HT05FSxoOkjtSRVRST0ZMRVggSE9PSxoGxwRTVFJPS0UaBb09VElMREUfBps8IEJFTE9XFBClzgJHWVBUT0xPR0lDQUwgQUlOIgOjzgJMRUYUAssCTkcWErzWAiBXSVRIIENST1NTRUQtVEFJTBwMlL4HUEFMQVRBTCBIT09LFAKDBVNIFgqGBSBXSVRIIENVUkwcCou+B0RPVUJMRSBCQVImCYy+ByBBTkQgQ1VSTBwMiztQQUxBVEFMIEhPT0scDpg7UkVUUk9GTEVYIEhPT0sUAevOAlQVAfABSBQCkgVaSBYJuQMgUkVWRVJTRUQXCu8DV0lUSCBDQVJPTh0DkwVVUkwcDJi+B1BBTEFUQUwgSE9PSxwOmjtSRVRST0ZMRVggSE9PSxwEugNUQUlMEwFmRhQPnzwgV0lUSCBET1QgQUJPVkUaBJIDSE9PSxoM7jpNSURETEUgVElMREUaDII7UEFMQVRBTCBIT09LGgaZzwJTVFJPS0UUC6kFRU5HIERJR1JBUEgfC4C+ByBXSVRIIFRSSUxMEwFnRxQL9QMgV0lUSCBBQ1VURRoFnwJCUkVWRRoF5wNDQVJPThsGowJFRElMTEEbCZ0CSVJDVU1GTEVYGgmhAkRPVCBBQk9WRRoE4ARIT09LGgahPE1BQ1JPThoOoc8CT0JMSVFVRSBTVFJPS0UaDIM7UEFMQVRBTCBIT09LGgblA1NUUk9LRRQE4wRBTU1BFAKjA0hBFAi7zwJMT1RUQUwgQRsBvc8CSRsEwgRTVE9QGwG/zwJVEwFoSBQRqzwgV0lUSCBCUkVWRSBCRUxPVxoFnwRDQVJPThsGqTxFRElMTEEbCaUCSVJDVU1GTEVYGgnoWERFU0NFTkRFUhsIpzxJQUVSRVNJUxsIozxPVCBBQk9WRR4FpTxCRUxPVxoE5gRIT09LGgqWPUxJTkUgQkVMT1caDJXPAlBBTEFUQUwgSE9PSxoGpwJTVFJPS0UUBfZYQUxGIEgUA6fOAkVORxcK5wQgV0lUSCBIT09LFAGVA1YTAWlJFAvtASBXSVRIIEFDVVRFGgWtAkJSRVZFGgXQA0NBUk9OGwnuAUlSQ1VNRkxFWBoJ7wFESUFFUkVTSVMjCq88IEFORCBBQ1VURRsIyz1PVCBCRUxPVxwKiQRVQkxFIEdSQVZFGgXsAUdSQVZFGgrJPUhPT0sgQUJPVkUaDosESU5WRVJURUQgQlJFVkUaBqsCTUFDUk9OGgavAk9HT05FSxoOljtSRVRST0ZMRVggSE9PSxoG6ARTVFJPS0UgE5q+ByBBTkQgUkVUUk9GTEVYIEhPT0saBakCVElMREUfBq08IEJFTE9XFAj6zgJOU1VMQVIgRBsB/M4CRhsB+TpHGwGDzwJSGwGFzwJTGwGHzwJUFQzk1gJWRVJURUQgQUxQSEEcAsDWAk9FFAPpBE9UQRcM/DogV0lUSCBTVFJPS0UWB+HWAklGSUVEIEUUAe3OAlMTAWpKFAvwAyBXSVRIIENBUk9OGwm1AklSQ1VNRkxFWBsLnQVST1NTRUQtVEFJTBoGyQRTVFJPS0UTAWtLFAuxPCBXSVRIIEFDVVRFGgXpA0NBUk9OGwa3AkVESUxMQRoJ6lhERVNDRU5ERVIbDsPOAklBR09OQUwgU1RST0tFGwizPE9UIEJFTE9XGgSZA0hPT0saCrU8TElORSBCRUxPVxoOo88CT0JMSVFVRSBTVFJPS0UaDIQ7UEFMQVRBTCBIT09LGgbBzgJTVFJPS0UgFMXOAiBBTkQgRElBR09OQUwgU1RST0tFFAK4AlJBEwFsTBQLugIgV0lUSCBBQ1VURRoDmgNCQVIbA+wERUxUHhGTvgcgQU5EIFBBTEFUQUwgSE9PSxoFvgJDQVJPThsGvAJFRElMTEEbD708SVJDVU1GTEVYIEJFTE9XGwO0BFVSTBoJtzxET1QgQkVMT1cjC7k8IEFORCBNQUNST04cCOFYVUJMRSBCQVIhDLjWAk1JRERMRSBUSUxERRoIkb4HRklTSEhPT0saC8nOAkhJR0ggU1RST0tFGg+31gJJTlZFUlRFRCBMQVpZIFMaCrs8TElORSBCRUxPVxoUpr4HTUlELUhFSUdIVCBMRUZUIEhPT0sdB8ACRExFIERPVCEEudYCUklORyEF6wRUSUxERRoMhTtQQUxBVEFMIEhPT0saDu0EUkVUUk9GTEVYIEhPT0soCY7PAiBBTkQgQkVMVBoGwgJTVFJPS0UUBdvPAkFNQkRBGQybAyBXSVRIIFNUUk9LRRQGtdYCRU5JUyBGFQLuBFpIFxSFvgcgV0lUSCBSRVRST0ZMRVggSE9PSxQByQNKFAX/Ak9ORyBTGRWcPSBXSVRIIERJQUdPTkFMIFNUUk9LRSAImz1PVCBBQk9WRR8LnT1ISUdIIFNUUk9LRRQJqgVTIERJR1JBUEgUAvLOAlVNFAmrBVogRElHUkFQSBMBbU0UC788IFdJVEggQUNVVEUaDLrWAkNST1NT", + "RUQtVEFJTBoJwTxET1QgQUJPVkUeBcM8QkVMT1caBPEESE9PSxoM7zpNSURETEUgVElMREUaDIY7UEFMQVRBTCBIT09LFA3XzwJJRERMRSBTQ09UUyBTGQn7PS1XRUxTSCBMTCAB/T1WFALzzgJVTRMBbk4UF8kCIFBSRUNFREVEIEJZIEFQT1NUUk9QSEUVCsQCV0lUSCBBQ1VURRoFyAJDQVJPThsGxgJFRElMTEEbD8s8SVJDVU1GTEVYIEJFTE9XGwu71gJST1NTRUQtVEFJTBsDtQRVUkwaCZHPAkRFU0NFTkRFUhsIxTxPVCBBQk9WRR4FxzxCRUxPVxoF+QNHUkFWRRoJ8gRMRUZUIEhPT0sbCck8SU5FIEJFTE9XGw2eA09ORyBSSUdIVCBMRUcaFKe+B01JRC1IRUlHSFQgTEVGVCBIT09LHQnwOkRMRSBUSUxERRoOpc8CT0JMSVFVRSBTVFJPS0UaDIc7UEFMQVRBTCBIT09LGg7zBFJFVFJPRkxFWCBIT09LGgXxAVRJTERFFAHMA0oUAvTOAlVNEwFvTxQL8wEgV0lUSCBBQ1VURRoFzwJCUkVWRRoF0gNDQVJPThsJ9AFJUkNVTUZMRVgkCtE9IEFORCBBQ1VURSkJ2T1ET1QgQkVMT1cpBdM9R1JBVkUpCtU9SE9PSyBBQk9WRSkF1z1USUxERRoJ9gFESUFFUkVTSVMjC6sEIEFORCBNQUNST04bCK8ET1QgQUJPVkUjC7EEIEFORCBNQUNST04eBc09QkVMT1ccCtECVUJMRSBBQ1VURSEFjQRHUkFWRRoF8gFHUkFWRRoKzz1IT09LIEFCT1ZFHAKhA1JOHgrbPSBBTkQgQUNVVEUjCeM9RE9UIEJFTE9XIwXdPUdSQVZFIwrfPUhPT0sgQUJPVkUjBeE9VElMREUaDo8ESU5WRVJURUQgQlJFVkUaE8vOAkxPTkcgU1RST0tFIE9WRVJMQVkcAs3OAk9QHA36WFcgUklORyBJTlNJREUaBs0CTUFDUk9OIArTPCBBTkQgQUNVVEUlBdE8R1JBVkUaBusDT0dPTkVLIAvtAyBBTkQgTUFDUk9OGg6bvgdSRVRST0ZMRVggSE9PSxoG+AFTVFJPS0UgCv8DIEFORCBBQ1VURRoF9QFUSUxERR8KzTwgQU5EIEFDVVRFJAnPPERJQUVSRVNJUyQGrQRNQUNST04UAaMDSRQLwc8CTEQgUE9MSVNIIE8UBLfPAk1FR0EUAc/OAk8UBdsEUEVOIEUZFJM7IFdJVEggUkVUUk9GTEVYIEhPT0sYAdQETxkUlzsgV0lUSCBSRVRST0ZMRVggSE9PSx8Gv9YCU1RST0tFGQHi1gJFFAGjBFUTAXBQFAvVPCBXSVRIIEFDVVRFGgnXPERPVCBBQk9WRRoI084CRkxPVVJJU0gaBKUDSE9PSxoM8TpNSURETEUgVElMREUaDIg7UEFMQVRBTCBIT09LGg3VzgJTUVVJUlJFTCBUQUlMGwX9OlRST0tFIBLRzgIgVEhST1VHSCBERVNDRU5ERVIUGs/PAkhBUllOR0VBTCBWT0lDRUQgRlJJQ0FUSVZFFQH4BEkTAXFRFBXZzgIgV0lUSCBESUFHT05BTCBTVFJPS0UaBKAFSE9PSx4FywQgVEFJTBoY184CU1RST0tFIFRIUk9VR0ggREVTQ0VOREVSFAm5BFAgRElHUkFQSBMBclIUCNvOAiBST1RVTkRBFQrVAldJVEggQUNVVEUaBdkCQ0FST04bBtcCRURJTExBGwvJ1gJST1NTRUQtVEFJTBoJ2TxET1QgQUJPVkUeBds8QkVMT1cjC908IEFORCBNQUNST04cCpEEVUJMRSBHUkFWRRoI/gRGSVNISE9PSyIR8zogQU5EIE1JRERMRSBUSUxERScMlr4HUEFMQVRBTCBIT09LGg6TBElOVkVSVEVEIEJSRVZFGgrfPExJTkUgQkVMT1cbB/wET05HIExFRxoUqL4HTUlELUhFSUdIVCBMRUZUIEhPT0sdCfI6RExFIFRJTERFGg6nzwJPQkxJUVVFIFNUUk9LRRoMiTtQQUxBVEFMIEhPT0saBs0EU1RST0tFGgT9BFRBSUwZCsfWAk9VVCBIQU5ETEUUCOQEQU1TIEhPUk4UCYRDRVZFUlNFRCBDHQm/zgIgV0lUSCBET1QcAdgERR0Ch74HTkccBvbPAkhBTEYgSBwBg74HSxwG3ARPUEVOIEUiCt0EIFdJVEggSE9PSygOlDtSRVRST0ZMRVggSE9PSxwP/wRSIFdJVEggRklTSEhPT0scCIG+B1NDUklQVCBHFAL1zgJVTRYI3c4CIFJPVFVOREETAXNTFAvbAiBXSVRIIEFDVVRFHw7lPCBBTkQgRE9UIEFCT1ZFGgXhAkNBUk9OHw7nPCBBTkQgRE9UIEFCT1ZFGwbfAkVESUxMQRsJ3QJJUkNVTUZMRVgbCpkET01NQSBCRUxPVxsDnr4HVVJMGg/NzwJESUFHT05BTCBTVFJPS0UbCOE8T1QgQUJPVkUeBeM8QkVMT1cjDuk8IEFORCBET1QgQUJPVkUaBIIFSE9PSxoUqb4HTUlELUhFSUdIVCBMRUZUIEhPT0sdCfQ6RExFIFRJTERFGg6pzwJPQkxJUVVFIFNUUk9LRRoMijtQQUxBVEFMIEhPT0saFMrPAlNIT1JUIFNUUk9LRSBPVkVSTEFZGwm/BFdBU0ggVEFJTBQI4NYCQUtIQSBZQVQVBozPAkxUSUxMTxQE2QRDSFdBGAraBCBXSVRIIEhPT0seDpU7UkVUUk9GTEVYIEhPT0sVBuEEUklQVCBHGxK21gIgV0lUSCBDUk9TU0VELVRBSUwaAcvWAlIbCszWAiBXSVRIIFJJTkcUBt8BSEFSUCBTFBWeOklERVdBWVMgRElBRVJFU0laRUQgVRwBkTpPHQyTOiBXSVRIIFNUUk9LRR0FkjpQRU4gTxwInzpUVVJORUQgTRwBnTpVFQfZzwJHTU9JRCBTFBGFBVFVQVQgUkVWRVJTRUQgRVNIFAjF1gJUSVJSVVAgUhMBdFQUC+UCIFdJVEggQ0FST04bBuMCRURJTExBGw/xPElSQ1VNRkxFWCBCRUxPVxsKmwRPTU1BIEJFTE9XGwO2BFVSTBoJlz1ESUFFUkVTSVMdDOZYR09OQUwgU1RST0tFGwjrPE9UIEFCT1ZFHgXtPEJFTE9XGgStA0hPT0seE4m+ByBBTkQgUkVUUk9GTEVYIEhPT0saCu88TElORSBCRUxPVxoUqr4HTUlELUhFSUdIVCBMRUZUIEhPT0sdCfU6RExFIFRJTERFGgyrA1BBTEFUQUwgSE9PSxoOiAVSRVRST0ZMRVggSE9PSxoG5wJTVFJPS0UUC/dYQUlMTEVTUyBQSEkUE6gFQyBESUdSQVBIIFdJVEggQ1VSTBQLpwVFU0ggRElHUkFQSB8Sl74HIFdJVEggUEFMQVRBTCBIT09LJQ6cvgdSRVRST0ZMRVggSE9PSxQU+jpIIFdJVEggU1RSSUtFVEhST1VHSBUD/gFPUk4YDOXOAiBXSVRIIFNUUk9LRSQS584CIFRIUk9VR0ggREVTQ0VOREVSFAi9A09ORSBGSVZFGAOFA1NJWBgDqANUV08VCJY6UCBIQUxGIE8UB6vOAlJFU0lMTE8UCaYFUyBESUdSQVBIHRTn1gIgV0lUSCBSRVRST0ZMRVggSE9PSxQC984CVU0VBtAEUk5FRCBBGwGCOkUbBNIETFBIQRoFjQNERUxUQRoB3QNFGgH3OkcaAeUESBsOrgUgV0lUSCBGSVNISE9PSykJrwUgQU5EIFRBSUwaAYk6SRsI/84CTlNVTEFSIEcaAZ4FSxoBgc8CTBoB7wRNGw7wBCBXSVRIIExPTkcgTEVHGgjD1gJPIE9QRU4tTyIMxNYCIFdJVEggU1RST0tFGwGUOkUcF8LWAiBXSVRIIEhPUklaT05UQUwgU1RST0tFIgbB1gJTVFJPS0UbBYg6UEVOIEUaAfkEUhsK+wQgV0lUSCBIT09LIQj6BExPTkcgTEVHKROIvgcgQU5EIFJFVFJPRkxFWCBIT09LIQzo1gJNSURETEUgVElMREUhDJW+B1BBTEFUQUwgSE9PSyEE+VhUQUlMGgGHBVQbCo2+ByBXSVRIIENVUkwaAtHWAlVJGgGMBVYaAY0FVxoBjgVZGwqGvgcgV0lUSCBCRUxUFAGpzgJaEwF1VRQEiQUgQkFSGBXP1gIgV0lUSCBTSE9SVCBSSUdIVCBMRUcVCvoBV0lUSCBBQ1VURRoF7QJCUkVWRRoF1ANDQVJPThsJ+wFJUkNVTUZMRVgkBvc8IEJFTE9XGgn8AURJQUVSRVNJUyMK2AMgQU5EIEFDVVRFKAXaA0NBUk9OKAXcA0dSQVZFKAbWA01BQ1JPTiQF8zxCRUxPVxsI5T1PVCBCRUxPVxwK8QJVQkxFIEFDVVRFIQWVBEdSQVZFGgX5AUdSQVZFGgrnPUhPT0sgQUJPVkUcArADUk4eCuk9IEFORCBBQ1VURSMJ8T1ET1QgQkVMT1cjBes9R1JBVkUjCu09SE9PSyBBQk9WRSMF7z1USUxERRoOlwRJTlZFUlRFRCBCUkVWRRoJ0tYCTEVGVCBIT09LGgbrAk1BQ1JPTiAO+zwgQU5EIERJQUVSRVNJUxoG8wJPR09ORUsaDpk7UkVUUk9GTEVYIEhPT0sbCe8CSU5HIEFCT1ZFGg/O1gJTSE9SVCBSSUdIVCBMRUcbBbnPAlRST0tFGgXpAlRJTERFHwr5PCBBTkQgQUNVVEUgBfU8QkVMT1cUAes6RRQB0NYCSRQB+M4CTRQB49YCTxQGigVQU0lMT04aDP86IFdJVEggU1RST0tFEwF2VhQK9FggV0lUSCBDVVJMGg/fzgJESUFHT05BTCBTVFJPS0UbCP88T1QgQkVMT1caBIsFSE9PSxoMjDtQQUxBVEFMIEhPT0saCvFYUklHSFQgSE9PSxoF/TxUSUxERRQD6c4CRU5EFAvjzgJJU0lHT1RISUMgWhQJm88CT0xBUFVLIEFFGwKdzwJPRRsCn88CVUUUAeHOAlkTAXdXFAuDPSBXSVRIIEFDVVRFGgr1AkNJUkNVTUZMRVgaCYU9RElBRVJFU0lTGwiHPU9UIEFCT1ZFHgWJPUJFTE9XGgWBPUdSQVZFGgTzWEhPT0saCpg9UklORyBBQk9WRRMBeFgUD409IFdJVEggRElBRVJFU0lTGwiLPU9UIEFCT1ZFGg3X1gJMT05HIExFRlQgTEVHJxPY1gIgQU5EIExPVyBSSUdIVCBSSU5HKArZ1gJXSVRIIFNFUklGHAzW1gJXIFJJR0hUIFJJTkcaDI07UEFMQVRBTCBIT09LEwF5WRQL/QEgV0lUSCBBQ1VURRoK9wJDSVJDVU1GTEVYGgn/AURJQUVSRVNJUxsIjz1PVCBBQk9WRR4F9T1CRUxPVxoF8z1HUkFWRRoEtANIT09LHgb3PSBBQk9WRRoE/z1MT09QGgazBE1BQ1JPThoKmT1SSU5HIEFCT1ZFGg/a1gJTSE9SVCBSSUdIVCBMRUcbBc8EVFJPS0UaBfk9VElMREUUA50ET0dIEwF6WhQL+gIgV0lUSCBBQ1VURRoF/gJDQVJPThsJkT1JUkNVTUZMRVgbA5EFVVJMGgnsWERFU0NFTkRFUhsI/AJPVCBBQk9WRR4Fkz1CRUxPVxoEpQRIT09LGgqVPUxJTkUgQkVMT1caDPY6TUlERExFIFRJTERFGgyOO1BBTEFUQUwgSE9PSxoOkAVSRVRST0ZMRVggSE9PSxoGtgNTVFJPS0UbCcAEV0FTSCBUQUlMDQqA9gNJR0FUVVJFIEZGFwGD9gNJFwGE9gNMFgGB9gNJFgGC9gNMFQKzAklKFQiF9gNMT05HIFMgVBUC0wJPRRUChvYDU1QHF5BBVUJTQ1JJUFQgU01BTEwgTEVUVEVSIEEdAZFBRR0BlUFIHQHiOkkdAfxYSh0BlkFLHQGXQUwdAZhBTR0BmUFOHQGSQU8dAZpBUB0B4zpSHQGbQVMeBJRBQ0hXQR0BnEFUHQHkOlUdAeU6Vh0Bk0FYARbD5gdFQUYgRkxVVFRFUklORyBJTiBXSU5EBAm+9QdMRVNTIFRSRUUEB+zyB1kgR1JFRU4CBNLpB0RHRVICNun2B0ZUIEFORCBMT1dFUiBBTkQgUklHSFQgVFJJQU5HVUxBUiBUSFJFRSBRVUFSVEVSUyBCTE9DSw8Q/PYHT05FIEVJR0hUSCBCTE9DSwkW2k9SSUdIVCBET1VCTEUgVFVSTlNUSUxFDwTbT1RBQ0sQFJv3B1JJQU5HVUxBUiBIQUxGIEJMT0NLCS/r9gdVUFBFUiBBTkQgUklHSFQgVFJJQU5HVUxBUiBUSFJFRSBRVUFSVEVSUyBCTE9DSw8Q/fYHT05FIEVJR0hUSCBCTE9DSx8ejpkHIENPTlRBSU5JTkcgQkxBQ0sgU01BTEwgU1FVQVJFBwru6wdHRVIgQlVCQkxFCAqIYExFIEJSQUNLRVQSCZFTIFdJVEggRE9UBhSTU1JDIExFU1MtVEhBTiBCUkFDS0VUBxWyVlJPVyBXSVRIIENJUkNMRUQgUExVUxAMsFZTTUFMTCBDSVJDTEUFIdBSQkFSQiBET1dOIFJJR0hUIEJBUkIgRE9XTiBIQVJQT09OGgrLUlVQIEhBUlBPT04KGspSVVAgUklHSFQgQkFSQiBET1dOIEhBUlBPT04YCs5SVVAgSEFSUE9PTgYXkGBMQUNLIExFTlRJQ1VMQVIgQlJBQ0tFVAsWl1NUT1JUT0lTRSBTSEVMTCBCUkFDS0VUBQeIRkNFSUxJTkcGC9xNTE9TRUQgRU5UUlkGDYxgT1JORVIgQlJBQ0tFVAYMe1VSTFkgQlJBQ0tFVBILqUcgTE9XRVIgSE9PSxMMqEdNSURETEUgUElFQ0UTCqdHVVBQRVIgSE9PSwUbhFxET1RURUQgU1VCU1RJVFVUSU9OIEJSQUNLRVQHEopgVUJMRSBBTkdMRSBCUkFDS0VUDAuoXFBBUkVOVEhFU0lTDA6cQFFVT1RBVElPTiBNQVJLDAzaU1dJR0dMWSBGRU5DRQUJ/FJGSVNIIFRBSUwHEItLVkUgRUlHSFRIUyBCTE9DSwYEikZMT09SBRHWS0hBTEYgQkxBQ0sgQ0lSQ0xFEAToV1NUQVIMA4xLT0NLCgaH8gdDSVJDTEUQCYbyByBXSVRIIERPVBYJg/IHRk9VUiBET1RTFgqE8gdUSFJFRSBET1RTFweF8gdXTyBET1RTCg2kmQdGTFlJTkcgU0FVQ0VSCwW59wdPTERFUgolkJwHSE9SSVpPTlRBTCBMSU5FIFdJVEggVEhSRUUgVElDSyBNQVJLUwoplPcHSU5WRVJTRSBNRURJVU0gU0hBREUgQU5EIFJJR0hUIEhBTEYgQkxPQ0sKF6OdB0xPV0VSIE9ORSBRVUFSVEVSIEJMT0NLCgyM9wdNRURJVU0gU0hBREUKC7L3B1JVTk5JTkcgTUFOChaNnAdUUklQTEUgREFTSCBIT1JJWk9OVEFMCheonQdVUFBFUiBPTkUgUVVBUlRFUiBCTE9DSwoNi5wHV0hJVEUgRUxMSVBTRQcV++oHTkQgVEVMRVBIT05FIFJFQ0VJVkVSBSHr9wdKVVNUSUZJRUQgUklHSFQgSEFMRiBCTEFDSyBDSVJDTEUaDOP3B1dISVRFIENJUkNMRQUWnFxMT1cgUEFSQVBIUkFTRSBCUkFDS0VUBgbF7QdVR0dBR0UFCNxPTVVMVElNQVAFIMlFTk9STUFMIEZBQ1RPUiBTRU1JRElSRUNUIFBST0RVQ1QFEI9LT05FIEVJR0hUSCBCTE9DSwkNjktRVUFSVEVSIEJMT0NLCQvP9wdUSElSRCBCTE9DSwYJ1U9VVEVSIEpPSU4FCyhQQVJFTlRIRVNJUxAK", + "nEcgRVhURU5TSU9OEQqdR0xPV0VSIEhPT0sRCptHVVBQRVIgSE9PSwUXjFxSQUlTRUQgT01JU1NJT04gQlJBQ0tFVAYKlENJR0hUIEFSUk9XEBXIUiBUSFJPVUdIIFNNQUxMIENJUkNMRREb/ENXSVRIIERPVUJMRSBWRVJUSUNBTCBTVFJPS0UWBq5DU1RST0tFFg/5Q1ZFUlRJQ0FMIFNUUk9LRQsLjFZCTEFDSyBBUlJPVwsM1ENET1VCTEUgQVJST1cXDM5DIFdJVEggU1RST0tFHQ+EUlZFUlRJQ0FMIFNUUk9LRQsR/0NPUEVOLUhFQURFRCBBUlJPVwsQ2PAHU0FOUy1TRVJJRiBBUlJPVwsV5FZUUklBTkdMRS1IRUFERUQgQVJST1cLCq1DV0FWRSBBUlJPVwwKhFZISVRFIEFSUk9XBRbFT1MtU0hBUEVEIEJBRyBERUxJTUlURVIGEctFRU1JRElSRUNUIFBST0RVQ1QHEYlLVkVOIEVJR0hUSFMgQkxPQ0sGEaZcSURFV0FZUyBVIEJSQUNLRVQHE5hATkdMRSBRVU9UQVRJT04gTUFSSwYM6OsHUEVFQ0ggQlVCQkxFBg1bUVVBUkUgQlJBQ0tFVBMKokcgRVhURU5TSU9OFAyjR0xPV0VSIENPUk5FUhQMoUdVUFBFUiBDT1JORVIUEtdcV0lUSCBET1VCTEUgU1RST0tFGQXFQFFVSUxMGQbVXFNUUk9LRRkVj1NUSUNLIElOIEJPVFRPTSBDT1JORVIhCo1TVE9QIENPUk5FUhkIi1NVTkRFUkJBUgYTglxVQlNUSVRVVElPTiBCUkFDS0VUBQSjRVRBQ0sGDYuYB0hJUkQgSU5EVUNUT1ILGsH3B1dISVRFIFJJR0hUIFBPSU5USU5HIElOREVYBwzs6wdPVUdIVCBCVUJCTEUHEY1LUkVFIEVJR0hUSFMgQkxPQ0sLDopLUVVBUlRFUlMgQkxPQ0sUF6KdB0xPV0VSIE9ORSBRVUFSVEVSIEJMT0NLFBepnQdVUFBFUiBPTkUgUVVBUlRFUiBCTE9DSwYVlGBPUlRPSVNFIFNIRUxMIEJSQUNLRVQGFIlcUkFOU1BPU0lUSU9OIEJSQUNLRVQHGs9TSUFOR0xFIEJFU0lERSBWRVJUSUNBTCBCQVILFuz2B1VMQVIgT05FIFFVQVJURVIgQkxPQ0sGD873B1dPIFRISVJEUyBCTE9DSwUXoFxWRVJUSUNBTCBCQVIgV0lUSCBRVUlMTA8HuEdPWCBMSU5FBRSOYFdISVRFIENPUk5FUiBCUkFDS0VUDAyDU1VSTFkgQlJBQ0tFVAsSlmBMRU5USUNVTEFSIEJSQUNLRVQLC4VTUEFSRU5USEVTSVMLDppgU1FVQVJFIEJSQUNLRVQLFphgVE9SVE9JU0UgU0hFTEwgQlJBQ0tFVAYL2FNJR0dMWSBGRU5DRQYLjusHUklUSU5HIEhBTkQEHo4LLUZBQ0lORyBBUk1FTklBTiBFVEVSTklUWSBTSUdODAjImAdCQVNTSU5FVAwEkpkHRklTSBAQlJkHIFdJVEggT1BFTiBNT1VUSA8Bm/IHVAwc9JgHU05BS0UgSEVBRCBXSVRIIENMT1NFRCBNT1VUSBwK8JgHT1BFTiBNT1VUSA0K1h9WQVNUSSBTSUdOFwrYHyBXSVRIIERPVFMFG+ZNSEFOREVEIElOVEVSTEFDRUQgUEVOVEFHUkFNBRH5mwdQT0lOVElORyBBSVJQTEFORQ8MqUZOR0xFIEJSQUNLRVQPCuCYB1RPTUlDIEJPTUIOFPxTQ1VSVkVEIEFOR0xFIEJSQUNLRVQOBY6YB0RJT0RFDxqrAU9VQkxFIEFOR0xFIFFVT1RBVElPTiBNQVJLDgv4mAdFTkVSR1kgV0FWRQ4QjeoHTUFHTklGWUlORyBHTEFTUw4Kl5kHUkFDSU5HIENBUg8E5ZgHSUZMRQ8NoJkHT0NLRVQgQk9PU1RFUhUE1pgHU0hJUBAQopkHTExFUiBDT0FTVEVSIENBUg4MgpgHU1RJQ0sgRklHVVJFDgSemQdUQU5LBR2qT1NIQURFRCBXSElURSBSSUdIVFdBUkRTIEFSUk9XBhu5UklERSBBUkMgQU5USUNMT0NLV0lTRSBBUlJPVwUSqkBUTy1SSUdIVCBFTUJFRERJTkcOB+ZASVNPTEFURQ4EjkBNQVJLDgitQE9WRVJSSURFBAuQQ1dBUkRTIEFSUk9XDxbKViBBQk9WRSBBTE1PU1QgRVFVQUwgVE8WF8JWUkVWRVJTRSBBTE1PU1QgRVFVQUwgVE8eDstWVElMREUgT1BFUkFUT1IWFsNSU0hPUlQgUklHSFRXQVJEUyBBUlJPVxYO81JUSUxERSBPUEVSQVRPUhEjtfcHTkQgVVBQRVIgQU5EIExPV0VSIE9ORSBFSUdIVEggQkxPQ0sQCKRDRlJPTSBCQVIYEZ9SIFRPIEJMQUNLIERJQU1PTkQVD8DxB0RPV05XQVJEUyBBUlJPVxAVxkNPVkVSIFJJR0hUV0FSRFMgQVJST1cQEfdSVEhST1VHSCBMRVNTLVRIQU4YBvpSU1VCU0VUGAG+VlgRBeRDTyBCQVIWHblDIE9WRVIgUklHSFRXQVJEUyBBUlJPVyBUTyBCQVIUDJ1STEFDSyBESUFNT05EEBC4VldJVEggRE9UVEVEIFNURU0XFPpDVUJMRSBWRVJUSUNBTCBTVFJPS0UVFZTwB0VRVUlMQVRFUkFMIEFSUk9XSEVBRBUEqUNIT09LFRiI8AdMQVJHRSBUUklBTkdMRSBBUlJPV0hFQUQWA6tDT09QFRmE8AdNRURJVU0gVFJJQU5HTEUgQVJST1dIRUFEFQyY8QdOT1RDSEVEIFRBSUwVCsZSUExVUyBCRUxPVxUbkPAHU01BTEwgRVFVSUxBVEVSQUwgQVJST1dIRUFEGxKA8AdUUklBTkdMRSBBUlJPV0hFQUQWBZpDVFJPS0UVBKJDVEFJTBkculYgV0lUSCBET1VCTEUgVkVSVElDQUwgU1RST0tFHw+5VlZFUlRJQ0FMIFNUUk9LRRYMkFZJUCBET1dOV0FSRFMZB5FWVVBXQVJEUxUP90NWRVJUSUNBTCBTVFJPS0UPBZlSLVRBSUwKIKjxB0JBQ0stVElMVEVEIFNIQURPV0VEIFdISVRFIEFSUk9XCwqFVkxBQ0sgQVJST1cQE4hXQ0lSQ0xFRCBXSElURSBBUlJPVwsYoPEHT1RUT00tU0hBREVEIFdISVRFIEFSUk9XChC88AdDT01QUkVTU0VEIEFSUk9XCgzgQ0RBU0hFRCBBUlJPVwsL0ENPVUJMRSBBUlJPVxYJhlIgRlJPTSBCQVIXC81DV0lUSCBTVFJPS0UcD4JSVkVSVElDQUwgU1RST0tFFgWbUi1UQUlMEQqMUkRBU0ggQVJST1cKEbTwB0ZJTkdFUi1QT1NUIEFSUk9XCyCq8QdST05ULVRJTFRFRCBTSEFET1dFRCBXSElURSBBUlJPVwoE8vUHSEFORAwdy0NSUE9PTiBPVkVSIFJJR0hUV0FSRFMgSEFSUE9PThI251JXSVRIIEJBUkIgRE9XTiBBQk9WRSBSSUdIVFdBUkRTIEhBUlBPT04gV0lUSCBCQVJCIERPV04hD+tSQkVMT1cgTE9ORyBEQVNIIQjeUkZST00gQkFSIQbWUlRPIEJBUiAFvUNXQVJEUxwp4lJVUCBBQk9WRSBMRUZUV0FSRFMgSEFSUE9PTiBXSVRIIEJBUkIgRE9XTiYI6lJPTkcgREFTSCUf5lJSSUdIVFdBUkRTIEhBUlBPT04gV0lUSCBCQVJCIFVQHwjaUkZST00gQkFSHwbSUlRPIEJBUh4FvENXQVJEUwsKxPAHRUFWWSBBUlJPVxAQwPAHQ09NUFJFU1NFRCBBUlJPVwoXpPEHTEVGVC1TSEFERUQgV0hJVEUgQVJST1cKEf1DT1BFTi1IRUFERUQgQVJST1cKDcdDUEFJUkVEIEFSUk9XUwsL9/UHVVNISU5HIEhBTkQKD8VWUVVBRFJVUExFIEFSUk9XChim8QdSSUdIVC1TSEFERUQgV0hJVEUgQVJST1cLBezsB09DS0VUChDQ8AdTQU5TLVNFUklGIEFSUk9XCwy48AdRVUFSRUQgQVJST1cNC9xDSUdHTEUgQVJST1cKFqLxB1RPUCBTSEFERUQgV0hJVEUgQVJST1cLEZDxB1JJQU5HTEUgQVJST1dIRUFEEg3gVi1IRUFERUQgQVJST1cfJoBXIE9WRVIgUklHSFRXQVJEUyBUUklBTkdMRS1IRUFERUQgQVJST1cgBvBWVE8gQkFSIA+o8AdXSVRIIEJPTEQgU0hBRlQlGPpWRE9VQkxFIEhPUklaT05UQUwgU1RST0tFLA/6VlZFUlRJQ0FMIFNUUk9LRSULrPAHSEVBVlkgU0hBRlQlEqZXTE9ORyBUSVAgRE9XTldBUkRTLgekV1VQV0FSRFMlDKTwB01FRElVTSBTSEFGVCUMoPAHTkFSUk9XIFNIQUZUJRCw8AdWRVJZIEhFQVZZIFNIQUZUGgzqVkRBU0hFRCBBUlJPVxoNhFdQQUlSRUQgQVJST1dTDQnaQ1BMRSBBUlJPVxEKjlJEQVNIIEFSUk9XCw+eQ1dPIEhFQURFRCBBUlJPVw0WtlYtSEVBREVEIEFSUk9XIEZST00gQkFSGxu1VldJVEggRE9VQkxFIFZFUlRJQ0FMIFNUUk9LRSAEu1ZUQUlMJBy9ViBXSVRIIERPVUJMRSBWRVJUSUNBTCBTVFJPS0UqD7xWVkVSVElDQUwgU1RST0tFIRLsV1JJQU5HTEUgQVJST1dIRUFEUyAPtFZWRVJUSUNBTCBTVFJPS0UVEbdWVFJJUExFIERBU0ggQVJST1cKCpxDV0FWRSBBUlJPVwsK5kNISVRFIEFSUk9XFRqU8QcgV0lUSElOIFRSSUFOR0xFIEFSUk9XSEVBRAIBtfMHRwIDy+YHTU9OAgHMTE8DBIboB1BBUkQCFa04UENIQSBDT05TT05BTlQgU0lHTiBLFwO1OEFORxYBrzhMFgGuOE0WAbA4ThcGtDhZSU4tRE8WAbE4UBYBsjhSFgGzOFQHC8g4RElHSVQgRUlHSFQNBMU4RklWRQ4DxDhPVVINBMk4TklORQ0DwThPTkUNBcc4U0VWRU4OAsY4SVgNBcM4VEhSRUUOAsI4V08NBMA4WkVSTwcIozhMRVRURVIgQQ4CkzhCQQ8ClDhMQQ4ChjhDQQ8ChzhIQQ4CjDhEQQ8CzzhEQQ8CmThaQQ4CkThGQQ8CkjhMQQ4CgzhHQQ8ChDhMQQ4CnThIQQ8CnjhMQQ4CiDhKQQ4CgDhLQQ8CgjhIQQ8CgThMQQ4CnDhMQQ4ClThNQQ8CljhMQQ4CjThOQQ8ChThHQQ8CiThZQQ4CjjhQQQ8CkDhIQQ8CjzhMQQ4CmzhSQQ4CoDhTQQ8CoThIQQ4CijhUQQ8CizhIQQ8ClzhTQRACmDhIQQ8CzThUQRACzjhIQQ4CnzhWQQ4CojhXQQ4CmjhZQQcSvThQVU5DVFVBVElPTiBDRVItV0ETErw4TllFVCBUSFlPT00gVEEtUk9MEwa7OFRBLVJPTBQFvzhTSE9PSxkHvjggQ0VSLVdBBwq3OFNJR04gTlVLVEEMA7Y4UkFOCBKlOFVCSk9JTkVEIExFVFRFUiBSQRgCpDhZQQcNpjhWT1dFTCBTSUdOIEFBEgGsOEUSAac4SRIBqDhPEwGpOE8SAao4VRMBqzhVAjKLVVNTLVRIQU4gQUJPVkUgRE9VQkxFLUxJTkUgRVFVQUwgQUJPVkUgR1JFQVRFUi1USEFOECSRVUdSRUFURVItVEhBTiBBQk9WRSBET1VCTEUtTElORSBFUVVBTBAP9lJMRUZUV0FSRFMgQVJST1cQGo9VU0lNSUxBUiBBQk9WRSBHUkVBVEVSLVRIQU4YCI1VT1IgRVFVQUwRM5NVTEFOVEVEIEVRVUFMIEFCT1ZFIEdSRUFURVItVEhBTiBBQk9WRSBTTEFOVEVEIEVRVUFMCxKJVU5EIE5PVCBBUFBST1hJTUFURQ4Yh1VTSU5HTEUtTElORSBOT1QgRVFVQUwgVE8KEOhEQlVUIE5PVCBFUVVBTCBUTxUK5kVJVkFMRU5UIFRPCg+mVUNMT1NFRCBCWSBDVVJWRRkUqFUgQUJPVkUgU0xBTlRFRCBFUVVBTAoY2kVFUVVBTCBUTyBPUiBHUkVBVEVSLVRIQU4KDoVVT1IgQVBQUk9YSU1BVEUNCORERVFVQUwgVE8QCvJESVZBTEVOVCBUTw0M9kRHUkVBVEVSLVRIQU4NEP1UU0xBTlRFRCBFUVVBTCBUTx0PgVUgV0lUSCBET1QgQUJPVkUsBoNVIFJJR0hUJwb/VElOU0lERQsM5kRWRVIgRVFVQUwgVE8KBDxTSUdOChL5VFdJVEggQ0lSQ0xFIElOU0lERQ8D1kVET1QPE/tUUVVFU1RJT04gTUFSSyBBQk9WRQIH0J0HVUtPVEhFQQIKmucHVkVMIFNMSURFUgEBCkYBBM5MSUJSQQIX8uwHR0FUVVJFIE9QRU4gRVQgT1JOQU1FTlQDDfX0B0hUIEJMVUUgSEVBUlQGCvjrB0NIRUNLIE1BUksGFbvvB0VJR0hUIFNQT0tFRCBBU1RFUklTSwYXye8HRklWRSBQT0lOVEVEIEJMQUNLIFNUQVILD6/vB1NQT0tFRCBBU1RFUklTSwcWzFdPVVIgUE9JTlRFRCBCTEFDSyBDVVNQGQTE7wdTVEFSBgui7wdHUkVFSyBDUk9TUwYk8k5MRUZUIFRPUlRPSVNFIFNIRUxMIEJSQUNLRVQgT1JOQU1FTlQGBIjtB1JBSUwHJPNOSUdIVCBUT1JUT0lTRSBTSEVMTCBCUkFDS0VUIE9STkFNRU5UBgep7wdTQUxUSVJFBwSRS0hBREUHErXvB0lYIFNQT0tFRCBBU1RFUklTSwYYwO8HVEhSRUUgUE9JTlRFRCBCTEFDSyBTVEFSBxjS7wdXRUxWRSBQT0lOVEVEIEJMQUNLIFNUQVIGDNhOVkVSVElDQUwgQkFSBgyO7wdXSElURSBTUVVBUkUFBIdMTklORwkF8usHIE1PT0QOB/HrByBCVUJCTEUCD84yTUJVIERJR0lUIEVJR0hUDATLMkZJVkUNA8oyT1VSDATPMk5JTkUMA8cyT05FDAXNMlNFVkVODQLMMklYDAXJMlRIUkVFDQLIMldPDATGMlpFUk8GEMQyRVhDTEFNQVRJT04gTUFSSwYJkjJMRVRURVIgQkEOApMySEENAoYyQ0EOAocySEENAo0yREEOAo4ySEENAoMyR0EOAoQySEEOA50yWUFODQKcMkhBDQKIMkpBDgKJMkhBDQKBMktBDgKCMkhBDQKXMkxBDQKUMk1BDQKPMk5BDgKFMkdBDQKQMlBBDgKRMkhBDQKWMlJBDQKbMlNBDgKZMkhBDgKaMlNBDQKLMlRBDgKMMkhBDgKeMlJBDQKYMldBDQKVMllBDwGKMk4GDcUyUVVFU1RJT04gTUFSSwYOujJTSUdOIEtFTVBIUkVORwsDwDJMT08LCbkyTVVLUEhSRU5HCwS7MlNBLUkHFLIyTUFMTCBMRVRURVIgQU5VU1ZBUkETArAyS0ETArgyTEETArYyTUETArQyTkEUArEyR0ETArUyUEETArcyUkETArMyVEEHEqoyVUJKT0lORUQgTEVUVEVSIFJBFwKrMldBFwKpMllBBgygMlZPV0VMIFNJR04gQRIBpDJJEgGmMlURAacyRRIBozJFEQGhMkkRAagyTxIBpTJPEQGiMlULD4AyLUNBUlJJRVIgTEVUVEVSAxPPZUlURUQgTElBQklMSVRZIFNJR04CBwpORSBGRUVECQUKIChMRikFIpRUSU5URUdSQVRJT04gTk9UIElOQ0xVRElO", + "RyBUSEUgUE9MRREhklRXSVRIIFJFQ1RBTkdVTEFSIFBBVEggQVJPVU5EIFBPTEUWHZNUU0VNSUNJUkNVTEFSIFBBVEggQVJPVU5EIFBPTEUFCahAU0VQQVJBVE9SBQoLVEFCVUxBVElPTg8EigEgU0VUBA+bjARBUiBBIFNJR04gQTAyOEIPB8eMBDEwMC0xMDIQA8qMBDIwQhADz4wEMzFDDwPVjAQzMDERAdaMBDIRAdeMBDMRAdiMBDQRAdmMBDURAdqMBDYRAduMBDcRAdyMBDgRAt2MBDlBEgHejARCEgHfjARDEALgjAQxMBEB4YwEMREB4owEMhEC44wEM0ESAeSMBEISAeWMBEMRAeaMBDQRAeeMBDURAeiMBDYRAemMBDcRAeqMBDgRAeuMBDkQAuyMBDIwEQHtjAQxEQHujAQyEQHvjAQzEQHwjAQ0EQHxjAQ1EQHyjAQ2EQHzjAQ3EQH0jAQ4EQH1jAQ5EAL2jAQzMBEB94wEMREB+IwEMhEB+YwEMxEB+owENBEB+4wENREB/IwENhEB/YwENxEB/owEOBEB/4wEORACgI0ENDARAYGNBDERAYKNBDIRAYONBDMRAYSNBDQRAYWNBDURAYaNBDYRAYeNBDcRAYiNBDgRAYmNBDkQAoqNBDUwEQGLjQQxEQGMjQQyEQGNjQQzEQGOjQQ0EQGPjQQ1EQGQjQQ2EQGRjQQ3EQGSjQQ4EQGTjQQ5EAKUjQQ2MBEBlY0EMREBlo0EMhEBl40EMxEBmI0ENBEBmY0ENREBmo0ENhEBm40ENxEBnI0EOBEBnY0EORACno0ENzARAZ+NBDEPB6CNBDQwMC1WQVMRBaGNBDEtVkFTEQWijQQyLVZBUxEFo40EMy1WQVMRBaSNBDQtVkFTEQWljQQ1LVZBUxEFpo0ENi1WQVMRBaeNBDctVkFTEQWojQQ4LVZBUxEFqY0EOS1WQVMQBqqNBDEwLVZBUxEFq40EMS1WQVMRBayNBDItVkFTEQWtjQQzLVZBUxEFro0ENC1WQVMRBa+NBDUtVkFTEQWwjQQ2LVZBUxEFsY0ENy1WQVMRBbKNBDgtVkFTDwOzjQQ1MDERAbSNBDIRAbWNBDMRAbaNBDQRAbeNBDURAbiNBDYRAbmNBDgRAbqNBDkQAruNBDEwEQG8jQQxEQG9jQQyEQG+jQQzEQG/jQQ1EQHAjQQ2EALBjQQyMBEBwo0EMREBw40EMxEBxI0ENBEBxY0ENREBxo0ENhEBx40ENxEByI0EOBEByY0EORACyo0EMzARAcuNBDERAcyNBDIRAc2NBDQRAc6NBDURAc+NBDYRAdCNBDcRAdGNBDgRAdKNBDkQAtONBDQwEQHUjQQxEQHVjQQyEQHWjQQ1EQHXjQQ3EQHYjQQ4EQHZjQQ5EALajQQ1MBEB240EMREB3I0EMhEB3Y0EMxEB3o0ENBEB340ENREB4I0ENhEB4Y0ENxEB4o0EORAC440ENjMRAeSNBDQRAeWNBDURAeaNBDYRAeeNBDgRAeiNBDkQAumNBDcwEQHqjQQxEQHrjQQyEQHsjQQzEQHtjQQ0EQHujQQ1EQHvjQQ2EQHwjQQ3EQHxjQQ4EQHyjQQ5EALzjQQ4MBEB9I0EMREB9Y0EMhEB9o0EMxEB940ENBEB+I0ENREB+Y0ENhEB+o0ENxEB+40EOBEB/I0EORAC/Y0EOTERAf6NBDIRAf+NBDQRAYCOBDURAYGOBDYRAYKOBDgPA4OOBDYwMBEBhI4EMREBhY4EMhEBho4EMxEBh44ENBEBiI4ENhEBiY4EOBEBio4EORACi44EMTARAYyOBDERAY2OBDIRAY6OBDMRAY+OBDQRAZCOBDURAZGOBDYRAZKOBDcRAZOOBDgRAZSOBDkQApWOBDIwEQGWjgQxEQGXjgQyEQGYjgQzEQGZjgQ0EQGajgQ2EQGbjgQ3EQGcjgQ4EQGdjgQ5EAKejgQzNBEBn44ENxEBoI4EOBACoY4ENDARAaKOBDIRAaOOBDMRAaSOBDQRAaWOBDURAaaOBDYRAaeOBDgRAaiOBDkQAqmOBDUxEQGqjgQyEQGrjgQzEQGsjgQ0EQGtjgQ1EQGujgQ2EQGvjgQ3EQGwjgQ4EQGxjgQ5EAKyjgQ2MBEBs44EMREBtI4EMhEBtY4EMxEBto4ENA8FwI4ENzAxIEERA8GOBDIgQhEDwo4EMyBEEQPDjgQ0IEURA8SOBDUgRhEDxY4ENiBIEQPGjgQ3IEoRA8eOBDggSxEDyI4EOSBMEgXJjgQtMiBMMhMEyo4EMyBMMxMEy44ENCBMNBMEzI4ENiBMNhAEzY4EMTAgVxEDzo4EMSBYEQPPjgQyIFkRB9COBDMgT01FR0ERBdGOBDQgQUJCEQTSjgQ1IEJCEQTTjgQ3IEREEAfUjgQyNiBFWVlZEAXVjgQzMiBKRQ8D4I4EODAwEQHhjgQxEQHijgQyEQHjjgQzEQHkjgQ0EQHljgQ1EQHmjgQ2EQHnjgQ3DwSAjARCMDAxEgGBjAQyEgGCjAQzEgGDjAQ0EgGEjAQ1EgGFjAQ2EgGGjAQ3EgGHjAQ4EgGIjAQ5EQKJjAQxMBIBiowEMRIBi4wEMxIBjIwENhIBjYwENxECjowEMjASAY+MBDETAZCMBEYTAZGMBE0SAZKMBDITAZOMBEYTAZSMBE0SAZWMBDMTAZaMBE0SAZeMBDQSAZiMBDYSAZmMBDcSAZqMBDgSAZyMBDkRAp2MBDMwEgGejAQxEgGfjAQ0EgGgjAQ3EgGhjAQ4EgGijAQ5EQKjjAQ0MBIBpIwEMRIBpYwENBIBpowENRIBp4wENhIBqIwENxIBqYwEOBIBqowEORECq4wENTASAayMBDESAa2MBDMSAa6MBDQSAa+MBDUSAbCMBDYSAbGMBDcSAbKMBDgSAbOMBDkRArSMBDYwEgG1jAQxEgG2jAQ1EgG3jAQ2EgG4jAQ3EgG5jAQ5EQK6jAQ3MBIBu4wEMxIBvIwENBIBvYwENhIBvowENxIBv4wEOBIBwIwEORECwYwEODASAcKMBDESAcOMBDISAcSMBDUSAcWMBDYSAcaMBDcQA8iMBDExOBECyYwEMjASAcuMBDISAcyMBDMRA82MBDMxQRMBzowEQhEC0IwENjQRAtGMBDcxEQLSjAQ4MBIB04wEOBEC1IwEOTEHE4CBBEIgSURFT0dSQU0gQjEwMCBNQU4VB4GBBDIgV09NQU4VBoKBBDQgREVFUhUHg4EENSBFUVVJRBYGhIEERiBNQVJFFgqFgQRNIFNUQUxMSU9OFQaGgQQ2RiBFV0UWBYeBBE0gUkFNFQuIgQQ3RiBTSEUtR09BVBYJiYEETSBIRS1HT0FUFQaKgQQ4RiBTT1cWBouBBE0gQk9BUhUGjIEEOUYgQ09XFgaNgQRNIEJVTEwUCI6BBDIwIFdIRUFUFQiPgQQxIEJBUkxFWRUHkIEEMiBPTElWRRUHkYEEMyBTUElDRRUJkoEENSBDWVBFUlVTFAaVgQQzMCBPSUwVBpaBBDEgV0lORRUBl4EEMhQJmoEENDAgQlJPTlpFFQabgQQxIEdPTEQVAZyBBDIVBp2BBDUgV09PTBUBnoEENhQCn4EENTAVBqCBBDEgSE9SThUBoYEEMhUBooEEMxUBo4EENBUBpYEENxUBpoEEOBUHp4EEOSBDTE9USBQCqIEENjAVAamBBDEVCaqBBDIgR0FSTUVOVBUIq4EEMyBBUk1PVVIVAayBBDQVAa2BBDUVAa6BBDYVAa+BBDcVAbCBBDgVAbGBBDkUArKBBDcwFQGzgQQxFQG0gQQyFQe1gQQzIE1PTlRIFQG2gQQ0FQa3gQQ2IFRSRUUVAbiBBDcVAbmBBDgVAbqBBDkUAruBBDgwFQG8gQQxFQG9gQQyFQG+gQQzFQG/gQQ0FQHAgQQ1FQHBgQQ5FALCgQQ5MBUIw4EEMSBIRUxNRVQTDcSBBDIyMCBGT09UU1RPT0wVCcWBBDUgQkFUSFRVQhQIxoEEMzAgU1BFQVIVB8eBBDEgQVJST1cVAciBBDIVB8mBBDMgU1dPUkQVAcqBBDQVAcuBBDYUEsyBBDQwIFdIRUVMRUQgQ0hBUklPVBUJzYEEMSBDSEFSSU9UFQ/OgQQyIENIQVJJT1QgRlJBTUUVB8+BBDMgV0hFRUwVAdCBBDUVAdGBBDYVAdOBBDgVAdSBBDkUAtWBBDUxFQHWgQQyFQHXgQQzFQbYgQQ0IERBUlQVAdmBBDUVAdqBBDYVAduBBDcVAdyBBDgVAd2BBDkSC96BBFZFU1NFTCBCMTU1GgPfgQQyMDAcAeCBBDEcAeGBBDIcAeKBBDMcAeOBBDQcAeSBBDUcAeWBBDYcAeaBBDccAeeBBDgcAeiBBDkbAumBBDEwHAHqgQQxHAHrgQQyHAHsgQQzHAHtgQQ0HAHugQQ1HAHvgQQ2HAHwgQQ3HAHxgQQ4HAHygQQ5GwLzgQQyMRwB9IEEMhwB9YEENhwB9oEENxwB94EEOBwB+IEEORsC+YEENTAaA/qBBDMwNQkSk4EETU9OT0dSQU0gQjEyNyBLQVBPFQiUgQQ4IEtBTkFLTxQImIEEMzMgQVJFUEEVBpmBBDUgTUVSSRQIpIEENTYgVFVSTzITCdKBBDI0NyBESVBURQkQhYAEU1lMTEFCTEUgQjAwMSBEQRUEq4AEMiBSTxUEnoAEMyBQQRUEs4AENCBURRUEtYAENSBUTxUEmYAENiBOQRUEh4AENyBESRUDgIAEOCBBFQSugAQ5IFNFFASEgAQxMCBVFQShgAQxIFBPFQSwgAQyIFNPFQSVgAQzIE1FFQSIgAQ0IERPFQSXgAQ1IE1PFQSjgAQ2IFFBFQS8gAQ3IFpBFAW/gAQyMCBaTxUEpYAEMSBRSRUEmIAEMyBNVRUEmoAENCBORRUEwIAENSBBMhUErIAENiBSVRUEqYAENyBSRRUDgoAEOCBJFQXGgAQ5IFBVMhQFm4AEMzAgTkkVBK2ABDEgU0EVBKaABDIgUU8VBcmABDMgUkEzFQSNgAQ2IEpPFQS0gAQ3IFRJFQOBgAQ4IEUVBKCABDkgUEkUBbmABDQwIFdJFQSvgAQxIFNJFQS6gAQyIFdPFQTBgAQzIEEzFQSQgAQ0IEtFFQSGgAQ1IERFFQSLgAQ2IEpFFQXFgAQ4IE5XQRQFooAENTAgUFUVBImABDEgRFUVBJyABDIgTk8VBKqABDMgUkkVBLeABDQgV0EVBJ2ABDUgTlUVBIqABDcgSkEVBLGABDggU1UVBLKABDkgVEEUBaiABDYwIFJBFQODgAQxIE8VBceABDIgUFRFFQSOgAQ1IEpVFQXLgAQ2IFRBMhUEkYAENyBLSRUFyoAEOCBSTzIVBLaABDkgVFUUBZKABDcwIEtPFQXDgAQxIERXRRUEn4AEMiBQRRUEloAEMyBNSRUEvYAENCBaRRUEuIAENSBXRRUFyIAENiBSQTIVBI+ABDcgS0EVBKSABDggUUUUBZSABDgwIE1BFQSTgAQxIEtVFQTCgAQ1IEFVFQXMgAQ3IFRXRRQGxIAEOTAgRFdPFQXNgAQxIFRXTwsJ0IAETUJPTCBCMDE4EwHRgAQ5EgLSgAQyMhIC04AEMzQSAtSABDQ3EwHVgAQ5EgLWgAQ1NhIC14AENjMTAdiABDQSAtmABDc5EgLagAQ4MhMB24AEMxMB3IAENhMB3YAEOQMIl+oHSyBTWU1CT0wEDYfrB0VEIFBBUEVSQ0xJUFMCB4HzB09OIEZBQ0UCAuLrB1BTBASE6QdUSUNLAgekQVJBIFNJR04CC+7JAlNVIExFVFRFUiBBDQHvyQJFDALQyQJCQQwC2skCQ0ENAtvJAkhBDALTyQJEQQ0C3MkCWkEMAfDJAkUNAfHJAlUMAunJAkZBDALWyQJHQQ0C7ckCSEEMAubJAkhBDQLoyQJIQQwB8skCSQwC2ckCSkEMAtfJAktBDQLYyQJIQQwC4ckCTEEMAt/JAk1BDALgyQJOQQ0C5ckCR0EMAfPJAk8NAffJAkUMAtHJAlBBDQLSyQJIQQwC4skCU0ENAuvJAkhBDALUyQJUQQ0C1ckCSEENCvvJAk9ORSBNWUEgQk8VA/rJAkNZQRUD/ckCSkVVFQL8yQJOQRUC+MkCVEkRBfnJAk5BIFBPDQLdyQJTQQ4C3skCSEEMAfTJAlUNAfXJAkUNAfbJAkgMAurJAldBDALnyQJYQQwC7MkCWUENArC/BEhBDALkyQJaQQ0C48kCSEEFEf7JAlBVTkNUVUFUSU9OIENPTU1BEQn/yQJGVUxMIFNUT1ACEbZBVlJFIFRPVVJOT0lTIFNJR04CBI7zB1pBUkQBBJnzB0xBTUEBBp7zB09CU1RFUgICkuoHQ0sEDY/qByBXSVRIIElOSyBQRU4EDQ5JTkctU0hJRlQgT05FDgQPWkVSTwIMlpgHR0lDIEdBVEUgQU5ECwaZmAdCVUZGRVIRFJqYByBXSVRIIElOVkVSVEVEIElOUFVUCw+XmAdJTlZFUlRFRCBJTlBVVFMUBpiYB09VVFBVVAsClZgHT1IFBqdEQUwgQU5ECw/RVCBXSVRIIERPVCBBQk9WRRMM3lRVQkxFIE9WRVJCQVIYCOBUVU5ERVJCQVIRD9xUSE9SSVpPTlRBTCBEQVNIEQvaVE1JRERMRSBTVEVNEQjfVFVOREVSQkFSCAKoRE9SChjZVCBPVkVSTEFQUElORyBMT0dJQ0FMIEFORAsO0lRXSVRIIERPVCBBQk9WRRIM4lRVQkxFIE9WRVJCQVIXCONUVU5ERVJCQVIQD91USE9SSVpPTlRBTCBEQVNIEAvbVE1JRERMRSBTVEVNAgbt5gdMTElQT1ACK+ZVTkcgREFTSCBGUk9NIExFRlQgTUVNQkVSIE9GIERPVUJMRSBWRVJUSUNBTAYHzE9JVklTSU9OBgOY9QdSVU0FEPdPTEVGVCBSSUdIVCBBUlJPVxUU2PEHIFdJVEggREVQRU5ERU5UIExPQkUQDPpPRE9VQkxFIEFSUk9XCgTeT1RBQ0sJC/VPV0FSRFMgQVJST1cUCftPIEZST00gQkFSDwz4T0RPVUJMRSBBUlJPVxsJ/U8gRlJPTSBCQVIPJtTxB0hBUlBPT04gQUJPVkUgU0hPUlQgUklHSFRXQVJEUyBIQVJQT09ODw6zVlNRVUlHR0xFIEFSUk9XBQrdT1JJR0hUIFRBQ0sKC/ZPV0FSRFMgQVJST1cVCfxPIEZST00gQkFSFhnQ8QdPVkVSIExPTkcgTEVGVFdBUkRTIEFSUk9XFgnW8QdUSFJPVUdIIFgWEdfxB1dJVEggRE9VQkxFIFNMQVNIEAz5T0RPVUJMRSBBUlJPVxwJ/k8gRlJPTSBCQVIQJdLxB0hBUlBPT04gQUJPVkUgU0hPUlQgTEVGVFdBUkRTIEhBUlBPT04YG9HxB09WRVIgTE9ORyBMRUZUV0FSRFMgSEFSUE9PThAO/09TUVVJR0dMRSBBUlJPVwIM9O4HVCBPRiBGT1JUVU5FAwr08wdJT04gQk9UVExFAwK39QdVUwIQrewHVURMWSBDUllJTkcgRkFDRQII6ecHVkUgSE9URUwFBozpB0xFVFRFUgIKzkBXIEFTVEVSSVNLBAer9QdCQVRURVJZBRCF6gdSSUdIVE5FU1MgU1lNQk9MBBufYERPVUJMRSBQUklNRSBRVU9UQVRJT04gTUFSSwQGx1xLQVZZS0EKCchcIFdJVEggRE9UBARfTElORQMRg05FUiBCTEFERSBTQ0lTU09SUwYfnZ0HQ0VOVFJFIExFRlQgT05FIFNJWFRFRU5USCBCTE9DSxIOvZgHVFdFTEZUSCBDSVJDTEUNEeX3B09ORSBRVUFSVEVSIEJMT0NLDRmenQdSSUdIVCBPTkUgU0lYVEVFTlRIIEJMT0NLEw6+mAdUV0VMRlRIIENJUkNMRQYShUtGSVZFIEVJR0hUSFMgQkxPQ0sGIIGcB0hBTEYgQU5EIFVQ", + "UEVSIEhBTEYgV0hJVEUgQ0lSQ0xFCwWES0JMT0NLCwbhS0NJUkNMRQsShJwHSEVBVlkgV0hJVEUgU1FVQVJFCxTbS0lOVkVSU0UgV0hJVEUgQ0lSQ0xFCxaknQdMRUZUIE9ORSBRVUFSVEVSIEJMT0NLCwyP9wdNRURJVU0gU0hBREULF6+dB1JJR0hUIE9ORSBRVUFSVEVSIEJMT0NLCyOTnAdWRVJUSUNBTCBMSU5FIFdJVEggVEhSRUUgVElDSyBNQVJLUwcXhZgHT1JJWk9OVEFMIFJVTEVSIFNFR01FTlQGEorrB0xFRlQgQkFMTFBPSU5UIFBFTgwvvPYHTE9DSyBESUFHT05BTCBMT1dFUiBNSURETEUgTEVGVCBUTyBMT1dFUiBDRU5UUkU1Bb32B1JJR0hUGiLO9gdVUFBFUiBDRU5UUkUgVE8gTE9XRVIgTUlERExFIFJJR0hUMAXQ9gdSSUdIVCoSzPYHVVBQRVIgTUlERExFIFJJR0hUIBTA9gdMRUZUIFRPIExPV0VSIENFTlRSRS4Mz/YHTUlERExFIFJJR0hUKBLN9gdVUFBFUiBNSURETEUgUklHSFQgG772B01JRERMRSBMRUZUIFRPIExPV0VSIENFTlRSRTUM0fYHTUlERExFIFJJR0hUNQW/9gdSSUdIVAsGjesHQ1JBWU9OCwyL6wdGT1VOVEFJTiBQRU4LE5ydB09ORSBTSVhURUVOVEggQkxPQ0sLCozrB1BBSU5UQlJVU0gMBYnrB0VOQ0lMCxXImQdRVUFEUkFOVCBDSEVTUyBCSVNIT1AaBLyZB0tJTkcbBcyZB05JR0hUGgTQmQdQQVdOGgXAmQdRVUVFThoExJkHUk9PSxUL30tJUkNVTEFSIEFSQxQUrpkHRkFDRSBXSVRIIE9QRU4gTU9VVEgVDLCZB1JPV05JTkcgRkFDRRQNuJkHTUlDUk9DT01QVVRFUhQMrJkHTkVVVFJBTCBGQUNFFAyqmQdTTUlMSU5HIEZBQ0UVDtSZB1RBTkRJTkcgS05JR0hUFAq0mQdURUxFVklTSU9ODgu5mAdSVEVSIENJUkNMRQsgv1JTRU1JQ0lSQ1VMQVIgQU5USUNMT0NLV0lTRSBBUlJPVwsI+ktUUklBTkdMRRERn/cHVUxBUiBNRURJVU0gU0hBREUMDbyYB1dFTEZUSCBDSVJDTEUGJpmdB01JRERMRSBDRU5UUkUgTEVGVCBPTkUgU0lYVEVFTlRIIEJMT0NLFBmanQdSSUdIVCBPTkUgU0lYVEVFTlRIIEJMT0NLDRiYnQdMRUZUIE9ORSBTSVhURUVOVEggQkxPQ0sSDriYB1RXRUxGVEggQ0lSQ0xFDRmbnQdSSUdIVCBPTkUgU0lYVEVFTlRIIEJMT0NLEw67mAdUV0VMRlRIIENJUkNMRQYQgUtPTkUgRUlHSFRIIEJMT0NLCg2CS1FVQVJURVIgQkxPQ0sGN8f2B1JJR0hUIEJMT0NLIERJQUdPTkFMIExPV0VSIENFTlRSRSBUTyBMT1dFUiBNSURETEUgUklHSFQrEsn2B1VQUEVSIE1JRERMRSBSSUdIVDEFy/YHUklHSFQhGsj2B0xFRlQgVE8gTE9XRVIgTUlERExFIFJJR0hUKQzF9gdVUFBFUiBDRU5UUkUvDMr2B01JRERMRSBSSUdIVCEbw/YHTUlERExFIExFRlQgVE8gVVBQRVIgQ0VOVFJFNgzG9gdNSURETEUgUklHSFQ2BcT2B1JJR0hUGyHB9gdVUFBFUiBNSURETEUgTEVGVCBUTyBVUFBFUiBDRU5UUkU2BcL2B1JJR0hUDA/TT0NPUk5FUiBXSVRIIERPVAwaz05EUk9QLVNIQURPV0VEIFdISVRFIFNRVUFSRQwTn50HT05FIFNJWFRFRU5USCBCTE9DSwwGjk5QRU5DSUwMFcmZB1FVQURSQU5UIENIRVNTIEJJU0hPUBsEvZkHS0lORxwFzZkHTklHSFQbBNGZB1BBV04bBcGZB1FVRUVOGwTFmQdST09LFgveS0lSQ1VMQVIgQVJDFRSvmQdGQUNFIFdJVEggT1BFTiBNT1VUSBYMsZkHUk9XTklORyBGQUNFFQ25mQdNSUNST0NPTVBVVEVSFQytmQdORVVUUkFMIEZBQ0UVDKuZB1NNSUxJTkcgRkFDRRYO1ZkHVEFORElORyBLTklHSFQVCrWZB1RFTEVWSVNJT04PC7qYB1JURVIgQ0lSQ0xFDA2HmAdSVUxFUiBTRUdNRU5UDBy+UlNFTUlDSVJDVUxBUiBDTE9DS1dJU0UgQVJST1cNFL7qB0hBRE9XRUQgV0hJVEUgQ0lSQ0xFGwbRTlNRVUFSRQwI/0tUUklBTkdMRRIRnvcHVUxBUiBN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BVpFUk8MDprdBUVYQ0xBTUFUSU9OIE9IDAmY3QVGVUxMIFNUT1AMD5LdBU5VTUJFUiBFSUdIVEVFThQFi90FTEVWRU4TB4/dBUZJRlRFRU4UB47dBU9VUlRFRU4TCJPdBU5JTkVURUVOEwmR3QVTRVZFTlRFRU4UBpDdBUlYVEVFThMDit0FVEVOFAeN3QVISVJURUVOFAWM3QVXRUxWRQwO7dwFU01BTEwgTEVUVEVSIEEaAf7cBUkaA+TcBVRJVRkB8NwFQhkB8dwFQxkB+dwFRBkB79wFRRkB6twFRhkB6dwFRxkB9twFSBoB9twFUBkB69wFSRkB7twFShkB7NwFSxoB5twFUBkB9NwFTBkB4NwFTRkB+9wFThoB99wFRxoB99wFWRkB/dwFTxoB+twFRRkB59wFUBkB9dwFURkB/NwFUhkB4dwFUxkB6NwFVBkB8twFVRkB4twFVhkB49wFVxkB+NwFWBkB/9wFWRoB89wFVRkB5dwFWg0Kmd0FWU1CT0wgQUlWQQMLzFxJRVZBTCBDT01NQQkQ01xFWENMQU1BVElPTiBNQVJLCQ3UXFFVRVNUSU9OIE1BUksED6tNVU0gQkxBQ0sgQ0lSQ0xFCBCF7wdPTEQgV0hJVEUgQ0lSQ0xFBxjO7wdFSUdIVCBQT0lOVEVEIEJMQUNLIFNUQVIND7zvB1NQT0tFRCBBU1RFUklTSwcUsO8HRklWRSBTUE9LRUQgQVNURVJJU0sIIupOTEFUVEVORUQgTEVGVCBQQVJFTlRIRVNJUyBPUk5BTUVOVBEa605SSUdIVCBQQVJFTlRIRVNJUyBPUk5BTUVOVAgWxe8HT1VSIFBPSU5URUQgQkxBQ0sgU1RBUhQNx+8HUElOV0hFRUwgU1RBUgcLo+8HR1JFRUsgQ1JPU1MHG/ROTEVGVCBDVVJMWSBCUkFDS0VUIE9STkFNRU5UDBToTlBBUkVOVEhFU0lTIE9STkFNRU5UCyDsTi1QT0lOVElORyBBTkdMRSBCUkFDS0VUIE9STkFNRU5UBxLfQE1BVEhFTUFUSUNBTCBTUEFDRQcc9U5SSUdIVCBDVVJMWSBCUkFDS0VUIE9STkFNRU5UDRTpTlBBUkVOVEhFU0lTIE9STkFNRU5UDCDtTi1QT0lOVElORyBBTkdMRSBCUkFDS0VUIE9STkFNRU5UBweq7wdT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SUNLEQ3CBUVGVCBBUlJPV0hFQUQVCb8FSEFMRiBSSU5HFQTq1gJUQUNLEQ/PBU9XIEFDVVRFIEFDQ0VOVBQRiM8CQ0lSQ1VNRkxFWCBBQ0NFTlQUGZDOAkRPVFRFRCBMRUZULVNURU0gVE9ORSBCQVIbCIvOAlRPTkUgQkFSFgzvBVdOIEFSUk9XSEVBRBQMzgVHUkFWRSBBQ0NFTlQUGZ/OAklOVkVSVEVEIEVYQ0xBTUFUSU9OIE1BUksUCv8FTEVGVCBBUlJPVx4E8QVIRUFEGA6VzgItU1RFTSBUT05FIEJBUhQGzQVNQUNST04UD/IFUklHSFQgQVJST1dIRUFEFgLzBU5HFAX3BVRJTERFFQfoBU9ORSBCQVIUDPAFVVAgQVJST1dIRUFEFA3MBVZFUlRJQ0FMIExJTkUTFZrOAkVSIFJJR0hUIENPUk5FUiBBTkdMRRAGyQVNQUNST04RHI/OAklEIERPVFRFRCBMRUZULVNURU0gVE9ORSBCQVIbCIrOAlRPTkUgQkFSFBKUzgJMRUZULVNURU0gVE9ORSBCQVIUCOcFVE9ORSBCQVITF/YFRExFIERPVUJMRSBBQ1VURSBBQ0NFTlQeDPUFR1JBVkUgQUNDRU5UFwz0BUdSQVZFIEFDQ0VOVBII1wVOVVMgU0lHThAK/gVPUEVOIFNIRUxGEAnWBVBMVVMgU0lHThEEuQVSSU1FEAz4BVJBSVNFRCBDT0xPThcKnM4CRE9XTiBBUlJPVxcQnc4CRVhDTEFNQVRJT04gTUFSSxcZns4CSU5WRVJURUQgRVhDTEFNQVRJT04gTUFSSxcIm84CVVAgQVJST1cRIrmPBEVUUk9GTEVYIENMSUNLIFdJVEggUkVUUk9GTEVYIEhPT0sSDL0FVkVSU0VEIENPTU1BGQzBBUdMT1RUQUwgU1RPUCUMtI8EIFdJVEggU1RST0tFEQreBUhPVElDIEhPT0sRDsMFSUdIVCBBUlJPV0hFQUQWCb4FSEFMRiBSSU5HFgTr1gJUQUNLEAX9BVNIRUxGEg+KzwJPUlQgRVFVQUxTIFNJR04RBsM6TUFMTCBBFwGDjwRFFwLcOklOFwTFOkxQSEEWAcc6QhcKhY8EIFdJVEggSE9PSxcHsTtBUlJFRCBPFwPdOkVUQRcM1TpPVFRPTSBIQUxGIE8WAZw7QxcKnTsgV0lUSCBDVVJMFwmAjwRBUElUQUwgQUEeAYSPBEIeAZKPBEcfCpSPBCBXSVRIIEhPT0seAZaPBEgeAaY7SR8MpzsgV0lUSCBTVFJPS0UfCbYFTlZFUlRFRCBSHgGrO0wfCpyPBCBXSVRIIEJFTFQeAbA7Th4Co48ET0UeAaqPBFIeAbg7VR4Bso8EWRcC4TpISRcLpI8ETE9TRUQgT01FR0EdD4+PBFJFVkVSU0VEIE9QRU4gRRYByDpEFwqMjwQgV0lUSCBIT09LIQmNjwQgQU5EIFRBSUwdBIuPBFRBSUwXBN86RUxUQRgKio8EWkggRElHUkFQSBcUoTtPVExFU1MgSiBXSVRIIFNUUk9LRSsJmI8EIEFORCBIT09LFwmHjwRaIERJR1JBUEggComPBCBXSVRIIENVUkwmDoiPBFJFVFJPRkxFWCBIT09LFgHJOkUXAtE6TkcXArQ7U0gXAp47VEgXAr47WkgWAaA7RhcLkI8ERU5HIERJR1JBUEgWAc06RxcKk48EIFdJVEggSE9PSxcE4AVBTU1BFwreOlJFRUsgR0FNTUEcA+A6UEhJFgGwBUgXCrEFIFdJVEggSE9PSx0GlY8EU1RST0tFFwPc1gJFTkcaCpePBCBXSVRIIEhPT0sWDaQ7SSBXSVRIIFNUUk9LRRcDpTtPVEEWAbIFShcSqDsgV0lUSCBDUk9TU0VELVRBSUwWAc86SxYB4QVMFwqbjwQgV0lUSCBCRUxUHQ/d1gJJTlZFUlRFRCBMQVpZIFMdDN7WAk1JRERMRSBUSUxERR0MqjtQQUxBVEFMIEhPT0sdDqk7UkVUUk9GTEVYIEhPT0srCZ2PBCBBTkQgQkVMVBcDno8ERVpIGhSfjwQgV0lUSCBSRVRST0ZMRVggSE9PSxcK+c8CSUdBVFVSRSBPRRcJmY8EUyBESUdSQVBIFwmajwRaIERJR1JBUEgWAdA6TRcKrDsgV0lUSCBIT09LFhCuO04gV0lUSCBMRUZUIEhPT0sdDq87UkVUUk9GTEVYIEhPT0sWAdI6TxcMoo8EIFdJVEggU1RST0tFFwXLOlBFTiBFGwHTOk8WAdY6UBcCsjtISRYBpY8EURYBswVSFw6pjwQgV0lUSCBGSVNISE9PSx0EqI8EVEFJTBcIkY8EQU1TIEhPUk4XCY6PBEVWRVJTRUQgRR8M5AVHTE9UVEFMIFNUT1AfBp87T1BFTiBFFgHiBVMXCrqPBCBXSVRIIENVUkwdBLM7SE9PSxcEyjpDSFdBGAaiO1JJUFQgRxcJ2TpJREVXQVlTIFUWAdc6VBcStTsgV0lUSCBQQUxBVEFMIEhPT0sdDq+PBFJFVFJPRkxFWCBIT09LFxOrjwRDIERJR1JBUEggV0lUSCBDVVJMFwuujwRFU0ggRElHUkFQSBcEvztIRVRBFwnUOk9QIEhBTEYgTxcJrI8EUyBESUdSQVBIIBStjwQgV0lUSCBSRVRST0ZMRVggSE9PSxcHxDpVUk5FRCBBHgHGOkUeBJs7TFBIQR0BoztIHQHOOkkdAdo6TR4OrTsgV0lUSCBMT05HIExFRx0GzDpPUEVOIEUdAbQFUh4KtQUgV0lUSCBIT09LJAimjwRMT05HIExFRywTp48EIEFORCBSRVRST0ZMRVggSE9PSx0BujtWHQHp1gJXHQGgjwRZHgqhjwQgV0lUSCBCRUxUFgHYOlUXBLY7IEJBUhgO39YCV0lUSCBMRUZUIEhPT0sXBrc7UFNJTE9OFgHbOlYXCrk7IFdJVEggSE9PSx0KsI8EUklHSFQgSE9PSxYBtwVXFgHjBVgWAbgFWRYBuztaFwq9OyBXSVRIIENVUkwdDrw7UkVUUk9GTEVYIEhPT0sRE6DOAlRSRVNTIEFORCBISUdIIFRPTkUbCKHOAkxPVyBUT05FESCCjwRVUEVSU0NSSVBUIEhBTEYgVFJJQU5HVUxBUiBDT0xPThwQgY8EVFJJQU5HVUxBUiBDT0xPThAQ0AVUUklBTkdVTEFSIENPTE9OEQu7BVVSTkVEIENPTU1BEAvtBVVOQVNQSVJBVEVEEQvEBVAgQVJST1dIRUFEEwTUBVRBQ0sRAfDOAlMQDcgFVkVSVElDQUwgTElORREG7AVPSUNJTkcQGOsFWUFORyBERVBBUlRJTkcgVE9ORSBNQVJLERbqBUlOIERFUEFSVElORyBUT05FIE1BUksDC4pUVUxPIFRXTyBTVU0CB7DpB05FWSBCQUcGCrjpB1dJVEggV0lOR1MFC5HyBy1NT1VUSCBGQUNFAwyAMEdPTElBTiBCSVJHQQ8V5KwEIFdJVEggRE9VQkxFIE9STkFNRU5UFQjgrARPUk5BTUVOVAoFhDBDT0xPTgwDgjBNTUEKC5gwRElHSVQg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IE5PVEUQBOqjB09ST04PEIaiB0xFRlQgUkVQRUFUIFNJR04QBLejB09OR0EUEMKjByBJTVBFUkZFQ1RBIFJFU1QVDcGjB1BFUkZFQ1RBIFJFU1QPBrajB01BWElNQRAEkKMHRVpaTxAFu6MHSU5JTUEVBryjByBCTEFDSxYExaMHUkVTVBAS06IHT09OIE5PVEVIRUFEIEJMQUNLHQXSogdXSElURRAJuqIHVUxUSSBSRVNUFBCpogdQTEUgTUVBU1VSRSBSRVNUDwyvogdOQVRVUkFMIERPV04XAq6iB1VQEAqnowdFQkVOU1RJTU1FEA3YogdPVEVIRUFEIEJMQUNLEAzZogdVTEwgTk9URUhFQUQPHuSiB09ORSBIVU5EUkVEIFRXRU5UWS1FSUdIVEggTk9URSkEwqIHUkVTVBILlqIHLUxJTkUgU1RBRkYQEJujB1JOQU1FTlQgU1RST0tFLTEgAaSjBzAgAaWjBzEfAZyjBzIfAZ2jBzMfAZ6jBzQfAZ+jBzUfAaCjBzYfAaGjBzcfAaKjBzgfAaOjBzkQCraiB1RUQVZBIEFMVEEWBbeiB0JBU1NBDxTWogdQQVJFTlRIRVNJUyBOT1RFSEVBRBAJrqMHRURBTCBNQVJLFQevowdVUCBNQVJLEQzdowdTIFNVQlBVTkNUSVMQBI+jB0lBTk8QDMSiB0xVUyBOT1RFSEVBRBAG1KMHT0RBVFVTEQfZowdSUkVDVFVTGAfaowcgRkxFWFVTDwzfogdRVUFSVEVSIE5PVEUXBL2iB1JFU1QXCbOiB1RPTkUgRkxBVBwFsqIHU0hBUlARD7iiB0lORElDRVNJTUEgQUxUQRwFuaIHQkFTU0EPC4iiB1JFUEVBVCBET1RTFQuNogdFRCBGSUdVUkUtMR8BjqIHMh8Bj6IHMxETg6IHVkVSU0UgRklOQUwgQkFSTElORRAQh6IHSUdIVCBSRVBFQVQgU0lHThEJjKMHTkZPUlpBTkRPDwnWowdTQ0FORElDVVMYB9ujByBGTEVYVVMQBIuiB0VHTk8RDrqjB01JQlJFVklTIEJMQUNLGgTEowdSRVNUGgW5owdXSElURRMMvqMHTUlOSU1BIEJMQUNLGgTGowdSRVNUGgW9owdXSElURRAJsaIHSEFSUCBET1dOFQKwogdVUBELhaIHT1JUIEJBUkxJTkUQDYCiB0lOR0xFIEJBUkxJTkURDJuiB1gtTElORSBTVEFGRhMQnKIHU1RSSU5HIEZSRVRCT0FSRBIL4aIHVEVFTlRIIE5PVEUZBL+iB1JFU1QTDeOiB1ktRk9VUlRIIE5PVEUcBMGiB1JFU1QQA+mjB09SSRAH0qMHUVVBUkUgQhYOx6IHTk9URUhFQUQgQkxBQ0sfBcaiB1dISVRFEAWNowdVQklUTw8sy6MHVEVNUFVTIElNUEVSRkVDVFVNIENVTSBQUk9MQVRJT05FIElNUEVSRkVDVEE7DcyjByBESU1JTlVUSU9OLTFHAc2jBzJHAc6jBzMxCMqjB1BFUkZFQ1RBFiPIowdQRVJGRUNUVU0gQ1VNIFBST0xBVElPTkUgSU1QRVJGRUNUQS8Ix6MHUEVSRkVDVEE3DcmjByBESU1JTlVUSU9OLTEQEeKiB0hJUlRZLVNFQ09ORCBOT1RFHQTAogdSRVNUEQ6YogdSRUUtTElORSBTVEFGRhAH2KMHT1JDVUxVUxcK3KMHIFJFU1VQSU5VUxABlqMHUhEaz6IHSUFOR0xFIE5PVEVIRUFEIERPV04gQkxBQ0smBc6iB1dISVRFIQrLogdMRUZUIEJMQUNLJgXKogdXSElURSELzaIHUklHSFQgQkxBQ0snBcyiB1dISVRFIQjJogdVUCBCTEFDSyQL0aIHUklHSFQgQkxBQ0sqBdCiB1dISVRFJAXIogdXSElURRca1aIHLVJPVU5EIE5PVEVIRUFEIERPV04gQkxBQ0ssBdSiB1dISVRFEAOXowdVUk4TBpmjByBTTEFTSBQCmqMHVVAQDZeiB1dPLUxJTkUgU1RBRkYPBdOjB1ZJUkdBEAzXogdPSUQgTk9URUhFQUQPCt2iB1dIT0xFIE5PVEUVBLuiB1JFU1QQD7OjB0lUSCBGSU5HRVJOQUlMUw8Kw6IHWCBOT1RFSEVBRA8BjqMHWgECjjBWUwEBlQFXAR++IFlBTk1BUiBDT05TT05BTlQgU0lHTiBNRURJQUwgSEEeArwgUkEeAr0gV0EeArsgWUEYDOAgT04gTUVESUFMIExBIgLfIE1BIgLeIE5BFw6CIVNIQU4gTUVESUFMIFdBCAvIIERJR0lUIEVJR0hUDgTFIEZJVkUPA8QgT1VSDgTJIE5JTkUOA8EgT05FDgXHIFNFVkVODwLGIElYDgXDIFRIUkVFDwLCIFdPDgTAIFpFUk8IHeKtBEVBU1RFUk4gUFdPIEtBUkVOIERJR0lUIEVJR0hUIATfrQRGSVZFIQPerQRPVVIgBOOtBE5JTkUgA9utBE9ORSAF4a0EU0VWRU4hAuCtBElYIAXdrQRUSFJFRSEC3K0EV08gBNqtBFpFUk8ICKEgTEVUVEVSIEEQB/rUAklUT04gUkEQAaogVQ8ClyBCQRACmCBIQQ8ChSBDQRAChiBIQQ8CkiBEQRACjSBEQRECjiBIQRACkyBIQQ8BpyBFEBXwIEFTVEVSTiBQV08gS0FSRU4gR0hXQSED7iBOTkEhA+8gWVdBDwKCIEdBEAKDIEhBEAe/IFJFQVQgU0EPAp8gSEEPAaMgSRABpCBJDwKHIEpBEAKIIEhBDwKAIEtBEAKBIEhBEgbh1AJNVEkgQ0EXAuLUAkhBFgPo1AJEREEYAunUAkhBFwLq1AJIQRYC79QCRkEWAuDUAkdBFgLt1AJIQRcC7tQCSEEWAuPUAkpBFwLk1AJIQRYD7tQCTExBFgLr1AJOQRcC5dQCWUEWAvPUAlJBFgLs1AJTQRYD5tQCVFRBGALn1AJIQRYC8dQCWEEWAvLUAlpBDwKcIExBEAKgIExBDwKZIE1BEAbcIE9OIEJCQRUB3SBFEwGoIEUTA9sgSkhBEwPaIE5HQQ8ClCBOQRAChCBHQRACjyBOQRECiiBZQRACiSBZQQ8BqSBPDwKVIFBBEAKWIEhBDwKbIFJBEA+OIVVNQUkgUEFMQVVORyBGQQ8CniBTQRAN4SBHQVcgS0FSRU4gU0hBEALQIEhBEgOiIE4gQRQC/yBCQRUC5NMCSEEUAvggQ0EVAuHTAkhBFAL7IERBFAL+IEZBFAL3IEdBFQLg0wJIQRQCgSFIQRQD4tMCSkhBFAL1IEtBFQL2IEhBFAL8IE5BFQLj0wJOQRUC+iBZQRQD/SBQSEEUA4AhVEhBFAL5IFpBEQ7+1AJXRSBQQUxBVU5HIENIQRwD/9QCU0hBEALRIFNBDwKQIFRBEQr90wJJIExBSU5HIEJBGgL+0wJIQRkC+9MCREEaAu3TAkRBGwLu0wJIQRoC/NMCSEEZAujTAkZBGQLp0wJHQRoC6tMCSEEZAuvTAkpBGgLs0wJIQRkD+tMCTExBGQPv0wJOTkEaAufTAllBEAKRIEhBEAKLIFRBEQKMIEhBDwGlIFUQAaYgVQ8J1CBWT0NBTElDIEwYAdUgTBcB0iBSGAHTIFIPAp0gV0EQFOYgRVNURVJOIFBXTyBLQVJFTiBQV0EhA+UgVEhBDwKaIFlBCRH21AJPR09HUkFNIEtIQU1USSBITRgD9NQCT0FZGAL11AJRTggk8NQCTU9ESUZJRVIgTEVUVEVSIEtIQU1USSBSRURVUExJQ0FUSU9OGBLm0wJTSEFOIFJFRFVQTElDQVRJT04ID9itBFBBTyBESUdJVCBFSUdIVBIE1a0ERklWRRMD1K0ET1VSEgTZrQROSU5FEgPRrQRPTkUSBdetBFNFVkVOEwLWrQRJWBIF060EVEhSRUUTAtKtBFdPEgTQrQRaRVJPCBCYIVNIQU4gRElHSVQgRUlHSFQTBJUhRklWRRQDlCFPVVITBJkhTklORRMDkSFPTkUTBZchU0VWRU4UApYhSVgTBZMhVEhSRUUUApIhV08TBJAhWkVSTwkMtiBJR04gQU5VU1ZBUkEOA7ogU0FUDQm3IERPVCBCRUxPVw0NmiFLSEFNVEkgVE9ORS0xGQGbITMNDsogTElUVExFIFNFQ1RJT04NDvvUAlBBTyBLQVJFTiBUT05FDRSPIVJVTUFJIFBBTEFVTkcgVE9ORS01DQfLIFNFQ1RJT04OGY0hSEFOIENPVU5DSUwgRU1QSEFUSUMgVE9ORRoGiyFUT05FLTIfAYwhMxID5dMCU0FXEgaHIVRPTkUtMhcBiCEzFwGJITUXAYohNg0Q/NQCVEFJIExBSU5HIFRPTkUtMhwB/dQCNQ0GuSBWSVJBTUEPBbggU0FSR0ENGOkgV0VTVEVSTiBQV08gS0FSRU4gVE9ORS0xJAHqIDIkAesgMyQB7CA0JAHtIDUJFM4gWU1CT0wgQUZPUkVNRU5USU9ORUQQEPfUAklUT04gRVhDTEFNQVRJT04VA/jUAk9ORRUD+dQCVFdPDwnNIENPTVBMRVRFRA8IzyBHRU5JVElWRQ8IzCBMT0NBVElWRQ8QnyFTSEFOIEVYQ0xBTUFUSU9OFAOeIU9ORQgV+NMCVEFJIExBSU5HIERJR0lUIEVJR0hUGAT10wJGSVZFGQP00wJPVVIYBPnTAk5JTkUYA/HTAk9ORRgF99MCU0VWRU4ZAvbTAklYGAXz0wJUSFJFRRkC8tMCV08YBPDTAlpFUk8JGeMgT05FIE1BUksgU0dBVyBLQVJFTiBIQVRISR0G5CBLRSBQSE8IDawgVk9XRUwgU0lHTiBBQRQBsiBJFQWcIVRPTiBBGgGdIUkTAbEgRRQGtSAgQUJPVkUTDPEgR0VCQSBLQVJFTiBJEwGtIEkUAa4gSRMI9CBLQVlBSCBFRRkC8iBPRRkB8yBVEwazIE1PTiBJSRcBtCBPEw3iIFNHQVcgS0FSRU4gRVUUBoMhSEFOIEFBGAGEIUUZBoUhIEFCT1ZFGAeGIUZJTkFMIFkTB6sgVEFMTCBBQRMBryBVFAGwIFUTCdggVk9DQUxJQyBMHAHZIEwbAdYgUhwB1yBSExTnIFdFU1RFUk4gUFdPIEtBUkVOIEVVJQLoIFVFABqAVE4tQVJZIENJUkNMRUQgRE9UIE9QRVJBVE9SDg2BVFBMVVMgT1BFUkFUT1IODoJUVElNRVMgT1BFUkFUT1IHCJBET1BST0RVQ1QGDMJFSU5URVJTRUNUSU9OBgvARUxPR0lDQUwgQU5EDgLBRU9SBgePRFBST0RVQ1QGHIVUU1FVQVJFIElOVEVSU0VDVElPTiBPUEVSQVRPUg0OhlRVTklPTiBPUEVSQVRPUgcIkURVTU1BVElPTgYOiVRUSU1FUyBPUEVSQVRPUgYFw0VVTklPTgsSg1QgT1BFUkFUT1IgV0lUSCBET1QaBIRUUExVUwYS/1VXSElURSBWRVJUSUNBTCBCQVIBHquRBEFCQVRBRUFOIENSVUNJRk9STSBOVU1CRVIgRk9VUgoMgZEETEVUVEVS", + "IEFMRVBIEgOXkQRZSU4RBIORBEJFVEgRBoWRBERBTEVUSBELgJEERklOQUwgQUxFUEgXBIKRBEJFVEgXAoaRBEhFFwSOkQRLQVBIFwaQkQRMQU1FREgXA5KRBE1FTRcDlJEETlVOFwSckQRTSElOFwSMkQRZT0RIEQWEkQRHSU1FTBECh5EESEUTAoqRBFRIEQSPkQRLQVBIEQaRkQRMQU1FREgRA5ORBE1FTREDlZEETlVOEQKYkQRQRREEmpEEUU9QSBEEm5EEUkVTSBEFmZEEU0FESEUTBJaRBE1FS0gSA52RBEhJThEDnpEEVEFXEgOLkQRFVEgRA4iRBFdBVxEEjZEEWU9ESBEFiZEEWkFZSU4KC6yRBE5VTUJFUiBGSVZFEgOqkQRPVVIRA6eRBE9ORRQIr5EEIEhVTkRSRUQRA62RBFRFThIEqZEESFJFRRIFrpEEV0VOVFkTAaiRBE8DAodETEECFfjJB0cgTVVOREFSSSBESUdJVCBFSUdIVBIE9ckHRklWRRMD9MkHT1VSEgT5yQdOSU5FEgPxyQdPTkUSBffJB1NFVkVOEwL2yQdJWBIF88kHVEhSRUUTAvLJB1dPEgTwyQdaRVJPDAjVyQdMRVRURVIgQRQB18kHQhQB2ckHSBQB1skHShQC2MkHTlkTAeTJB0UUAebJB0cUAurJB0xMFAHnyQdNFAHoyQdOFQHlyQdOFALpyQdUVBMB2skHSRQC3MkHREQUAd7JB0gUAdvJB1MUAd3JB1QTAdDJB08UAdLJB0wUAtTJB05HFAHRyQdQFAHTyQdZEwHfyQdVFAHgyQdDFAHhyQdEFAHiyQdLFAHjyQdSDAnuyQdTSUdOIElLSVIRBezJB01VSE9SEQTryQdPSk9EEQXvyQdTVVRVSBEF7ckHVE9ZT1ICCYXpB0lMIFBPTElTSAMHpkFSQSBTSUdOAgEVSwII2+kHTUUgQkFER0UCArxFTkQEEuOzBElOQUdBUkkgSEVBRFNUUk9LRQwIoLMETEVUVEVSIEEUAaGzBEEUAauzBEkUAa2zBFUTAsSzBEJBFALFswRIQRMCs7MEQ0EUArSzBEhBEwK/swREQRQCurMEREEVAruzBEhBFALAswRIQRMBqrMERRMCsLMER0EUArGzBEhBEwLOswRIQRMBorMESRQBo7MESRMCtbMESkEUArazBEhB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RVJFAwXUTUVOVFJZCAWr7QcgU0lHTgMN9ekHTU9CSUxFIFBIT05FUwMZnuoHT05FIFVOREVSIEVJR0hURUVOIFNZTUJPTAMLt+0HUEVERVNUUklBTlMEBfLqB0lSQUNZAw6t7QdTTU9LSU5HIFNZTUJPTAIMoAEtQlJFQUsgU1BBQ0UCEu9ATUlOQUwgRElHSVQgU0hBUEVTBAiOgwRTTUEgU0lHTgIRkUBOLUJSRUFLSU5HIEhZUEhFTgQUse0HUE9UQUJMRSBXQVRFUiBTWU1CT0wDB91VRk9SS0lORwIBvUVSAw27QURJQyBNQVJLIFNJR04DD7JFTUFMIFNVQkdST1VQIE9GEgy0RSBPUiBFUVVBTCBUTwMcolJUSCBFQVNUIEFORCBTT1VUSCBXRVNUIEFSUk9XDASXQ1JST1cQFahSIEFORCBTT1VUSCBFQVNUIEFSUk9XERmxUkNST1NTSU5HIE5PUlRIIFdFU1QgQVJST1caEK5SU09VVEggRUFTVCBBUlJPVxEIufEHRlJPTSBCQVIRCaRSV0lUSCBIT09LCwuIVkJMQUNLIEFSUk9XCwzXQ0RPVUJMRSBBUlJPVwsM4uwHUE9JTlRJTkcgQlVEFATS7AdMRUFGFAna7AdWSU5FIExFQUYLENXwB1NBTlMtU0VSSUYgQVJST1cLFedWVFJJQU5HTEUtSEVBREVEIEFSUk9XIAf3ViBUTyBCQVILC4BWV0hJVEUgQVJST1cGGbTQAklORElDIEZSQUNUSU9OIE9ORSBFSUdIVEgZBLHQAkhB", + "TEYZB7DQAlFVQVJURVIZCbPQAlNJWFRFRU5USBUOstACVEhSRUUgUVVBUlRFUlMbCrXQAlNJWFRFRU5USFMMELfQAlBMQUNFSE9MREVSIE1BUksMDbnQAlFVQU5USVRZIE1BUksPCbbQAlJURVIgTUFSSwwKuNACUlVQRUUgTUFSSwYZoVJXRVNUIEFORCBTT1VUSCBFQVNUIEFSUk9XDASWQ1JST1cQFadSIEFORCBOT1JUSCBFQVNUIEFSUk9XERmyUkNST1NTSU5HIE5PUlRIIEVBU1QgQVJST1cRCLjxB0ZST00gQkFSEQnxQ1RPIENPUk5FUhQIuENMT05HIEJBUhEJo1JXSVRIIEhPT0sLC4lWQkxBQ0sgQVJST1cLDNZDRE9VQkxFIEFSUk9XCwzg7AdQT0lOVElORyBCVUQUBNDsB0xFQUYUCdjsB1ZJTkUgTEVBRgsQ1PAHU0FOUy1TRVJJRiBBUlJPVwsV5lZUUklBTkdMRS1IRUFERUQgQVJST1cgB/ZWIFRPIEJBUgsLgVZXSElURSBBUlJPVwUW6u0HRUFTVC1QT0lOVElORyBBSVJQTEFORQICw+gHU0UEB/yZByBTWU1CT0wCDYRFVCBBIFNVQlNFVCBPRggJhUVQRVJTRVQgT0YFDslETE1PU1QgRVFVQUwgVE8FDIlETiBFTEVNRU5UIE9GBRbERFNZTVBUT1RJQ0FMTFkgRVFVQUwgVE8ECvtGQ0hFQ0sgTUFSSwQI4ERFUVVBTCBUTwcK7URJVkFMRU5UIFRPBAzvREdSRUFURVItVEhBTgQM4kRJREVOVElDQUwgVE8ECe5ETEVTUy1USEFOBBLqRU5PUk1BTCBTVUJHUk9VUCBPRhYM7EUgT1IgRVFVQUwgVE8EC6ZEUEFSQUxMRUwgVE8EBKwBU0lHTgUa4kVRVUFSRSBJTUFHRSBPRiBPUiBFUVVBTCBUTwsX40VPUklHSU5BTCBPRiBPUiBFUVVBTCBUTwQFwURUSUxERQUDrUVSVUUDJMPqB0NIRUQgTEVGVCBTRU1JQ0lSQ0xFIFdJVEggVEhSRUUgRE9UUwkqr09PV0VSIFJJR0hULVNIQURPV0VEIFdISVRFIFJJR0hUV0FSRFMgQVJST1cIIMTqB1JJR0hUIFNFTUlDSVJDTEUgV0lUSCBUSFJFRSBET1RTCCuxT1VQUEVSIFJJR0hULVNIQURPV0VEIFdISVRFIFJJR0hUV0FSRFMgQVJST1cDAcjrB0UEBMrrByBQQUQHAsnrB0dFBATT6QdCT09LCBbU6QcgV0lUSCBERUNPUkFUSVZFIENPVkVSAQ2QmAdQTiBUUkFOU0lTVE9SAQIAVUwDAQBMAheZSU1CRVIgRUlHSFRFRU4gRlVMTCBTVE9QCA+SSUxFVkVOIEZVTEwgU1RPUAcRlklGSUZURUVOIEZVTEwgU1RPUAgRlUlPVVJURUVOIEZVTEwgU1RPUAcSmklOSU5FVEVFTiBGVUxMIFNUT1AHE5hJU0VWRU5URUVOIEZVTEwgU1RPUAgDI0lHTgkPl0lYVEVFTiBGVUxMIFNUT1AHDZFJVEVOIEZVTEwgU1RPUAgRlElISVJURUVOIEZVTEwgU1RPUAgPk0lXRUxWRSBGVUxMIFNUT1AKDZtJTlRZIEZVTEwgU1RPUAMIlkJFUk8gU0lHTgIS4d8FU0hVIElURVJBVElPTiBNQVJLAgqp6gdUIEFORCBCT0xUASDPwgdZSUFLRU5HIFBVQUNIVUUgSE1PTkcgQ0lSQ0xFRCBDQRcLyMIHRElHSVQgRUlHSFQdBMXCB0ZJVkUeA8TCB09VUh0EycIHTklORR0DwcIHT05FHQXHwgdTRVZFTh4CxsIHSVgdBcPCB1RIUkVFHgLCwgdXTx0EwMIHWkVSTxcIpMIHTEVUVEVSIEEfAaXCB0EeAojCB0NBHgKPwgdEQR8CncIHTEEeAarCB0UfAavCB0UeApXCB0ZBHgKiwgdHQR4ChMIHSEEgAZ/CB0geAabCB0keAo7CB0tBHgKJwgdMQR4CgMIHTUEfAqDCB0xBHgKFwgdOQR8CjMIHQ0EfAofCB0tBHwKcwgdQQSACnsIHTEEfApnCB1FBHwKRwgdSQR8CgsIHVEEgAo3CB1NBIAKTwgdYQR8CkMIHWUEeAajCB08fAanCB08eAprCB1BBHwKhwgdMQR4Cl8IHUUEeApbCB1JBHwKjwgdSQR4CisIHU0EeAoPCB1RBHwKBwgdTQR8ClMIHWEEeAafCB1UeApLCB1ZBHgGswgdXHgKGwgdYQR8Cm8IHWUEeApjCB1lBHgKLwgdaQRgMzsIHT0dPR1JBTSBOWUFKFw+6wgdTSUdOIEZPUiBBTklNQUwgDLvCB0lOVkVSVEVCUkFURSAIucIHTE9DQVRJT04gBrfCB1BFUlNPTiAFuMIHVEhJTkccBbzCB1hXIFhXGBK9wgdZTExBQkxFIExFTkdUSEVORVIXBrDCB1RPTkUtQhwBtsIHRBwBtcIHRxwBssIHShwBscIHTRwBtMIHUxwBs8IHVgAc/P8DT0JKRUNUIFJFUExBQ0VNRU5UIENIQVJBQ1RFUgIYp1NMSVFVRSBBTkdMRSBPUEVOSU5HIERPV04WAqZTVVAIBt1cSFlQSEVOAhH/R1NFUlZFUiBFWUUgU1lNQk9MAQr17gdDQ1VMVEFUSU9OAhHHSFIgQU1PVU5UIE9GIENIRUNLBAvESEJFTFQgQlVDS0xFBQbFSE9XIFRJRQUZxkhSQU5DSCBCQU5LIElERU5USUZJQ0FUSU9OBAXBSENIQUlSBRbJSFVTVE9NRVIgQUNDT1VOVCBOVU1CRVIEBMhIREFTSAUPykhPVUJMRSBCQUNLU0xBU0gEBMJIRk9SSwQEwEhIT09LBA3DSElOVkVSVEVEIEZPUksCDNHtB1RBR09OQUwgU0lHTgMEmegHT1BVUwED4uYHREVOAQ7i5wdGRklDRSBCVUlMRElORw8Hu50HIFNZTUJPTAERmy1HSEFNIEZFQVRIRVIgTUFSSwYLkC1MRVRURVIgQUlMTQ0FgS1CRUlUSA0Fii1DRUlSVA4DiS1PTEwNBIctREFJUg0HlS1FQUJIQURIDwWTLURIQURIDwmZLU1IQU5DSE9MTA0Fgy1GRUFSTg0EjC1HT1JUDQSYLUlGSU4OBpQtT0RIQURIDQSCLUxVSVMNBIstTVVJTg0HjS1OR0VBREFMDgOFLUlPTg0DkS1PTk4OAZYtUg0Fmi1QRUlUSA0Ejy1SVUlTDQSELVNBSUwOBY4tVFJBSUYNBYgtVElOTkUNBIYtVUFUSA4Hly1JTExFQU5ODgGSLVIGFZwtUkVWRVJTRUQgRkVBVEhFUiBNQVJLBgqALVNQQUNFIE1BUksCBNsFT05FSwEHpkJITSBTSUdOAQfi7QdJTCBEUlVNAQvM6AdLIEhBTkQgU0lHTgEM/ThMIENISUtJIEFIQUQJC9g4RElHSVQgRUlHSFQPBNU4RklWRRAD1DhPVVIPBNk4TklORQ8D0ThPTkUPBdc4U0VWRU4QAtY4SVgPBdM4VEhSRUUQAtI4V08PBNA4WkVS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ngRCRVRIEgr1ngRGSU5BTCBIRVRIEgryngRHSU1FTC1IRVRIEgT3ngRLQVBIEgb4ngRMQU1FREgTA4GfBEVTSBID+Z4ETUVNEgP6ngROVU4SAvyeBFBFEgT+ngRSRVNIEgX9ngRTQURIRRQE+54ETUVLSBMD/54ESElOEgOAnwRUQVcSA/OeBFdBVxIE9p4EWU9ESBIF9J4EWkFZSU4LD4afBFBVTkNUVUFUSU9OIEJBUhcJiZ8ERk9VUiBET1RTFwiHnwRUV08gQkFSUxsEiJ8ERE9UUwMI0/MHRVIgQURVTFQGA/ToB01BTgYF9egHV09NQU4CA9L1B0lWRQEIyeoHTSBTWU1CT0wBM5vqB04gV0lUSCBFWENMQU1BVElPTiBNQVJLIFdJVEggTEVGVCBSSUdIVCBBUlJPVyBBQk9WRQIRmO0HQ09NSU5HIEFVVE9NT0JJTEUJA43tB0JVUwkL8e0HRklSRSBFTkdJTkUJCpTtB1BPTElDRSBDQVIJBJbtB1RBWEkCDq/rB0UgQlVUVE9OIE1PVVNFBAqkQERPVCBMRUFERVIIGatcT1ZFUiBUV08gRE9UUyBQVU5DVFVBVElPTgMP8fQHLVBJRUNFIFNXSU1TVUlUAgPF8wdJT04BCNbpB1BFTiBCT09LBwGjSFgFD7JOQ0VOVFJFIEFTVEVSSVNLDAqrTkJMQUNLIFNUQVIMBZtOQ1JPU1MMGLxOVEVBUkRST1AtU1BPS0VEIEFTVEVSSVNLBQvC6QdGSUxFIEZPTERFUgYFwesHT0xERVIFCtDoB0hBTkRTIFNJR04FBJPqB0xPQ0sFGe3pB01BSUxCT1ggV0lUSCBMT1dFUkVEIEZMQUcSC+zpB1JBSVNFRCBGTEFHBQbDT1NVQlNFVAcGxE9QRVJTRVQEHY9HLUNJUkNVSVQtT1VUUFVUIEgtVFlQRSBTWU1CT0wUDZBHTC1UWVBFIFNZTUJPTAUZvk9PVVRMSU5FRCBSSUdIVFdBUkRTIEFSUk9XAxWdAVJBVElORyBTWVNURU0gQ09NTUFORAIHzk1ISVVDSFVTAgiNTFBPU0lUSU9OAgq/6QdUSUNBTCBESVNDDAW46wcgSUNPTgQGpUZPTiBLRVkBEcdPUiBXSVRIIERPVCBJTlNJREUCCdnpB0FOR0UgQk9PSwcF4fMHSEVBUlQFBKfzB1VU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DI3nB0UgREVDT1JBVElPTgQFzeYHQVBQTEUDB/f0B0sgSEVBUlQDCq9OV0hFRUwgU1RBUgIE00xTQ0VTAwOr6gdUT0wCB9RFVENIRk9SSwkN2lUgV0lUSCBURUUgVE9QAQan9QdMQUNBUkQEEphGRSBPRiBJTlRFUkVTVCBTSUdOCQfQ7QdXT1JTSElQAwyOQk5DSyBDT05TVEFOVA8Mj0IgT1ZFUiBUV08gUEkDDd3tB1lHUk9VTkQgU0xJREUEFdHhB0lORyBDQVJEIEFDRSBPRiBDTFVCUxQIweEHRElBTU9ORFMUBrHhB0hFQVJUUxQGoeEHU1BBREVTDQSg4QdCQUNLDgrP4QdMQUNLIEpPS0VSDQ7Y4QdFSUdIVCBPRiBDTFVCUxYIyOEHRElBTU9ORFMWBrjhB0hFQVJUUxYGqOEHU1BBREVTDQ3V4QdGSVZFIE9GIENMVUJTFQjF4QdESUFNT05EUxUGteEHSEVBUlRTFQal4QdTUEFERVMOA+DhB09PTA8L1OEHVVIgT0YgQ0xVQlMVCMThB0RJQU1PTkRTFQa04QdIRUFSVFMVBqThB1NQQURFUw0N2+EHSkFDSyBPRiBDTFVCUxUIy+EHRElBTU9ORFMVBrvhB0hFQVJUUxUGq+EHU1BBREVTDQ3e4QdLSU5HIE9GIENMVUJTFQjO4QdESUFNT05EUxUGvuEHSEVBUlRTFQau4QdTUEFERVMODtzhB05JR0hUIE9GIENMVUJTFwjM4QdESUFNT05EUxcGvOEHSEVBUlRTFwas4QdTUEFERVMNDdnhB05JTkUgT0YgQ0xVQlMVCMnhB0RJQU1PTkRTFQa54QdIRUFSVFMVBqnhB1NQQURFUw0O3eEHUVVFRU4gT0YgQ0xVQlMWCM3hB0RJQU1PTkRTFga94QdIRUFSVFMWBq3hB1NQQURFUw0Jv+EHUkVEIEpPS0VSDQ7X4QdTRVZFTiBPRiBDTFVCUxYIx+EHRElBTU9ORFMWBrfhB0hFQVJUUxYGp+EHU1BBREVTDgvW4QdJWCBPRiBDTFVCUxQIxuEHRElBTU9ORFMUBrbhB0hFQVJUUxQGpuEHU1BBREVTDQza4QdURU4gT0YgQ0xVQlMUCMrhB0RJQU1PTkRTFAa64QdIRUFSVFMUBqrhB1NQQURFUw4N0+EHSFJFRSBPRiBDTFVCUxYIw+EHRElBTU9ORFMWBrPhB0hFQVJUUxYGo+EHU1BBREVTDgbh4QdSVU1QLTEUAerhBzAUAevhBzEUAezhBzIUAe3hBzMUAe7hBzQUAe/hBzUUAfDhBzYUAfHhBzcUAfLhBzgUAfPhBzkTAeLhBzIUAfThBzAUAfXhBzETAePhBzMTAeThBzQTAeXhBzUTAebhBzYTAefhBzcTAejhBzgTAenhBzkOC9LhB1dPIE9GIENMVUJTFAjC4QdESUFNT05EUxQGsuEHSEVBUlRTFAai4QdTUEFERVMNC9/hB1dISVRFIEpPS0VSAgGLAUQCAYwBVQMEoPUHTkdFUgMGK1MgU0lHTgkS8lQgQUJPVkUgRVFVQUxTIFNJR04KE61USU4gTEVGVCBIQUxGIENJUkNMRQ0RrlRSSUdIVCBIQUxGIENJUkNMRQ0IuVRUUklBTkdMRQoTqFRXSVRIIEJMQUNLIFRSSUFOR0xFDxejVENJUkNVTUZMRVggQUNDRU5UIEFCT1ZFDwmlVERPVCBCRUxPVw8SolRTTUFMTCBDSVJDTEUgQUJPVkUQDKdUVUJTQ1JJUFQgVFdPDwukVFRJTERFIEFCT1ZFFQWmVEJFTE9XBAuxAS1NSU5VUyBTSUdOAwLHTFRPBQrWVyBGT1JNIEZJVkUMA9VXT1VSCwXUV1RIUkVFDALTV1dPAQGeAU0BDZGYB05QIFRSQU5TSVNUT1IBEKnrB09DS0VUIENBTENVTEFUT1ICCJPtB0xJQ0UgQ0FSChGo7QdTIFJFVk9MVklORyBMSUdIVAcH", + "7ugHT0ZGSUNFUgIEqegHT0RMRQIYrEBQIERJUkVDVElPTkFMIEZPUk1BVFRJTkcQB+lASVNPTEFURQME/+YHQ09STgIN/ukHUlRBQkxFIFNURVJFTwIG51dTRUlET04DD5ZGSVRJT04gSU5ESUNBVE9SAwjv6QdUQUwgSE9STgcEkmBNQVJLCwWgYCBGQUNFBAPu6QdCT1gCCfLmB1QgT0YgRk9PRAMRsO0HQUJMRSBXQVRFUiBTWU1CT0wEAtTyB1RPAwm09QdURUQgUExBTlQCA93oB1VDSAMI1+YHTFRSWSBMRUcDB6MBTkQgU0lHTgML1/UHUklORyBMSVFVSUQDDb7sB1RJTkcgQ0FUIEZBQ0UIBKHsB0ZBQ0UCDf1HV0VSIE9OIFNZTUJPTAgL/EctT0ZGIFNZTUJPTAYM/kdTTEVFUCBTWU1CT0wHBftHWU1CT0wBC//pB1JBWUVSIEJFQURTAgb6REVDRURFUwgWt1UgQUJPVkUgQUxNT1NUIEVRVUFMIFRPDwuzVUVRVUFMUyBTSUdODxO5VU5PVCBBTE1PU1QgRVFVQUwgVE8TCLVVRVFVQUwgVE8PF69VU0lOR0xFLUxJTkUgRVFVQUxTIFNJR04bDLFVTk9UIEVRVUFMIFRPCRXoRUJVVCBOT1QgRVFVSVZBTEVOVCBUTwkL/ERPUiBFUVVBTCBUTw8K/kRJVkFMRU5UIFRPCQ6wRVVOREVSIFJFTEFUSU9OAwnD9QdHTkFOVCBNQU4JBsT1B1BFUlNPTgkFsPIHV09NQU4DDp5CU0NSSVBUSU9OIFRBS0UEIJP8A0VOVEFUSU9OIEZPUk0gRk9SIFZFUlRJQ0FMIENPTE9OIQOQ/ANNTUEfB7H8A0VNIERBU0ggBrL8A04gREFTSCAPlfwDWENMQU1BVElPTiBNQVJLHxOZ/ANIT1JJWk9OVEFMIEVMTElQU0lTHxGR/ANJREVPR1JBUEhJQyBDT01NQSsJkvwDRlVMTCBTVE9QHxK//ANMRUZUIEFOR0xFIEJSQUNLRVQkGLv8A0JMQUNLIExFTlRJQ1VMQVIgQlJBQ0tFVCQOwfwDQ09STkVSIEJSQUNLRVQlDLf8A1VSTFkgQlJBQ0tFVCQUvfwDRE9VQkxFIEFOR0xFIEJSQUNLRVQkC7X8A1BBUkVOVEhFU0lTJA7H/ANTUVVBUkUgQlJBQ0tFVCQWufwDVE9SVE9JU0UgU0hFTEwgQlJBQ0tFVCQUw/wDV0hJVEUgQ09STkVSIEJSQUNLRVQqEpf8A0xFTlRJQ1VMQVIgQlJBQ0tFVCAHs/wDT1cgTElORR8NlvwDUVVFU1RJT04gTUFSSx8TwPwDUklHSFQgQU5HTEUgQlJBQ0tFVCUYvPwDQkxBQ0sgTEVOVElDVUxBUiBCUkFDS0VUJQ7C/ANDT1JORVIgQlJBQ0tFVCYMuPwDVVJMWSBCUkFDS0VUJRS+/ANET1VCTEUgQU5HTEUgQlJBQ0tFVCULtvwDUEFSRU5USEVTSVMlDsj8A1NRVUFSRSBCUkFDS0VUJRa6/ANUT1JUT0lTRSBTSEVMTCBCUkFDS0VUJRTE/ANXSElURSBDT1JORVIgQlJBQ0tFVCsSmPwDTEVOVElDVUxBUiBCUkFDS0VUOQSY/ANLQ0VUHwmU/ANTRU1JQ09MT04fDrD8A1RXTyBET1QgTEVBREVSHw20/ANXQVZZIExPVyBMSU5FAwTo8gdUWkVMAwqXR1ZJT1VTIFBBR0UCA7JASU1FAwO08gdOQ0UGAvjoB1NTBA+ZR1QgU0NSRUVOIFNZTUJPTAUCqOsHRVIHBbbrByBJQ09OAwyeAVZBQ1kgTUVTU0FHRQUKkQFURSBVU0UgT05FDAOSAVRXTwsCkQEtMQwBkgEyAgqv8wdPQklORyBDQU5FAwzH7QdISUJJVEVEIFNJR04DB4VGSkVDVElWRQMKykJQRVJUWSBMSU5FBAa3RE9SVElPTgoFnURBTCBUTwMH2FdTRVJQSU5BASOblwRTQUxURVIgUEFITEFWSSBGT1VSIERPVFMgV0lUSCBDUk9TUx8DnJcERE9UEAyAlwRMRVRURVIgQUxFUEgXBIGXBEJFVEgXBoOXBERBTEVUSBcFgpcER0lNRUwXAoSXBEhFGQKHlwRUSBcEiZcES0FQSBcGipcETEFNRURIFwiLlwRNRU0tUU9QSBcDjJcETlVOFwKOlwRQRRcFj5cEU0FESEUZBI2XBE1FS0gYA5CXBEhJThcDkZcEVEFXFw2FlwRXQVctQVlJTi1SRVNIFwSIlwRZT0RIFwWGlwRaQVlJThALrJcETlVNQkVSIEZPVVIXA6mXBE9ORRoIr5cEIEhVTkRSRUQXA62XBFRFThgEq5cESFJFRRgFrpcEV0VOVFkZAaqXBE8QDJmXBFNFQ1RJT04gTUFSSxATmpcEVFVSTkVEIFNFQ1RJT04gTUFSSwIEyZ0HWUNIRQECkQFVMQIBkgEyAhji6QdCTElDIEFERFJFU1MgTE9VRFNQRUFLRVICD4hATkNUVUFUSU9OIFNQQUNFBg/OXFMgRUxFVkFUVVMgTUFSSwIKnOkHUlBMRSBIRUFSVAMC2+gHU0UCBczpB1NIUElOAhyu7QdUIExJVFRFUiBJTiBJVFMgUExBQ0UgU1lNQk9MABOWS1FVQURSQU5UIExPV0VSIExFRlQPBZdLUklHSFQJCphLVVBQRVIgTEVGVBMfmUsgQU5EIExPV0VSIExFRlQgQU5EIExPV0VSIFJJR0hUHgWaS1JJR0hUGBqbS1VQUEVSIFJJR0hUIEFORCBMT1dFUiBMRUZULgWcS1JJR0hUDwWdS1JJR0hUFA+eSyBBTkQgTE9XRVIgTEVGVCMQn0sgQU5EIExPV0VSIFJJR0hUBRaMVFVQTEUgSU5URUdSQUwgT1BFUkFUT1IKBddAUFJJTUUDA/7uB09BUgMJ6UxSVEVSIE5PVEUDGZZUVEVSTklPTiBJTlRFR1JBTCBPUEVSQVRPUgIXyEBFU1RJT04gRVhDTEFNQVRJT04gTUFSSwkEP01BUksIC99ERUQgRVFVQUwgVE8CBrtNSU5DVU5YAgwiT1RBVElPTiBNQVJLAAaH6AdSQUJCSVQGBbDoByBGQUNFAgWd8wdDQ09PTgMHzucHSU5HIENBUgcKzecHTU9UT1JDWUNMRQITt0dESUNBTCBTWU1CT0wgQk9UVE9NBAH76QdPBQeY6gcgQlVUVE9OBQuiTEFDVElWRSBTSUdOAgmD7QdJTFdBWSBDQVIIBeTtB1RSQUNLAwHGTU4EA4jmB0JPVwMQmvIHU0VEIEJBQ0sgT0YgSEFORAcFtFxDT01NQQcDs1xET1QKGIdcVEVEIElOVEVSUE9MQVRJT04gTUFSS0VSBwSKTkZJU1QHBItOSEFORAsVkOsHIFdJVEggRklOR0VSUyBTUExBWUVEESSW6wdQQVJUIEJFVFdFRU4gTUlERExFIEFORCBSSU5HIEZJTkdFUlMHFIZcSU5URVJQT0xBVElPTiBNQVJLRVIHB+riB01DIFNJR04IBuviB0QgU0lHTggG7OIHUiBTSUdOBxnM9wdTTUFMTCBMRUZUIFNRVUFSRSBCUkFDS0VUCAWLXFFVQVJFAgGP6AdNAgGA6AdUAwK2RElPAgOS9QdaT1IBBv7zB0VDRUlQVAQGkpgHUFRBQ0xFAw0eT1JEIFNFUEFSQVRPUgMRme0HUkVBVElPTkFMIFZFSElDTEUDEvxMWUNMRUQgUEFQRVIgU1lNQk9MBiD6TElORyBTWU1CT0wgRk9SIEdFTkVSSUMgTUFURVJJQUxTFQ/zTFRZUEUtMSBQTEFTVElDUxoK9EwyIFBMQVNUSUNTGgr1TDMgUExBU1RJQ1MaCvZMNCBQTEFTVElDUxoK90w1IFBMQVNUSUNTGgr4TDYgUExBU1RJQ1MaCvlMNyBQTEFTVElDUwIHzuYHRCBBUFBMRQQN5/MHR0lGVCBFTlZFTE9QRQIMu0BGRVJFTkNFIE1BUksCIObjB0dJT05BTCBJTkRJQ0FUT1IgU1lNQk9MIExFVFRFUiBBIQHn4wdCIQHo4wdDIQHp4wdEIQHq4wdFIQHr4wdGIQHs4wdHIQHt4wdIIQHu4wdJIQHv4wdKIQHw4wdLIQHx4wdMIQHy4wdNIQHz4wdOIQH04wdPIQH14wdQIQH24wdRIQH34wdSIQH44wdTIQH54wdUIQH64wdVIQH74wdWIQH84wdXIQH94wdYIQH+4wdZIQH/4wdaBAuuAVNURVJFRCBTSUdOAhXS0gJKQU5HIENPTlNPTkFOVCBTSUdOIEgWAdDSAk4XAc/SAkcWAdHSAlIHCMbSAkxFVFRFUiBBDgK30gJCQQ4CudICQ0EOArTSAkRBDgKx0gJHQQ4CwdICSEEOArrSAkpBDgKw0gJLQQ4CvtICTEEOArjSAk1BDwLC0gJCQQ4CtdICTkEPAsTSAkRBDwKy0gJHQRACw9ICR0EPArvSAllBEALF0gJKQQ4CttICUEEOAr3SAlJBDgK80gJTQQ4Cs9ICVEEOAsDSAldBDgK/0gJZQQcM39ICU0VDVElPTiBNQVJLBwbT0gJWSVJBTUEIDMrSAk9XRUwgU0lHTiBBSRMBzNICVRIBydICRRMBztICQRMBzdICVRIBx9ICSRIBy9ICTxIByNICVQILjOwHTElFVkVEIEZBQ0UCDZfnB01JTkRFUiBSSUJCT04CE/3/A1BMQUNFTUVOVCBDSEFSQUNURVICBp9CU1BPTlNFAxTgTVRSSUNURUQgTEVGVCBFTlRSWS0xFgHhTTIFA7vtB09PTQIJkFdUVVJOIExFRlQHBZFXUklHSFQHBs5HU1lNQk9MAhP/7AdWRVJTRSBDSEVDS0VSIEJPQVJECAWNAUlOREVYCCDI7wdMSUdIVCBGT1VSIFBPSU5URUQgUElOV0hFRUwgU1RBUgoHjQFORSBGRUVECAdcU09MSURVUw8J9VMgT1BFUkFUT1IQEMhPUFJFQ0VESU5HIFNVQlNFVBAW91NXSVRIIEhPUklaT05UQUwgU1RST0tFCCTBVlRJTERFIE9QRVJBVE9SIEFCT1ZFIExFRlRXQVJEUyBBUlJPVx0Qx1ZSSUdIVFdBUkRTIEFSUk9XBwejU0QgQU5HTEUODqVTIFdJVEggVU5ERVJCQVIJBcFcQ09NTUEJDLZARE9VQkxFIFBSSU1FFQ+dYCBRVU9UQVRJT04gTUFSSxAP7VVTVFJPS0UgTk9UIFNJR04JCbBTRU1QVFkgU0VUCRKRXEZPUktFRCBQQVJBR1JBUEhPUwkglesHSEFORCBXSVRIIE1JRERMRSBGSU5HRVIgRVhURU5ERUQJCJBGTk9UIFNJR04JDMtAUElMQ1JPVyBTSUdOCgS1QFJJTUUJDa5cUVVFU1RJT04gTUFSSwkgkesHUkFJU0VEIEhBTkQgV0lUSCBGSU5HRVJTIFNQTEFZRUQKCv5XSUdIVCBBTkdMRQoamUxPVEFURUQgRkxPUkFMIEhFQVJUIEJVTExFVAkUw0JTQU5TLVNFUklGIENBUElUQUwgTAoIz0BFTUlDT0xPTgkQk+sHVEhVTUJTIERPV04gU0lHThAHkusHVVAgU0lHTgoEvURJTERFDgfNRSBFUVVBTFMKC7dAUklQTEUgUFJJTUUJDJTrB1ZJQ1RPUlkgSEFORAMNnukHT0xWSU5HIEhFQVJUUwEJj/MHSElOT0NFUk9TAQGNAUkCB/z7A0FMIFNJR04CBIDnB0JCT04GELBXIEFSUk9XIERPV04gTEVGVBIFsVdSSUdIVA0JtldMRUZUIERPV04SArRXVVANCrdXUklHSFQgRE9XThMCtVdVUA0HsldVUCBMRUZUEAWzV1JJR0hUAgfZ5gdDRSBCQUxMBQfY5gdDUkFDS0VSAgPG8gdGTEUCHv/2B0dIVCBBTkQgTE9XRVIgT05FIEVJR0hUSCBCTE9DSwoW/vYHVVBQRVIgT05FIEVJR0hUSCBCTE9DSwgK7+sHR0VSIEJVQkJMRQkCn0RMRQsIiWAgQlJBQ0tFVBMJklMgV0lUSCBET1QMGoFcRE9UVEVEIFNVQlNUSVRVVElPTiBNQVJLRVIME4BcU1VCU1RJVFVUSU9OIE1BUktFUgwTnFNWQVJJQU5UIFdJVEggU1FVQVJFDAi+RVdJVEggQVJDERb8RkRPV05XQVJEUyBaSUdaQUcgQVJST1cHF5RTUkMgR1JFQVRFUi1USEFOIEJSQUNLRVQIFfRPUk9XIFdJVEggQ0lSQ0xFRCBQTFVTEQz0Q1NNQUxMIENJUkNMRQYYkWBCTEFDSyBMRU5USUNVTEFSIEJSQUNLRVQMFphTVE9SVE9JU0UgU0hFTEwgQlJBQ0tFVAYHiUZDRUlMSU5HBw2NYE9STkVSIEJSQUNLRVQHDH1VUkxZIEJSQUNLRVQTC61HIExPV0VSIEhPT0sUDKxHTUlERExFIFBJRUNFFAqrR1VQUEVSIEhPT0sGG4VcRE9UVEVEIFNVQlNUSVRVVElPTiBCUkFDS0VUCBKLYFVCTEUgQU5HTEUgQlJBQ0tFVA4W8FJSUk9XIFdJVEggUk9VTkRFRCBIRUFEDQupXFBBUkVOVEhFU0lTDQ6dQFFVT1RBVElPTiBNQVJLDQzbU1dJR0dMWSBGRU5DRQYJ/VJGSVNIIFRBSUwIEIn3B1ZFIEVJR0hUSFMgQkxPQ0sHBItGTE9PUgYfgJwHSEFMRiBBTkQgTEVGVCBIQUxGIFdISVRFIENJUkNMRQsM10tCTEFDSyBDSVJDTEURBOlXU1RBUg0DkEtPQ0sLDaWZB0ZMWUlORyBTQVVDRVIMBbr3B09MREVSCyWRnAdIT1JJWk9OVEFMIExJTkUgV0lUSCBUSFJFRSBUSUNLIE1BUktTCxegnQdMT1dFUiBPTkUgUVVBUlRFUiBCTE9DSwsMjfcHTUVESVVNIFNIQURFCwuz9wdSVU5OSU5HIE1BTgsWjpwHVFJJUExFIERBU0ggSE9SSVpPTlRBTAsXq50HVVBQRVIgT05FIFFVQVJURVIgQkxPQ0sLDYycB1dISVRFIEVMTElQU0UIFf3qB05EIFRFTEVQSE9ORSBSRUNFSVZFUgYg6fcHSlVTVElGSUVEIExFRlQgSEFMRiBCTEFDSyBDSVJDTEUaDOH3B1dISVRFIENJUkNMRQYWnVxMT1cgUEFSQVBIUkFTRSBCUkFDS0VUBiDKRU5PUk1BTCBGQUNUT1IgU0VNSURJUkVDVCBQUk9EVUNUBhCVS09ORSBFSUdIVEggQkxPQ0sKDYf3B1FVQVJURVIgQkxPQ0sHD7z3B1BFTiBTUVVBUkVEIERPVAcJ1k9VVEVSIEpPSU4GCylQQVJFTlRIRVNJUxEKn0cgRVhURU5TSU9OEgqgR0xPV0VSIEhPT0sSCp5HVVBQRVIgSE9PSwYXjVxSQUlTRUQgT01JU1NJT04gQlJBQ0tFVAYWxk9TLVNIQVBFRCBCQUcgREVMSU1JVEVSBxHMRUVNSURJUkVDVCBQUk9EVUNUCBGL9wdWRU4gRUlHSFRIUyBCTE9DSwcRp1xJREVXQVlTIFUgQlJBQ0tFVAgTmUBOR0xFIFFVT1RBVElPTiBNQVJLBwbo6gdQRUFLRVINFOnqByBXSVRIIE9ORSBTT1VORCBXQVZFExHq6gdUSFJFRSBTT1VORCBXQVZFUwkK6esHRUNIIEJVQkJMRQcNXVFVQVJFIEJSQUNLRVQUCqVHIEVYVEVOU0lPThUMpkdMT1dFUiBDT1JORVIVDKRHVVBQRVIgQ09STkVSFRLYXFdJVEggRE9VQkxFIFNUUk9LRRoFxkBRVUlMTBoG1lxTVFJPS0UaFY5TVElDSyBJTiBCT1RUT00gQ09STkVSIgqQU1RPUCBDT1JORVIaCIxTVU5ERVJCQVIHE4NcVUJTVElUVVRJT04gQlJB", + "Q0tFVAYEokVUQUNLBw2NmAdISVJEIElORFVDVE9SDBrD9wdXSElURSBSSUdIVCBQT0lOVElORyBJTkRFWAgM7esHT1VHSFQgQlVCQkxFCBGI9wdSRUUgRUlHSFRIUyBCTE9DSwwOivcHUVVBUlRFUlMgQkxPQ0sVF6GdB0xPV0VSIE9ORSBRVUFSVEVSIEJMT0NLFReqnQdVUFBFUiBPTkUgUVVBUlRFUiBCTE9DSwcVlWBPUlRPSVNFIFNIRUxMIEJSQUNLRVQHFIpcUkFOU1BPU0lUSU9OIEJSQUNLRVQIBr9FSUFOR0xFDhTOUyBBQk9WRSBMRUZUIFRSSUFOR0xFDBbu9gdVTEFSIE9ORSBRVUFSVEVSIEJMT0NLBhehXFZFUlRJQ0FMIEJBUiBXSVRIIFFVSUxMEAe5R09YIExJTkUPDYaYB1JVTEVSIFNFR01FTlQGFI9gV0hJVEUgQ09STkVSIEJSQUNLRVQNDIRTVVJMWSBCUkFDS0VUDBKXYExFTlRJQ1VMQVIgQlJBQ0tFVAwLhlNQQVJFTlRIRVNJUwwOm2BTUVVBUkUgQlJBQ0tFVAwWmWBUT1JUT0lTRSBTSEVMTCBCUkFDS0VUBwvZU0lHR0xZIEZFTkNFBR6NCy1GQUNJTkcgQVJNRU5JQU4gRVRFUk5JVFkgU0lHTg0IyZgHQkFTU0lORVQNBJOZB0ZJU0gREJWZByBXSVRIIE9QRU4gTU9VVEgQAZzyB1QNHPaYB1NOQUtFIEhFQUQgV0lUSCBDTE9TRUQgTU9VVEgdCvKYB09QRU4gTU9VVEgOCtUfVkFTVEkgU0lHThgK1x8gV0lUSCBET1RTBhvlTUhBTkRFRCBJTlRFUkxBQ0VEIFBFTlRBR1JBTQYWqkZQT0lOVElORyBBTkdMRSBCUkFDS0VUEArimAdUT01JQyBCT01CDxT9U0NVUlZFRCBBTkdMRSBCUkFDS0VUDwWPmAdESU9ERRAauwFPVUJMRSBBTkdMRSBRVU9UQVRJT04gTUFSSw8L+pgHRU5FUkdZIFdBVkUPB4GYB0dPLUtBUlQPEI7qB01BR05JRllJTkcgR0xBU1MPCpmZB1JBQ0lORyBDQVIQBOeYB0lGTEUQDaGZB09DS0VUIEJPT1NURVIWBNiYB1NISVAREKOZB0xMRVIgQ09BU1RFUiBDQVIPDIOYB1NUSUNLIEZJR1VSRQ8En5kHVEFOSwYdqU9TSEFERUQgV0hJVEUgUklHSFRXQVJEUyBBUlJPVwcXuFJJREUgQVJDIENMT0NLV0lTRSBBUlJPVwYRq0BUTy1MRUZUIEVNQkVERElORw4H50BJU09MQVRFDgSPQE1BUksOCK5AT1ZFUlJJREUFFb1USEFORCBJTlRFUklPUiBQUk9EVUNUBQuSQ1dBUkRTIEFSUk9XEBb1UiBBQk9WRSBBTE1PU1QgRVFVQUwgVE8XF8hWUkVWRVJTRSBBTE1PU1QgRVFVQUwgVE8fDsxWVElMREUgT1BFUkFUT1IXFcJSU0hPUlQgTEVGVFdBUkRTIEFSUk9XFw70UlRJTERFIE9QRVJBVE9SEiO29wdORCBVUFBFUiBBTkQgTE9XRVIgT05FIEVJR0hUSCBCTE9DSxEIpkNGUk9NIEJBUhkRoFIgVE8gQkxBQ0sgRElBTU9ORBYPwfEHRE9XTldBUkRTIEFSUk9XERTEQ09WRVIgTEVGVFdBUkRTIEFSUk9XERTDVlRIUk9VR0ggR1JFQVRFUi1USEFOGQjEVlNVUEVSU0VUGQHHUlgSBeVDTyBCQVIVDJ5STEFDSyBESUFNT05EERW0Q1dJVEggQ09STkVSIERPV05XQVJEUxYLkVJET1RURUQgU1RFTRgU+0NVQkxFIFZFUlRJQ0FMIFNUUk9LRRYVlvAHRVFVSUxBVEVSQUwgQVJST1dIRUFEFgSqQ0hPT0sWGIrwB0xBUkdFIFRSSUFOR0xFIEFSUk9XSEVBRBcDrENPT1AYCLLxB1dFUiBIT09LFhmG8AdNRURJVU0gVFJJQU5HTEUgQVJST1dIRUFEFgya8QdOT1RDSEVEIFRBSUwWCsVSUExVUyBCRUxPVxYbkvAHU01BTEwgRVFVSUxBVEVSQUwgQVJST1dIRUFEHBKC8AdUUklBTkdMRSBBUlJPV0hFQUQXBZtDVFJPS0UWBKNDVEFJTBoclVIgV0lUSCBET1VCTEUgVkVSVElDQUwgU1RST0tFIA+UUlZFUlRJQ0FMIFNUUk9LRRcMjlZJUCBET1dOV0FSRFMaB49WVVBXQVJEUxYP+ENWRVJUSUNBTCBTVFJPS0UQBZpSLVRBSUwLIKnxB0JBQ0stVElMVEVEIFNIQURPV0VEIFdISVRFIEFSUk9XDAqVV0xBQ0sgQVJST1cRE4pXQ0lSQ0xFRCBXSElURSBBUlJPVwwYofEHT1RUT00gU0hBREVEIFdISVRFIEFSUk9XCxC+8AdDT01QUkVTU0VEIEFSUk9XCwziQ0RBU0hFRCBBUlJPVwwL0kNPVUJMRSBBUlJPVxcJh1IgRlJPTSBCQVIYC89DV0lUSCBTVFJPS0UdD4NSVkVSVElDQUwgU1RST0tFFwWcUi1UQUlMEgqNUkRBU0ggQVJST1cLEbbwB0ZJTkdFUi1QT1NUIEFSUk9XDCCr8QdST05ULVRJTFRFRCBTSEFET1dFRCBXSElURSBBUlJPVwsE8fUHSEFORA0czENSUE9PTiBPVkVSIExFRlRXQVJEUyBIQVJQT09OEzXpUldJVEggQkFSQiBET1dOIEFCT1ZFIExFRlRXQVJEUyBIQVJQT09OIFdJVEggQkFSQiBET1dOIg/tUkJFTE9XIExPTkcgREFTSCII31JGUk9NIEJBUiIG11JUTyBCQVIhBcFDV0FSRFMdJ+hSVVAgQUJPVkUgTEVGVFdBUkRTIEhBUlBPT04gV0lUSCBCQVJCIFVQJwjsUk9ORyBEQVNIJiHkUlJJR0hUV0FSRFMgSEFSUE9PTiBXSVRIIEJBUkIgRE9XTiAI21JGUk9NIEJBUiAG01JUTyBCQVIfBcBDV0FSRFMMCsbwB0VBVlkgQVJST1cREMLwB0NPTVBSRVNTRUQgQVJST1cLF6fxB0xFRlQtU0hBREVEIFdISVRFIEFSUk9XCxH+Q09QRU4tSEVBREVEIEFSUk9XCw3JQ1BBSVJFRCBBUlJPV1MMC/j1B1VTSElORyBIQU5ECw/GVlFVQURSVVBMRSBBUlJPVwsYpfEHUklHSFQtU0hBREVEIFdISVRFIEFSUk9XDAXu7AdPQ0tFVAsQ0vAHU0FOUy1TRVJJRiBBUlJPVwwMuvAHUVVBUkVEIEFSUk9XDgvdQ0lHR0xFIEFSUk9XCxaj8QdUT1AgU0hBREVEIFdISVRFIEFSUk9XDBGS8QdSSUFOR0xFIEFSUk9XSEVBRBMN4lYtSEVBREVEIEFSUk9XICWCVyBPVkVSIExFRlRXQVJEUyBUUklBTkdMRS1IRUFERUQgQVJST1chBvJWVE8gQkFSIQ+q8AdXSVRIIEJPTEQgU0hBRlQmGPxWRE9VQkxFIEhPUklaT05UQUwgU1RST0tFLQ/8VlZFUlRJQ0FMIFNUUk9LRSYLrvAHSEVBVlkgU0hBRlQmEqdXTE9ORyBUSVAgRE9XTldBUkRTLwelV1VQV0FSRFMmDKbwB01FRElVTSBTSEFGVCYMovAHTkFSUk9XIFNIQUZUJhCy8AdWRVJZIEhFQVZZIFNIQUZUGwzsVkRBU0hFRCBBUlJPVxsNhldQQUlSRUQgQVJST1dTDgnbQ1BMRSBBUlJPVxIKj1JEQVNIIEFSUk9XDA+gQ1dPIEhFQURFRCBBUlJPVw4WhVItSEVBREVEIEFSUk9XIEZST00gQkFSHBuBUldJVEggRE9VQkxFIFZFUlRJQ0FMIFNUUk9LRSEEllJUQUlMJRyYUiBXSVRIIERPVUJMRSBWRVJUSUNBTCBTVFJPS0UrD5dSVkVSVElDQUwgU1RST0tFIhLuV1JJQU5HTEUgQVJST1dIRUFEUyEPgFJWRVJUSUNBTCBTVFJPS0UWEZBSVFJJUExFIERBU0ggQVJST1cLCp1DV0FWRSBBUlJPVwwK6ENISVRFIEFSUk9XFgrwQyBGUk9NIFdBTEwXGZbxB1dJVEhJTiBUUklBTkdMRSBBUlJPV0hFQUQCAo3pB05HBAbaBSBBQk9WRQUE3+0HQlVPWQUI10RFUVVBTCBUTwUL1kRJTiBFUVVBTCBUTwUImERPUEVSQVRPUgUFsFxQT0lOVAQJkPUHRUQgUExBTkVUBAjt6gdJTkcgQkVMTAInq1JTSU5HIERJQUdPTkFMIENST1NTSU5HIEZBTExJTkcgRElBR09OQUwZELBSU09VVEggRUFTVCBBUlJPVwECq0BMRQIB50BJAgGPQE0CAa5ATwET4OYHT0FTVEVEIFNXRUVUIFBPVEFUTwIIlvIHQk9UIEZBQ0UCAqj1B0NLBAKA7QdFVAIL+/MHTEwgT0YgUEFQRVIED97rB0VELVVQIE5FV1NQQVBFUgUJoucHUiBDT0FTVEVSBwX87QdTS0FURQQZo/IHSU5HIE9OIFRIRSBGTE9PUiBMQVVHSElORwILmoMETUFOIEFTIFNJR04GDpuDBENFTlRVUklBTCBTSUdOBg2WgwRERU5BUklVUyBTSUdOBxOUgwRJTUlESUEgU0VYVFVMQSBTSUdOBw2ZgwRVUE9ORElVUyBTSUdOBg3nQk5VTUVSQUwgRUlHSFQPBepCTEVWRU4OBexCRklGVFkTC4ZDIEVBUkxZIEZPUk0UCIdDVEhPVVNBTkQQAuRCVkUSCO5CIEhVTkRSRUQTCIFDVEhPVVNBTkQPA+NCT1VSDgToQk5JTkUOA+BCT05FEQjtQiBIVU5EUkVEGQmIQyBUSE9VU0FORBII70JUSE9VU0FORBoEgEMgQyBEDhSDQ1JFVkVSU0VEIE9ORSBIVU5EUkVEDgXmQlNFVkVODwLlQklYEQqFQyBMQVRFIEZPUk0OA+lCVEVOEQmCQyBUSE9VU0FORA8E4kJIUkVFDwXrQldFTFZFEAHhQk8GDpeDBFFVSU5BUklVUyBTSUdOBg2SgwRTRU1VTkNJQSBTSUdOCA2YgwRTVEVSVElVUyBTSUdOCAqQgwRYVEFOUyBTSUdOCgiTgwRVTEEgU0lHTgcLlYMESUxJUVVBIFNJR04GCpGDBFVOQ0lBIFNJR04CBZPoB09TVEVSAwvc9QdUIFZFR0VUQUJMRQICueYHU0UEA/XnB1RURQIPukJUQVRFRCBDQVBJVEFMIFEIE+dORkxPUkFMIEhFQVJUIEJVTExFVAgY5U5IRUFWWSBCTEFDSyBIRUFSVCBCVUxMRVQIHc1XTElHSFQgRk9VUiBQT0lOVEVEIEJMQUNLIENVU1AIF89XV0hJVEUgRk9VUiBQT0lOVEVEIENVU1ACC83pB1VORCBQVVNIUElOBgaL7wdUQVJHRVQFEeXkB0VEIFNZTUJPTCBGT1IgQ0FJEwLg5AdGVRMC4eQHTFUTBOLkB1NIT1UVBuTkB1VBTkdYSRMC4+QHWEkCBaPtB1dCT0FUAQEeUwEJvUFVQkxFIFNJR04CDMnnB0dCWSBGT09UQkFMTAIK9FNMRS1ERUxBWUVEAg7nnARNSSBESUdJVCBFSUdIVAsE5JwERklWRQwD45wET1VSCwTonAROSU5FCwPgnARPTkULBeacBFNFVkVODALlnARJWAsF4pwEVEhSRUUMAuGcBFdPBRH7nARGUkFDVElPTiBPTkUgSEFMRhIH/JwEUVVBUlRFUhIF/ZwEVEhJUkQOCv6cBFRXTyBUSElSRFMFFPmcBE5VTUJFUiBFSUdIVCBIVU5EUkVEEQHwnARZDAXtnARGSUZUWQ4K9pwEVkUgSFVORFJFRA0E7JwET1JUWQ4K9ZwEVVIgSFVORFJFRAwM+pwETklORSBIVU5EUkVEEALxnARUWQwL8pwET05FIEhVTkRSRUQMDficBFNFVkVOIEhVTkRSRUQRAu+cBFRZDQr3nARJWCBIVU5EUkVEDwLunARUWQwD6ZwEVEVODQXrnARISVJUWQ4L9JwEUkVFIEhVTkRSRUQNBeqcBFdFTlRZDgnznARPIEhVTkRSRUQCEe4tTklDIEFSTEFVRyBTWU1CT0wGD/AtQkVMR1RIT1IgU1lNQk9MBhHtLUNST1NTIFBVTkNUVUFUSU9OBguqLUxFVFRFUiBBQyBBDgOrLUVTQw4KyS1MR0laIEVPTEhYDgaoLU5TVVogQQ0Y0i1CRVJLQU5BTiBCRU9SQyBCSkFSS0FOIEINAc0tQw4D4y1BTEMOBOQtRUFMQw8Bsy1ODgbiLVdFT1JUSA0B0S1EDgveLUFHQVogREFFRyBEDgfbLU9UVEVELUwUAcAtThQB1C1QDQHCLUUOAuAtQVIOCdYtSFdBWiBFSCBFDgK2LU5HDgKnLVRIDQ6gLUZFSFUgRkVPSCBGRSBGDg/3LVJBTktTIENBU0tFVCBBQxwD+C1FU0MbAvYtRUgbAvUtSVMbAvQtT1MNAbUtRw4CuC1BUg4Kty1FQk8gR1lGVSBHDwHELVINB7stSEFFR0wgSA8Gui1HTEFaIEgNDOgtSUNFTEFORElDLVlSDgLdLU5HEAPcLVdBWg4C4S1PUg4MwS1TQVogSVMgSVNTIEkOB8ctV0FaIEVPSA0Hwy1KRVJBTiBKDQHxLUsOBbQtQVVOIEsRAbItQQ0S2i1MQVVLQVogTEFHVSBMT0dSIEwOEMUtT05HLUJSQU5DSC1BUiBBRRkIvC1IQUdBTEwgSBkG2C1NQURSIE0ZBawtT1NTIE8ZAuYtWVINDNctTUFOTkFaIE1BTiBNDRG+LU5BVURJWiBOWUQgTkFVRCBODQGuLU8OAa8tRQ4BsC1ODgHzLU8OBdUtUEVOLVAOA6ktUyBPDg7fLVRIQUxBTiBFVEhFTCBPDQ/ILVBFUlRITyBQRU9SVEggUA0B6S1RDRCxLVJBSURPIFJBRCBSRUlEIFINAvItU0gPDcYtT1JULVRXSUctQVIgQRgJ0y1CSkFSS0FOIEIYCL0tSEFHQUxMIEgYBtktTUFEUiBNGAa/LU5BVUQgThgFrS1PU1MgTxgFzC1TT0wgUxgF0C1UWVIgVBgC5y1ZUg4Wyy1JR0VMIExPTkctQlJBTkNILVNPTCBTDgfKLU9XSUxPIFMOA+UtVEFODRSmLVRIVVJJU0FaIFRIVVJTIFRIT1JODg7PLUlXQVogVElSIFRZUiBUDQmiLVVSVVogVVIgVQ0BoS1WDQGlLVcOC7ktVU5KTyBXWU5OIFcNAeotWA0BpC1ZDgGjLVINAc4tWgYU7C1NVUxUSVBMRSBQVU5DVFVBVElPTgYS6y1TSU5HTEUgUFVOQ1RVQVRJT04GD+8tVFZJTUFEVVIgU1lNQk9MAwPD5wdORVIEE73nB0lORyBTSElSVCBXSVRIIFNBU0gCCKhBUEVFIFNJR04CIvZXU1NJQU4gQVNUUk9MT0dJQ0FMIFNZTUJPTCBCSU5PVklMRRwG9FdOT1ZJTEUcCPVXUVVJTlRJTEUcCPdXU0VOVEFHT04cCfhXVFJFREVDSUxFHAnzV1ZJR0lOVElMRQANzFNTIElOIFRSSUFOR0xFAQn38wdBRkVUWSBQSU4HBLrzB1ZFU1QCCdBMR0lUVEFSSVVTAgb1TUlMQk9BVAIR9uYHS0UgQk9UVExFIEFORCBDVVACCcLzB0xUIFNIQUtFUgQDk0xJUkUDCuH1B1VUSU5HIEZBQ0UCGbYQTUFSSVRBTiBBQkJSRVZJQVRJT04gTUFSSwoLgBBMRVRURVIgQUxBRhEDhRBCQUESAoEQSVQRBYMQREFMQVQRApAQRkkRBYIQR0FNQU4RAo8QSU4SAYcQVBIBhBBZEQSKEEtBQUYRBYsQTEFCQVQRA4wQTUlNEQONEE5V", + "ThEDkhBRVUYRBJMQUklTSBEElBBTSEFOEgaOEElOR0FBVBEElRBUQUFGEgKIEElUEgaREFNBQURJWREDiRBZVVQRA4YQWkVOCguZEE1BUksgREFHRVNIDw6bEEVQRU5USEVUSUMgWVVUDwKWEElOEQWXEC1BTEFGDwetEE5FUVVEQUEPCZgQT0NDTFVTSU9OCx2aEE9ESUZJRVIgTEVUVEVSIEVQRU5USEVUSUMgWVVUGgGoEEkaB6QQU0hPUlQgQQoSsRBQVU5DVFVBVElPTiBBRlNBQVEXBLIQTkdFRBgEvhBOQUFVFwa8EFJLQUFOVRcFtBBUTUFBVRYDsxBCQVUWDbcQTUVMT0RJQyBRSVRTQRYHsBBORVFVREFBFgW5EFFJVFNBFgq1EFNISVlZQUFMQUEXC70QT0YgTUFTSEZBQVQWBLsQVFVSVRYEuhBaQUVGFwS4EElRQUEKDKMQVk9XRUwgU0lHTiBBFgGgEEEVAZ0QRRUBqhBJFQaiEExPTkcgQRsBnxBBGgGcEEUaAakQSRoBphBVFQGrEE8WCaEQVkVSTE9ORyBBHwGeEEEVB6UQU0hPUlQgQRYErBBVS1VOFQGnEFUCBuryB05EV0lDSAMy9+wHUy1TRVJJRiBIRUFWWSBET1VCTEUgQ09NTUEgUVVPVEFUSU9OIE1BUksgT1JOQU1FTlQYJPbsB1RVUk5FRCBDT01NQSBRVU9UQVRJT04gTUFSSyBPUk5BTUVOVBEo+OwHTE9XIERPVUJMRSBDT01NQSBRVU9UQVRJT04gTUFSSyBPUk5BTUVOVAsU+uwHSU5URVJST0JBTkcgT1JOQU1FTlQCAvvyB1JJAgfw7QdURUxMSVRFCQjh6QcgQU5URU5OQQMDxExVUk4CDsFBVURJIFJJWUFMIFNJR04DHLTRAlJBU0hUUkEgQ09OU09OQU5UIFNJR04gSEFBUlULBc7RAkRBTkRBDArY0QJJR0lUIEVJR0hUEQTV0QJGSVZFEgPU0QJPVVIRBNnRAk5JTkURA9HRAk9ORREF19ECU0VWRU4SAtbRAklYEQXT0QJUSFJFRRIC0tECV08RBNDRAlpFUk8MC8/RAk9VQkxFIERBTkRBCwiC0QJMRVRURVIgQRMBg9ECQRMBjtECSRMBkdECVRICqNECQkETAqnRAkhBEgKX0QJDQRMCmNECSEESAqPRAkRBEwKe0QJEQRQCn9ECSEETAqTRAkhBEgGM0QJFEwGN0QJFEgKU0QJHQRMCldECSEESArLRAkhBEgGE0QJJEwGF0QJJEgKZ0QJKQRMCmtECSEESApLRAktBEwKT0QJIQRICrdECTEETArPRAkxBEgKq0QJNQRICpdECTkETApbRAkdBEwKg0QJOQRMCm9ECWUESAY/RAk8TAZDRAk8SAqbRAlBBEwKn0QJIQRICrNECUkESArHRAlNBEwKv0QJIQRMCsNECU0ESAqHRAlRBEwKi0QJIQRMCnNECVEEUAp3RAkhBEgGG0QJVEwGH0QJVEgKu0QJWQRMIitECT0NBTElDIEwbAYvRAkwaAYjRAlIbAYnRAlISAqvRAllBCw2A0QJTSUdOIEFOVVNWQVJBEAvF0QJDQU5EUkFCSU5EVRAGxNECVklSQU1BEgWB0QJTQVJHQQsNtdECVk9XRUwgU0lHTiBBQRcBwNECSRcBw9ECVRYBvtECRRcBv9ECRRYBttECSRcBt9ECSRYBwdECTxcBwtECTxYBuNECVRcBudECVRYJvNECVk9DQUxJQyBMHwG90QJMHgG60QJSHwG70QJSBASV8wdPUE9EAge35wdYT1BIT05FAQWWTUNBTEVTAwLj8wdSRgIE6+cHSE9PTAYIkucHIFNBVENIRUwCAZoBSQIF9O0HT09URVIDBYLzB1JQSU9OBgLPTFVTAgS16wdSRUVOBAeb9QdXRFJJVkVSAw2sQklQVCBDQVBJVEFMIEIPAbBCRQ8BsUJGDwGLQkgPAZBCSQ8BkkJMDwGzQk0PAZhCUA8Bm0JSBxTw7AdMSUdBVFVSRSBFVCBPUk5BTUVOVAcHr0JTTUFMTCBFDQGKQkcNAZNCTA0BtEJPAwPc6QdPTEwDBIhCVVBMRQEDrfMHRUFMAwG66QdUAhDI8gdDT05EIFBMQUNFIE1FREFMAwmnAVRJT04gU0lHTgQClEZPUgID8ldETkECEMjsB0UtTk8tRVZJTCBNT05LRVkDBbHmB0RMSU5HAgWTRkdNRU5UBw749wdFRCBESUdJVCBFSUdIVBAE9fcHRklWRRED9PcHT1VSEAT59wdOSU5FEAPx9wdPTkUQBff3B1NFVkVOEQL29wdJWBAF8/cHVEhSRUURAvL3B1dPEATw9wdaRVJPAgSz8gdMRklFAgc7TUlDT0xPTgQhslRESVJFQ1QgUFJPRFVDVCBXSVRIIEJPVFRPTSBDTE9TRUQEB7pNU0VYVElMRQIYoZgHUEFSQVRFRCBCTE9DSyBRVUFEUkFOVC0xGgGjmAcyGwGnmAczHAGvmAc0GwGrmAc0GgGlmAczGwGtmAc0GgGpmAc0GQGimAcyGgGmmAczGwGumAc0GgGqmAc0GQGkmAczGgGsmAc0GQGomAc0EAnRnAdTRVhUQU5ULTEZAdOcBzIaAdecBzMbAd+cBzQcAe+cBzUdAY+dBzYcAf+cBzYbAeecBzUcAYedBzYbAfecBzYaAducBzQbAeucBzUcAYudBzYbAfucBzYaAeOcBzUbAYOdBzYaAfOcBzYZAdWcBzMaAd2cBzQbAe2cBzUcAY2dBzYbAf2cBzYaAeWcBzUbAYWdBzYaAfWcBzYZAdmcBzQaAemcBzUbAYmdBzYaAfmcBzYZAeGcBzUaAYGdBzYZAfGcBzYYAdKcBzIZAdacBzMaAd6cBzQbAe6cBzUcAY6dBzYbAf6cBzYaAeacBzUbAYadBzYaAfacBzYZAdqcBzQaAeqcBzUbAYqdBzYaAfqcBzYZAeKcBzUaAYKdBzYZAfKcBzYYAdScBzMZAdycBzQaAeycBzUbAYydBzYaAfycBzYZAeScBzUaAYSdBzYZAfScBzYYAdicBzQZAeicBzUaAYidBzYZAficBzYYAeCcBzUZAYCdBzYYAfCcBzYKBvtXU1lNQk9MAias8gdSSU9VUyBGQUNFIFdJVEggU1lNQk9MUyBDT1ZFUklORyBNT1VUSAMJoEJWSUNFIE1BUksCCMX8A1NBTUUgRE9UAwu8TVFVSVFVQURSQVRFAgeWRFQgTUlOVVMEDpMBVFJBTlNNSVQgU1RBVEUCC6H1B1dJTkcgTkVFRExFAgW5TVhUSUxFAQKZAUdDARTNTkhBRE9XRUQgV0hJVEUgQ0lSQ0xFDwueTkxBVElOIENST1NTDwSwTlNUQVIDCej1B0tJTkcgRkFDRQMQ2PIHTExPVyBQQU4gT0YgRk9PRAMFmExNUk9DSwMWx6MEUkFEQSBBQkJSRVZJQVRJT04gU0lHTggR3aMEQ09OVElOVUFUSU9OIFNJR04IBcWjBERBTkRBCQrYowRJR0lUIEVJR0hUDgTVowRGSVZFDwPUowRPVVIOBNmjBE5JTkUOA9GjBE9ORQ4F16MEU0VWRU4PAtajBElYDgXTowRUSFJFRQ8C0qMEV08OBNCjBFpFUk8JC8ajBE9VQkxFIERBTkRBCATaowRFS0FNCRXMowRYVFJBIFNIT1JUIFZPV0VMIE1BUksICtyjBEhFQURTVFJPS0UICIOjBExFVFRFUiBBEAGEowRBEAGOowRJEAGQowRVDwKnowRCQRACqKMESEEPApajBENBEAKXowRIQQ8CoqMEREEQAp2jBERBEQKeowRIQRACo6MESEEPAY2jBEUPApOjBEdBEAKUowRIQQ8CsqMESEEPAYWjBEkQAYajBEkPApijBEpBEAKZowRIQQ8CkaMES0EQApKjBEhBDwKsowRMQRACraMETEEPAqmjBE1BDwKkowROQRAClaMER0EQAp+jBE5BEAKaowRZQQ8Bj6METw8CpaMEUEEQAqajBEhBDwKrowRSQQ8CsaMEU0EQAq+jBEhBEAKwowRTQQ8CoKMEVEEQAqGjBEhBEAKbowRUQRECnKMESEEPAYejBFUQAYijBFUPAq6jBFZBEAiLowRPQ0FMSUMgTBgBjKMETBcBiaMEUhgBiqMEUg8CqqMEWUEIAsSjBE9NCAvJowRTQU5ESEkgTUFSSwkN3qMERUNUSU9OIE1BUkstMRUB36MEMgoHyKMEUEFSQVRPUgkMgaMESUdOIEFOVVNWQVJBDgfBowRWQUdSQUhBDQuAowRDQU5EUkFCSU5EVQ0Uz6MESU5WRVJURUQgQ0FORFJBQklORFUNC8KjBEpJSFZBTVVMSVlBDQXKowROVUtUQQ0H26MEU0lEREhBTQ0Lw6MEVVBBREhNQU5JWUENBsCjBFZJUkFNQQ8FgqMEU0FSR0EJCc2jBFVUUkEgTUFSSwgTy6MEVk9XRUwgTU9ESUZJRVIgTUFSSw4Hs6MEU0lHTiBBQRQBvaMESRQBv6MEVRMI5rYEQ0FORFJBIEUaAee2BE8TAbyjBEUTAbSjBEkUAbWjBEkTAb6jBE8UAeC2BEUUAuG2BE9FEw/OowRQUklTSFRIQU1BVFJBIEUTB+S2BFNIT1JUIEUZAeW2BE8TAbajBFUUAeK2BEUUAbejBFUVAeO2BEUTCbqjBFZPQ0FMSUMgTBwBu6METBsBuKMEUhwBuaMEUgQBiPMHSwMH5+YHVkVEIElDRQQO6YgESUFOIExFVFRFUiBBRE8QAvGIBEdFEAHtiARIEAL6iARJUhAC+IgEUkURA/yIBFJBWRAC6IgEU0gQAveIBFdFDwPaiARCSUIPBteIBENIVVJDSA8E24gEREVBRA8D/YgERUFSEQHwiARUEALniARHRxAC+4gEUlIPA9OIBEZFRQ8D3IgER0FHDwXjiARIQS1IQRAD2YgEVU5HDwP+iARJQU4QAvKIBENFEAHmiARGDwXhiARKVURHRQ8E0ogES0lDSw8E5IgETE9MTA8H4IgETUVBU1VSRRAD5YgESU1FDwPviAROVU4PA/SIBE9BSxAC9ogESUwQAeqIBE4QA/WIBE9aRRAB+YgEUhAC7IgEVVQPBNCIBFBFRVAPBO6IBFJPQVIPAtWIBFNPEAPWiARVUkUPBN6IBFRIRVkRA9SIBElHSBAC0YgET1QPAvOIBFVQDwPdiARWT1cPA+KIBFdPRREC64gET0wPA9iIBFlFQREB/4gEVw8D34gEWk9PAgOR6AdFRVACBOHtB0lFTEQDBQ9GVCBJTgYDDk9VVAMK6U1OVE8gU0hSSU5FAwGi7QdQAh6v8gdPQ0tFRCBGQUNFIFdJVEggRVhQTE9ESU5HIEhFQUQDCqDmB09USU5HIFNUQVIDCs3tB1BQSU5HIEJBR1MJB9LtB1RST0xMRVkDGs9WUlQgQkFDS1NMQU5URUQgU09VVEggQVJST1cHLN9WRU5UIEFSUk9XIFBPSU5USU5HIERPV05XQVJEUyBUSEVOIE5PUlRIIEVBU1QGCd9VRE9XTiBUQUNLDw3nVSBXSVRIIE9WRVJCQVIGCd5VTEVGVCBUQUNLCivV8QdXQVJEUyBIQVJQT09OIEFCT1ZFIExPTkcgUklHSFRXQVJEUyBIQVJQT09OBibEUlJJR0hUV0FSRFMgQVJST1cgQUJPVkUgTEVGVFdBUkRTIEFSUk9XESTT8QdIQVJQT09OIEFCT1ZFIExPTkcgTEVGVFdBUkRTIEhBUlBPT04GE85WU0xBTlRFRCBOT1JUSCBBUlJPVwYH4FVVUCBUQUNLDRbpVSBBQk9WRSBTSE9SVCBET1dOIFRBQ0sODehVV0lUSCBVTkRFUkJBUgUE8OYHQ0FLRQUeofkGSEFORCBGT1JNQVQgQ09OVElOVUlORyBPVkVSTEFQEQmi+QZET1dOIFNURVARDqD5BkxFVFRFUiBPVkVSTEFQEQej+QZVUCBTVEVQBQHz9AdTAxD9RlVMREVSRUQgT1BFTiBCT1gDA4/1B1ZFTAMDv+0HV0VSAgSQ8wdSSU1QAwK38gdVRwIN4lNVRkZMRSBQUk9EVUNUAgGtAVkBAQ9JAgvCqwREREhBTSBEQU5EQQkLw6sET1VCTEUgREFOREEIEMmrBEVORCBPRiBURVhUIE1BUksICICrBExFVFRFUiBBEAGBqwRBEAGLqwRJEArbqwRMVEVSTkFURSBVEAGNqwRVDwKkqwRCQRACpasESEEPApOrBENBEAKUqwRIQQ8Cn6sEREEQApqrBERBEQKbqwRIQRACoKsESEEPAYqrBEUPApCrBEdBEAKRqwRIQQ8CrqsESEEPAYKrBEkQAYOrBEkPApWrBEpBEAKWqwRIQQ8CjqsES0EQAo+rBEhBDwKpqwRMQQ8CpqsETUEPAqGrBE5BEAKSqwRHQRACnKsETkEQAperBFlBDwGMqwRPDwKiqwRQQRACo6sESEEPAqirBFJBDwKtqwRTQRACq6sESEEQAqyrBFNBDwKdqwRUQRACnqsESEERFtirBFJFRS1DSVJDTEUgQUxURVJOQVRFIEkQApirBFRBEQKZqwRIQRAV2asEV08tQ0lSQ0xFIEFMVEVSTkFURSBJJQHaqwRJDwGEqwRVEAGFqwRVDwKqqwRWQRAIiKsET0NBTElDIEwYAYmrBEwXAYarBFIYAYerBFIPAqerBFlBCBHGqwRSRVBFVElUSU9OIE1BUkstMRgBx6sEMhgByKsEMwgYz6sEU0VDVElPTiBNQVJLIERPVUJMRSBSSU5HIArQqwQgV0lUSCBSQVlTFSDXqwRXSVRIIENJUkNMRVMgQU5EIEZPVVIgRU5DTE9TVVJFUyYE1asEUkFZUyYO1qsEVFdPIEVOQ0xPU1VSRVMaENGrBERPVUJMRSBDUkVTQ0VOVFMaE9OrBFFVQURSVVBMRSBDUkVTQ0VOVFMaGcyrBFJBWVMgQU5EIERPVFRFRCBDUkVTQ0VOVFMqEM2rBERPVUJMRSBDUkVTQ0VOVFMqEM6rBFRSSVBMRSBDUkVTQ0VOVFMaEtSrBFNFUFRVUExFIENSRVNDRU5UUxocy6sEVFJJREVOVCBBTkQgRE9UVEVEIENSRVNDRU5UUyYSyqsEVS1TSEFQRUQgT1JOQU1FTlRTHQ3SqwRQTEUgQ1JFU0NFTlRTCgvFqwRQQVJBVE9SIEJBUhIDxKsERE9UCQy9qwRJR04gQU5VU1ZBUkENC7yrBENBTkRSQUJJTkRVDQXAqwROVUtUQQ0HwasEU0lEREhBTQ0Gv6sEVklSQU1BDwW+qwRTQVJHQQgNr6sEVk9XRUwgU0lHTiBBQRQBuasESRQK3KsETFRFUk5BVEUgVR4B3asEVRQBu6sEVRMBuKsERRMBsKsESRQBsasESRMBuqsETxMBsqsEVRQBs6sEVRMJtKsEVk9DQUxJQyBSHAG1qwRSAw/AkgRFVElDIExFVFRFUiBOMDERAcGSBDIRAcKSBDMRAcOSBDQRAcSSBDURAcWSBDYRAcaSBDcRAceSBDgRAciSBDkQAsmSBDEwEQHKkgQxEQHLkgQyEQHMkgQzEQHNkgQ0EQHOkgQ1EQHPkgQ2EQHQkgQ3EQHRkgQ4EQHSkgQ5EALTkgQyMBEB1JIEMREB1ZIEMhEB1pIEMxEB15IENBEB2JIENREB2ZIENgQeoesHV0FZUyBCTEFDSyBET1dOIFBPSU5USU5HIElOREVYDxOa6wdMRUZUIFBPSU5USU5HIElOREVYDxSb6wdSSUdIVCBQT0lOVElORyBJTkRFWA8RoOsHVVAgUE9JTlRJTkcgSU5ERVgJGZ/rB1dISVRFIERPV04gUE9JTlRJTkcgSU5ERVgPE5jrB0xFRlQgUE9JTlRJTkcgSU5ERVgPFJnrB1JJR0hUIFBPSU5USU5HIElOREVYDxGe6wdVUCBQT0lOVElORyBJTkRFWAIP", + "mPIHR04gT0YgVEhFIEhPUk5TBCC3tAdXUklUSU5HIEFJUiBCTE9XIFNNQUxMIFJPVEFUSU9OUxQHtbQHSU5HIE9VVBAUuLQHU1VDSyBTTUFMTCBST1RBVElPTlMUBra0B0lORyBJTgwNurQHQlJFQVRIIEVYSEFMRRMGubQHSU5IQUxFDguQsgdVU0ggQkVUV0VFThIIj7IHTVVMVElQTEUSBo6yB1NJTkdMRQwOq7QHQ0hFRUtTIE5FVVRSQUwTBqq0B1BVRkZFRBMGrLQHU1VDS0VEDQSKtQdPTE9ODgOHtQdNTUEMHI60B0RSRUFNWSBFWUVCUk9XUyBET1dOIE5FVVRSQUwcDI20B05FVVRSQUwgRE9XTiQCkLQHVVAcCo+0B1VQIE5FVVRSQUwNFvazB1lOQU1JQyBBUlJPV0hFQUQgTEFSR0UeBfWzB1NNQUxMFBD9swdFVkVSWSBPVEhFUiBUSU1FFAT3swdGQVNUFAf+swdHUkFEVUFMFAf6swdSRUxBWEVEFAz7swdTSU1VTFRBTkVPVVMgDPyzByBBTFRFUk5BVElORxUD+LMHTE9XFAX5swdURU5TRQwEsLQHRUFSUw0J7LQHWENJVEVNRU5UDRGYtAdZRSBCTElOSyBNVUxUSVBMRRYGl7QHU0lOR0xFEASdtAdXSU5LDxOMtAdCUk9XUyBTVFJBSUdIVCBET1dOHgeLtAdORVVUUkFMHgKKtAdVUA8WqLQHR0FaRS1GTE9PUlBMQU5FIENVUlZFRB8IpLQHU1RSQUlHSFQnDKa0ByBBTFRFUk5BVElORygGpbQHRE9VQkxFFBKptAdXQUxMUExBTkUgQ0lSQ0xJTkcfBae0B1VSVkVEHgihtAdTVFJBSUdIVCYMo7QHIEFMVEVSTkFUSU5HJwaitAdET1VCTEUPC5+0B0xBU0hFUyBET1dOFgqgtAdGTFVUVEVSSU5HFgKetAdVUA8IlrQHUyBDTE9TRUQRC5u0B0hBTEYgQ0xPU0VEFgSZtAdPUEVOEQSUtAdPUEVOEQiVtAdTUVVFRVpFRBEJmrQHV0lERSBPUEVOFQ2ctAdOSU5HIE1PVkVNRU5UDCyHtAdGQUNFIERJUkVDVElPTiBQT1NJVElPTiBOT1NFIEZPUldBUkQgVElMVElORykKiLQHVVAgT1IgRE9XTjMIibQHIFRJTFRJTkcNDpu1B0lMTCBNT0RJRklFUi0yGgGctQczGgGdtQc0GgGetQc1GgGftQc2DgT+tAdOR0VSDROdsgdMSUNLIExBUkdFIE1VTFRJUExFGAabsgdTSU5HTEUSCp+yB1NFUVVFTlRJQUwTDZ6yB01BTEwgTVVMVElQTEUYBpyyB1NJTkdMRQ4a8LQHT09SUExBTkUgU0hPVUxERVIgSElQIE1PVkUND5K0B09SRUhFQUQgQ09OVEFDVBUHkbQHTkVVVFJBTBUIk7QHV1JJTktMRUQNCIi1B1VMTCBTVE9QDA2KsgdHUkFTUCBCRVRXRUVOEgiJsgdNVUxUSVBMRRIGiLIHU0lOR0xFDATrtAdIQUlSDgiFsQdORC1BTkdMRRYGhbAHIElOREVYHA6osQcgTUlERExFIExJVFRMRSQEibEHUklORx0Lw7EHUklORyBMSVRUTEUoBMKxByBPVVQdBfSxB1RIVU1CIgPzsQcgSU4jA/KxB09VVBcMo7EHTElUVExFIElOREVYIxKfsQcgVEhVTUIgSU5ERVggVEhVTUI1BJ6xByBPVVQeApaxB1VQFxLUsQdNSURETEUgUklORyBMSVRUTEUpA9OxByBJTioD0rEHT1VUFyKtsQdSSU5HIERPV04gTUlERExFIFRIVU1CIElOREVYIENST1NTHAazsQdMSVRUTEURBvawB0NJUkNMRRcGgbAHIElOREVYHQWHsAcgQkVOVB4FjbAHSElOR0UeBo+wB01JRERMRSQNqrEHIENST1NTIExJVFRMRSoCm7AHRUQlBqWxB0xJVFRMRSUEh7EHUklORyUFn7AHVEhVTUIeC7uxB1JJTkcgTElUVExFGAyhsQdMSVRUTEUgSU5ERVgfApSxB1VQGBLOsQdNSURETEUgUklORyBMSVRUTEUqBdWxByBCRU5UHwLHsQdVUBgLsbEHUklORyBMSVRUTEUSA+awB0xBVxUXybAHIEZPVVIgRklOR0VSUyBDT05KT0lORUQWHumxB0lOREVYIFRIVU1CIENVUlZFIFRIVU1CIElOU0lERRYc1rEHTUlERExFIFJJTkcgTElUVExFIENPTkpPSU5FRDIF17EHIFNJREUWCOiwB05PIFRIVU1CFg3psAdUSFVNQiBGT1JXQVJEHATnsAdTSURFEgLtsAdVUBQU07AHIEZJVkUgRklOR0VSUyBTUFJFQUQoBdSwByBPUEVOFQWCsAdJTkRFWBoMwLEHIFJJTkcgTElUVExFGwXssQdUSFVNQiAF7bEHIE9QRU4VEtCxB01JRERMRSBSSU5HIExJVFRMRRUI8bAHTk8gVEhVTUIVBOywB09QRU4ZCfCwByBOTyBUSFVNQhoN8rAHVEhVTUIgRk9SV0FSRCAE7rAHU0lERRUN87AHVEhVTUIgRk9SV0FSRBsE77AHU0lERRMG9bAHUkxJQ1VFGRW8sQcgSU5ERVggUklORyBMSVRUTEUgT04aFc+xB01JRERMRSBSSU5HIExJVFRMRSBPThoE9LAHT1BFThEEg7IHRklTVBUcyrAHIEZPVVIgRklOR0VSUyBDT05KT0lORUQgQkVOVBYEhLIHSEVFTBYFgLAHSU5ERVgbBYawByBCRU5UIAydsAcgT1ZFUiBNSURETEUcBoqwB0NVUFBFRBwGi7AHSElOR0VEIgSMsAcgTE9XIwmUsAdNSURETEUgVVAsC6awByBUSFVNQiBTSURFHAaOsAdNSURETEUiBZCwByBCRU5UJw+hsAcgVEhVTUIgU1RSQUlHSFQjCZWwB0NPTkpPSU5FRCwHmLAHIENVUFBFRDMOtbAHIFRIVU1CIEZPUldBUkQtBpmwB0hJTkdFRDMLsrAHIFRIVU1CIFNJREUtCpawB0lOREVYIEJFTlQtC5ewB01JRERMRSBCRU5ULQ20sAdUSFVNQiBGT1JXQVJEMwStsAdTSURFNwWvsAcgQkVOVDgJrrAHQ09OSk9JTkVEJAupsQdST1NTIExJVFRMRSgCmrAHRUQqC7OwByBUSFVNQiBTSURFIwaSsAdISU5HRUQpEqOwByBTUFJFQUQgVEhVTUIgU0lERSMGpLEHTElUVExFIw+RsAdSQUlTRUQgS05VQ0tMRVMkA4axB0lORycFi7EHIEJFTlQoCYyxB0NPTkpPSU5FRCMToLAHU1RSQUlHSFQgVEhVTUIgQkVOVCMFnrAHVEhVTUIoB7+wByBBTkdMRUQvBL6wByBPVVQpBKKwB0JFTlQpB6mwB0NJUkNMRUQqD72wB09OSk9JTkVEIEhJTkdFRCoFqLAHVVBQRUQpBquwB0hJTkdFRCoFqrAHT09LRUQjF6ewB1VQIFNQUkVBRCBUSFVNQiBGT1JXQVJEHA6JsAdSQUlTRUQgS05VQ0tMRR0KurEHSU5HIExJVFRMRRwZu7AHVEhVTUIgQU5HTEVEIElOIE1JRERMRSBVUCkNurAHT1VUIE1JRERMRSBVUCIG67EHQ0lSQ0xFKAu8sAdEIE1JRERMRSBVUCMPt7AHVVBQRUQgTUlERExFIFVQJAbnsQdSTElDVUUlD+ixB1ZFIFRIVU1CIElOU0lERS4F6rEHVU5ERVIiEuWxB0ZPUldBUkQgSU5ERVggQkVOVDAI5LEHU1RSQUlHSFQiBOaxB0hPT0smEMOwB0VEIE1JRERMRSBISU5HRUQwArGwB1VQIgTcsQdTSURFJgrisQcgQk9USCBCRU5UJwrhsQdJTkRFWCBCRU5ULQXjsQdISU5HRScK4LEHVEhVTUIgQkVOVC0J37EHQ09OSk9JTkVELQjesQdESUFHT05BTBwQk7AHVVAgTUlERExFIEhJTkdFRCwQpbAHIFRIVU1CIENPTkpPSU5FRDMEpLAHU0lERRYLmLEHTElUVExFIEJFTlQdBI6xB0RPV04hD5GxByBPVEhFUlMgQ0lSQ0xFRCINkLEHUklQUExFIENVUlZFRCkIj7EHU1RSQUlHSFQdBaCxB0lOREVYIgacsQcgVEhVTUIdDpexB1JBSVNFRCBLTlVDS0xFHQWasQdUSFVNQh4MmbEHT1VDSEVTIFRIVU1CHQKSsQdVUBYWnLAHTUlERExFIEJFTlQgT1ZFUiBJTkRFWB0ExLEHRE9XTh0GzLEHTElUVExFHQ7IsQdSQUlTRUQgS05VQ0tMRR4KzbEHSU5HIExJVFRMRR0VwrAHVEhVTUIgQU5HTEVEIElOREVYIFVQKhHBsAdPVVQgSU5ERVggQ1JPU1NFRDQCwLAHVVAjFLmwB0NJUkNMRUQgSU5ERVggSElOR0VEMQK4sAdVUCQOtrAHVVBQRUQgSU5ERVggVVAjD7CwB0hPT0tFRCBJTkRFWCBVUCMGy7EHTElUVExFHQLGsQdVUB8LybEHIFRIVU1CIFNJREUWCauxB1JJTkcgRE9XThsFt7EHSU5ERVgbBrCxB0xJVFRMRRsGtLEHTUlERExFIQq1sQcgQ09OSk9JTkVEIg+2sQdSQUlTRUQgS05VQ0tMRVMbDq+xB1JBSVNFRCBLTlVDS0xFGwW4sQdUSFVNQhsCrrEHVVAWBfWxB1RIVU1CGxX7sQcgQkVUV0VFTiBJTkRFWCBNSURETEUwCaywByBTVFJBSUdIVCQL/LEHTUlERExFIFJJTkckC/2xB1JJTkcgTElUVExFHAf6sQdGT1JXQVJEHAT2sQdIRUVMHBmCsgdPVkVSIEZPVVIgUkFJU0VEIEtOVUNLTEVTIQv/sQdUV08gRklOR0VSUxwJ+bEHU0lERSBCRU5UIQn4sQdDT05KT0lORUQhCPexB0RJQUdPTkFMHBKBsgdVTkRFUiBGT1VSIEZJTkdFUlMiCoiwB0lOREVYIEJFTlQiCZOxB0xJVFRMRSBVUCINgLIHVEhSRUUgRklOR0VSUyMK/rEHV08gRklOR0VSUxID2rAHTEFUFRXbsAcgQkVUV0VFTiBQQUxNIEZBQ0lOR1MWE8ywB0ZJVkUgRklOR0VSUyBTUFJFQUQpBdCwByBCRU5UKgnOsAdGT1VSIEJFTlQqBtewB0hJTkdFRDAJ2bAHIE5PIFRIVU1CMQrYsAdUSFVNQiBTSURFKg3SsAdUSFVNQiBGT1JXQVJEFwvEsAdPVVIgRklOR0VSUyIFxbAHIEJFTlQjCcewB0NPTkpPSU5FRCwGyLAHIFNQTElUIwbGsAdISU5HRUQWBNywB0hFRUwaFM2wByBGSVZFIEZJTkdFUlMgU1BSRUFELgXRsAcgQkVOVC8Jz7AHRk9VUiBCRU5UGwresAdUSFVNQiBTSURFFgzisAdTUExJVCBDRU5UUkUiC+OwByBUSFVNQiBTSURFLQXksAcgQkVOVBwQ4bAHSU5ERVggVEhVTUIgU0lERRwG5bAHTElUVExFFgrfsAdUSFVNQiBCRU5UHAfgsAdGT1JXQVJEHATdsAdTSURFEQX9sAdISU5HRRYZ1bAHIEZJVkUgRklOR0VSUyBTUFJFQUQgT1BFThgVy7AHT1VSIEZJTkdFUlMgQ09OSk9JTkVEFwWEsAdJTkRFWBwH27EHIEhJTkdFRB0NprEHTUlERExFIExJVFRMRSQEiLEHUklORygKjbEHIENPTkpPSU5FRB0LwbEHUklORyBMSVRUTEUdBfCxB1RIVU1CIgbvsQcgTEFSR0UjBO6xB09QRU4jBN2xB1NJREUkBPGxB01BTEwXBoqxB0xJVFRMRR0GorEHIElOREVYIwadsQcgVEhVTUIeBZuxB1RIVU1CFwbFsQdNSURETEUdDNGxByBSSU5HIExJVFRMRRcIgrEHTk8gVEhVTUIXBPuwB09QRU4bCYGxByBOTyBUSFVNQhwN/LAHVEhVTUIgRk9SV0FSRCIE/7AHU0lERRcEp7EHUklORxsdrLEHIERPV04gSU5ERVggVEhVTUIgSE9PSyBNSURETEUXBf6wB1NNQUxMFxmEsQdUSFVNQiBCRVRXRUVOIE1JRERMRSBSSU5HHQSAsQdTSURFIQ+DsQcgVE9VQ0hJTkcgSU5ERVgSA+uwB09PSxUJ6rAHIENVUkxJQ1VFFhS+sQdJTkRFWCBSSU5HIExJVFRMRSBJTigDvbEHT1VUKAW/sQdVTkRFUhYc2rEHTUlERExFIFJJTkcgTElUVExFIENPTkpPSU5FRDID2bEHIElOMwPYsQdPVVQdBcqxB1RIVU1CFgq5sQdSSU5HIFRIVU1CEQT3sAdPVkFMFRTWsAcgRklWRSBGSU5HRVJTIFNQUkVBRBYFg7AHSU5ERVgWCZWxB0xJVFRMRSBVUBYI+bAHTk8gVEhVTUIWC7KxB1JJTkcgTElUVExFFg36sAdUSFVNQiBGT1JXQVJEHAT4sAdTSURFDQP/swdFQUQQEIa0ByBNT1ZFTUVOVCBDSVJDTEUZEYW0By1GTE9PUlBMQU5FIENVUlZFJQiDtAdTVFJBSUdIVBoPhLQHV0FMTFBMQU5FIENVUlZFJAiBtAdTVFJBSUdIVCQEgrQHVElMVBEDgLQHUklNDBD2tAdMSU1CIENPTUJJTkFUSU9OEQj3tAdMRU5HVEgtMRgB+LQHMhgB+bQHMxgB+rQHNBgB+7QHNRgB/LQHNhgB/bQHNw4S1LQHUCBMT1dFUiBPVkVSIFVQUEVSEBDVtAdVUFBFUiBPVkVSIExPV0VSDxLTtAdTIFBSRVNTRUQgVE9HRVRIRVINDYO1B09DQVRJT04gREVQVEgVCYS1B0hFQUQgTkVDSxcEgbUHSUdIVBUMhrUHTElNQlMgRElHSVRTFQWFtQdUT1JTTxUFgrUHV0lEVEgUEYC1By1GTE9PUlBMQU5FIFNQQUNFFQ//tAdXQUxMUExBTkUgU1BBQ0UMFL20B01PVVRIIENMT1NFRCBDT05UQUNUGQe8tAdGT1JXQVJEGQe7tAdORVVUUkFMEwbWtAdPUk5FUlMSBcG0B0ZST1dOFwXDtAcgT1BFThgIwrQHV1JJTktMRUQSBM20B0tJU1MWCM60ByBGT1JXQVJEFwjPtAdXUklOS0xFRBILxLQHT1BFTiBDSVJDTEUXB8W0B0ZPUldBUkQXBMe0B09WQUwbCci0ByBXUklOS0xFRBwEybQHWUFXThcJyrQHUkVDVEFOR0xFIAnLtAcgV1JJTktMRUQhBMy0B1lBV04XCMa0B1dSSU5LTEVEEgW+tAdTTUlMRRcFwLQHIE9QRU4YCL+0B1dSSU5LTEVEEgXQtAdURU5TRRcI0bQHIEZPUldBUkQYBtK0B1NVQ0tFRBIP2LQHV1JJTktMRVMgRE9VQkxFGwbXtAdTSU5HTEUOGteyB1ZFTUVOVC1ESUFHT05BTCBBV0FZIExBUkdFKALYsgdTVCMG1rIHTUVESVVNIwXVsgdTTUFMTB4S37IHQkVUV0VFTiBBV0FZIExBUkdFMALgsgdTVCsG3rIHTUVESVVNKwXdsgdTTUFMTCYN47IHVE9XQVJEUyBMQVJHRTMC5LIHU1QuBuKyB01FRElVTS4F4bIHU01BTEweDduyB1RPV0FSRFMgTEFSR0UrAtyyB1NUJgbasgdNRURJVU0mBdmyB1NNQUxMFS/sswdGTE9PUlBMQU5FIEFSTSBDSVJDTEUgSElUVElORyBXQUxMIExBUkdFIERPVUJMRT4G6bMHU0lOR0xFOA3rswdNRURJVU0gRE9VQkxFPwboswdTSU5HTEU4DOqzB1NNQUxMIERPVUJMRT4G57MHU0lOR0xFIATzsgdCRU5EIQj6sgdPWCBMQVJHRSQG+bIHTUVESVVNJAX4", + "sgdTTUFMTCAF97IHQ0hFQ0shC/ayB09STkVSIExBUkdFJwb1sgdNRURJVU0nBfSyB1NNQUxMIQTusgdST1NTIQ3ZswdVUlZFIENPTUJJTkVEJhW4swdISVRUSU5HIENFSUxJTkcgTEFSR0U2BbezB1NNQUxMLgvHswdGTE9PUiBMQVJHRTQFxrMHU01BTEwmBdezB0xBUkdFKwLYswdTVCYG1rMHTUVESVVNJgXVswdTTUFMTCAS7LIHRE9VQkxFIEFMVEVSTkFUSU5HMgvtsgcgV1JJU1QgRkxFWCcI6rIHU1RSQUlHSFQnCuuyB1dSSVNUIEZMRVggIvSzB0ZJTkdFUiBDSVJDTEVTIEhJVFRJTkcgV0FMTCBET1VCTEU8BvOzB1NJTkdMRSgGqbIHT05UQUNUICG6swdIVU1QIEhJVFRJTkcgQ0VJTElORyBMQVJHRSBET1VCTEU7BryzB1RSSVBMRTUMubMHU01BTEwgRE9VQkxFOwa7swdUUklQTEUtEsmzB0ZMT09SIExBUkdFIERPVUJMRTMMyLMHU01BTEwgRE9VQkxFMxPLswdUUklQTEUgTEFSR0UgVFJJUExFOgzKswdTTUFMTCBUUklQTEUlBdqzB1NNQUxMIAPptAdKQVcgIcCzB0xPT1AgSElUVElORyBDRUlMSU5HIExBUkdFIERPVUJMRTsGvrMHU0lOR0xFNQy/swdTTUFMTCBET1VCTEU7Br2zB1NJTkdMRS0Sz7MHRkxPT1IgTEFSR0UgRE9VQkxFOQbNswdTSU5HTEUzDM6zB1NNQUxMIERPVUJMRTkGzLMHU0lOR0xFJQXbswdTTUFMTCALgLMHUEVBS1MgTEFSR0UmBv+yB01FRElVTSYF/rIHU01BTEwgEOKzB1NIQUtJTkcgUEFSQUxMRUwhFOeyB0lOR0xFIFNUUkFJR0hUIExBUkdFNQLosgdTVDAG5rIHTUVESVVNMAXlsgdTTUFMTCcK6bIHV1JJU1QgRkxFWCAb8bIHVFJJUExFIEFMVEVSTkFUSU5HIE1PVkVNRU5UMwrysgdXUklTVCBGTEVYJxHvsgdTVFJBSUdIVCBNT1ZFTUVOVCcK8LIHV1JJU1QgRkxFWCAawrMHV0FWRSBISVRUSU5HIENFSUxJTkcgTEFSR0U1BcGzB1NNQUxMLQvRswdGTE9PUiBMQVJHRTMF0LMHU01BTEwlBd6zB0xBUkdFJQXdswdTTUFMTCYE3LMHTkFLRSEf8LMHUklTVCBDSVJDTEUgSElUVElORyBXQUxMIERPVUJMRToG77MHU0lOR0xFIAz9sgdaSUdaQUcgTEFSR0UnBvyyB01FRElVTScF+7IHU01BTEwVFaSyB0hJTkdFIERPV04gU0VRVUVOVElBTBsVp7IHU0lERSBUTyBTSURFIFNDSVNTT1JTGxmlsgdVUCBET1dOIEFMVEVSTkFUSU5HIExBUkdFLwWmsgdTTUFMTCMFobIHTEFSR0UjBaKyB1NNQUxMHgqjsgdTRVFVRU5USUFMFSLmswdXQUxMUExBTkUgQVJNIENJUkNMRSBNRURJVU0gRE9VQkxFMQbkswdTSU5HTEUqDOWzB1NNQUxMIERPVUJMRTAG47MHU0lOR0xFHwq6sgdCRU5EIExBUkdFJAa5sgdNRURJVU0kBbiyB1NNQUxMIAjEsgdPWCBMQVJHRSMGw7IHTUVESVVNIwXCsgdTTUFMTB8LwbIHQ0hFQ0sgTEFSR0UlBsCyB01FRElVTSUFv7IHU01BTEwgC72yB09STkVSIExBUkdFJga8sgdNRURJVU0mCL6yB1JPVEFUSU9OJgW7sgdTTUFMTCAEs7IHUk9TUyAWjrMHVVJWRSBIQUxGLUNJUkNMRSBMQVJHRTYCj7MHU1QxBo2zB01FRElVTTEFjLMHU01BTEwmDK2zB0lUVElORyBDSEVTVC0KprMHRlJPTlQgV0FMTCUNirMHUVVBUlRFUiBMQVJHRTICi7MHU1QtBomzB01FRElVTS0FiLMHU01BTEwlDZ+zB1RIRU4gU1RSQUlHSFQnGZGzB1JFRS1RVUFSVEVSIENJUkNMRSBNRURJVU06BZCzB1NNQUxMJA6hswdEIENST1NTIE1FRElVTSwFoLMHU01BTEwfErGyB0RPVUJMRSBBTFRFUk5BVElORzELsrIHIFdSSVNUIEZMRVgmCK+yB1NUUkFJR0hUJgqwsgdXUklTVCBGTEVYHxXyswdGSU5HRVIgQ0lSQ0xFUyBET1VCTEUuBvGzB1NJTkdMRScGqLIHT05UQUNUHxKuswdIVU1QIEhJVFRJTkcgQ0hFU1QsCqezB0ZST05UIFdBTEwkBZSzB0xBUkdFJAaTswdNRURJVU0kBZKzB1NNQUxMHwPotAdKQVcfEq+zB0xPT1AgSElUVElORyBDSEVTVCwKqLMHRlJPTlQgV0FMTCQFl7MHTEFSR0UkBpazB01FRElVTSQFlbMHU01BTEwpB5izByBET1VCTEUfC8qyB1BFQUtTIExBUkdFJQbJsgdNRURJVU0lBciyB1NNQUxMHwelswdTSEFLSU5HIBSssgdJTkdMRSBTVFJBSUdIVCBMQVJHRTQCrbIHU1QvBquyB01FRElVTS8FqrIHU01BTEwmCq6yB1dSSVNUIEZMRVgfErayB1RSSVBMRSBBTFRFUk5BVElORzELt7IHIFdSSVNUIEZMRVgmEbSyB1NUUkFJR0hUIE1PVkVNRU5UJgq1sgdXUklTVCBGTEVYHxebswdXQVZFIENVUlZFIERPVUJMRSBMQVJHRTEGmrMHTUVESVVNMQWZswdTTUFMTCoMnrMHVFJJUExFIExBUkdFMQadswdNRURJVU0xBZyzB1NNQUxMJBO2swdESUFHT05BTCBQQVRIIExBUkdFMga1swdNRURJVU0yBbSzB1NNQUxMJA2wswdISVRUSU5HIENIRVNULAqpswdGUk9OVCBXQUxMIBjuswdSSVNUIENJUkNMRSBGUk9OVCBET1VCTEUyBu2zB1NJTkdMRR8Mx7IHWklHWkFHIExBUkdFJgbGsgdNRURJVU0mBcWyB1NNQUxMDATqtAdORUNLDQuytAdPU0UgQ09OVEFDVBEHsbQHTkVVVFJBTBEHtLQHV0lHR0xFUxIHs7QHUklOS0xFUwwLi7UHUEFSRU5USEVTSVMMFKm1B1JPVEFUSU9OIE1PRElGSUVSLTEwHwGqtQcxHwGrtQcyHwGstQczHwGttQc0HwGutQc1HwGvtQc2HgGhtQcyHgGitQczHgGjtQc0HgGktQc1HgGltQc2HgGmtQc3HgGntQc4HgGotQc5FBfhswctRkxPT1JQTEFORSBBTFRFUk5BVElORysQxbMHIEhJVFRJTkcgQ0VJTElORzQF1LMHRkxPT1IgBuCzB0RPVUJMRSYQxLMHIEhJVFRJTkcgQ0VJTElORy8F07MHRkxPT1IgBt+zB1NJTkdMRSYQw7MHIEhJVFRJTkcgQ0VJTElORy8F0rMHRkxPT1IVE6SzB1dBTExQTEFORSBBTFRFUk5BVEUnEbOzB0lORyBISVRUSU5HIENIRVNUMwqsswdGUk9OVCBXQUxMHwajswdET1VCTEUlDrKzByBISVRUSU5HIENIRVNULgqrswdGUk9OVCBXQUxMHwaiswdTSU5HTEUlDrGzByBISVRUSU5HIENIRVNULgqqswdGUk9OVCBXQUxMDQqTsgdVQiBCRVRXRUVOEAiSsgdNVUxUSVBMRRAGkbIHU0lOR0xFDAmJtQdTRU1JQ09MT04NFe60B0hPVUxERVIgSElQIFBPU0lUSU9OUxkF7bQHU1BJTkUVEvG0B1RJTFRJTkcgRlJPTSBXQUlTVA0YoLIHUVVFRVpFIEZMSUNLIEFMVEVSTkFUSU5HFA6YsgdMQVJHRSBNVUxUSVBMRRoGlrIHU0lOR0xFFAqasgdTRVFVRU5USUFMFQ2ZsgdNQUxMIE1VTFRJUExFGgaXsgdTSU5HTEUNDY2yB1RSSUtFIEJFVFdFRU4TCIyyB01VTFRJUExFEwaLsgdTSU5HTEUNDpWyB1VSRkFDRSBCRVRXRUVOFAeUsgdTWU1CT0xTDAXhtAdURUVUSBEK57QHIEJJVEUgTElQUxII4rQHTU9WRU1FTlQSB+W0B09OIExJUFMZCea0ByBNT1ZFTUVOVBUG47QHVE9OR1VFGwnktAcgTU9WRU1FTlQOD620B05TRSBDSEVFS1MgSElHSBkDr7QHTE9XGQautAdNSURETEUNGeC0B09OR1VFIENFTlRSRSBJTlNJREUgTU9VVEgaDN+0B1NUSUNLSU5HIE9VVBMU3bQHSU5TSURFIE1PVVRIIFJFTEFYRUQTDNq0B0xJQ0tJTkcgTElQUxMT3rQHTU9WRVMgQUdBSU5TVCBDSEVFSxMQ2bQHU1RJQ0tJTkcgT1VUIEZBUhMQ27QHVElQIEJFVFdFRU4gTElQUxcV3LQHVE9VQ0hJTkcgSU5TSURFIE1PVVRIDhf0tAdSU08tRkxPT1JQTEFORSBUV0lTVElORxIV87QHV0FMTFBMQU5FIENVUlZFRCBCRU5EHBDytAdTVFJBSUdIVCBTVFJFVENIDguHsgdVQ0ggQkVUV0VFThIIhrIHTVVMVElQTEUSBoWyB1NJTkdMRQ0wg7MHUkFWRUwtRkxPT1JQTEFORSBST1RBVElPTi1GTE9PUlBMQU5FIEFMVEVSTkFUSU5HMgaCswdET1VCTEUyBoGzB1NJTkdMRScVhrMHV0FMTFBMQU5FIEFMVEVSTkFUSU5HMQaFswdET1VCTEUxBoSzB1NJTkdMRR4Hh7MHU0hBS0lORxMb07IHV0FMTFBMQU5FIEFSTSBTUElSQUwgRE9VQkxFKAbSsgdTSU5HTEUoBtSyB1RSSVBMRR0f0LIHUk9UQVRJT04tRkxPT1JQTEFORSBBTFRFUk5BVElORzEGz7IHRE9VQkxFMQbOsgdTSU5HTEUmFc2yB1dBTExQTEFORSBBTFRFUk5BVElORzAGzLIHRE9VQkxFMAbLsgdTSU5HTEUdB9GyB1NIQUtJTkcMIvW0B1VQUEVSIEJPRFkgVElMVElORyBGUk9NIEhJUCBKT0lOVFMMG++0B1dBTExQTEFORSBTSE9VTERFUiBISVAgTU9WRQIR/usHTEhPVUVUVEUgT0YgSkFQQU4CKqBVTUlMQVIgQUJPVkUgR1JFQVRFUi1USEFOIEFCT1ZFIEVRVUFMUyBTSUdODhufVUxFU1MtVEhBTiBBQk9WRSBFUVVBTFMgU0lHTggN7FRNSU5VUyBTSU1JTEFSCA+eVU9SIEdSRUFURVItVEhBTgsJnVVMRVNTLVRIQU4CB79ETkUgV0FWRQMYmgFHTEUgQ0hBUkFDVEVSIElOVFJPRFVDRVIHHJkBR1JBUEhJQyBDSEFSQUNURVIgSU5UUk9EVUNFUgcem0BISUdILVJFVkVSU0VELTkgUVVPVEFUSU9OIE1BUksHIrlATEVGVC1QT0lOVElORyBBTkdMRSBRVU9UQVRJT04gTUFSSwgTmkBPVy05IFFVT1RBVElPTiBNQVJLByO6QFJJR0hULVBPSU5USU5HIEFOR0xFIFFVT1RBVElPTiBNQVJLBwuPAVNISUZUIFRIUkVFDgKOAVdPBgiOAS1TSElGVC0yDQGPATMDGOijBEhBTEEgQVJDSEFJQyBESUdJVCBFSUdIVBYE5aMERklWRRcD5KMET1VSFgTpowROSU5FFgPhowRPTkUWBeejBFNFVkVOFwLmowRJWBYF46MEVEhSRUUXAuKjBFdPEA3xowROVU1CRVIgRUlHSFRZFwXuowRGSUZUWRgE7aMET1JUWRcG8qMETklORVRZFwvzowRPTkUgSFVORFJFRBsI9KMEVEhPVVNBTkQXB/CjBFNFVkVOVFkYBO+jBElYVFkXA+qjBFRFThgF7KMESElSVFkYBeujBFdFTlRZCA6GG0xFVFRFUiBBQVlBTk5BEAeIG0VFWUFOTkERBYcbWUFOTkEQBpMbSVlBTk5BEBG2G0xQQVBSQUFOQSBCQVlBTk5BGgegG0NBWUFOTkEaB68bREFZQU5OQRsHqRtEQVlBTk5BGgecG0dBWUFOTkEaB6IbSkFZQU5OQRoHmhtLQVlBTk5BGge0G1BBWUFOTkEaB60bVEFZQU5OQRsHpxtUQVlBTk5BEAu5G01CQSBCQVlBTk5BEAaWG1VZQU5OQRAFhRtZQU5OQQ8PvRtEQU5UQUpBIExBWUFOTkEXB7EbTkFZQU5OQRcHwxtTQVlBTk5BDweSG0VFWUFOTkEQBZEbWUFOTkEPB8YbRkFZQU5OQQ8HxBtIQVlBTk5BDweKG0lJWUFOTkEQCJAbTFVVWUFOTkESBY8bWUFOTkEQCI4bUlVVWUFOTkESBY0bWUFOTkEQBYkbWUFOTkEPEp4bS0FOVEFKQSBOQUFTSUtZQVlBDxO3G01BSEFBUFJBQU5BIEJBWUFOTkEbB6EbQ0FZQU5OQRsHsBtEQVlBTk5BHAeqG0RBWUFOTkEbB50bR0FZQU5OQRsHoxtKQVlBTk5BGwebG0tBWUFOTkEbB7UbUEFZQU5OQRsHrhtUQVlBTk5BHAeoG1RBWUFOTkERBbgbWUFOTkEQEMUbVVVSREhBSkEgTEFZQU5OQRkHqxtOQVlBTk5BGQfCG1NBWUFOTkEPB5UbT09ZQU5OQRAFlBtZQU5OQQ8HuxtSQVlBTk5BDw+zG1NBTllBS0EgREFZQU5OQRgHrBtEQVlBTk5BFwefG0dBWUFOTkEXB6YbSkFZQU5OQQ8SpBtUQUFMVUpBIE5BQVNJS1lBWUEXFKUbU0FOWU9PR0EgTkFBS1NJS1lBWUEZBcEbWUFOTkEPB4wbVVVZQU5OQRAFixtZQU5OQQ8HwBtWQVlBTk5BDwe6G1lBWUFOTkEJD+4bSVRIIERJR0lUIEVJR0hUEwTrG0ZJVkUUA+obT1VSEwTvG05JTkUTA+cbT05FEwXtG1NFVkVOFALsG0lYEwXpG1RIUkVFFALoG1dPEwTmG1pFUk8IFvQbUFVOQ1RVQVRJT04gS1VORERBTElZQQgOyhtTSUdOIEFMLUxBS1VOQQ4JghtOVVNWQVJBWUENC4EbQ0FORFJBQklORFUNCYMbVklTQVJHQVlBCBXPG1ZPV0VMIFNJR04gQUVMQS1QSUxMQRMP0RtESUdBIEFFREEtUElMTEEYDPIbR0FFVFRBLVBJTExBGgnzG1lBTlVLSVRUQRgI0xtJUy1QSUxMQRgH2htLT01CVVZBGAnWG1BBQS1QSUxMQRMM2BtHQUVUVEEtUElMTEEVCd8bWUFOVUtJVFRBExDQG0tFVFRJIEFFREEtUElMTEEZCNIbSVMtUElMTEEZCdQbUEFBLVBJTExBFAnbG09NQlUgREVLQRgC2RtWQRoP3BsgSEFBIEFFTEEtUElMTEEfD90bRElHQSBBRUxBLVBJTExBHwveG0dBWUFOVUtJVFRBAiO+TlggUEVUQUxMRUQgQkxBQ0sgQU5EIFdISVRFIEZMT1JFVFRFBRG2Tk9JTlRFRCBCTEFDSyBTVEFSDA3N7wdQSU5XSEVFTCBTVEFSDBSv6gdTVEFSIFdJVEggTUlERExFIERPVAMNhkAtUEVSLUVNIFNQQUNFAxW6TlRFRU4gUE9JTlRFRCBBU1RFUklTSwEJ+e0HS0FURUJPQVJEAg6/5wdJIEFORCBTS0kgQk9PVAMC901FUgIDgOkHVUxMBQ+gTCBBTkQgQ1JPU1NCT05FUwMCqPMHTksBH5ZVTEFOVEVEIEVRVUFMIFRPIE9SIEdSRUFURVItVEhBTiAQmFUgV0lUSCBET1QgSU5TSURFFAmVVUxFU1MtVEhBTh0Ql1UgV0lUSCBET1QgSU5TSURFCBzaVk5PUlRIIEFSUk9XIFdJVEggSE9PS0VEIEhFQUQbDdxW", + "UklaT05UQUwgVEFJTAMO88wCVk9OSUMgQVNURVJJU0sCAvftB0VEAxPM7QdFUElORyBBQ0NPTU1PREFUSU9OCQS07AdGQUNFCQak6QdTWU1CT0wFBqrsB1kgRkFDRQMK9eoHVVRIIE9SIFNQWQIM1eYHSUNFIE9GIFBJWlpBAxPB7AdHSFRMWSBGUk9XTklORyBGQUNFCQzC7AdTTUlMSU5HIEZBQ0UCA7NGT1BFBA3YVElORyBMQVJHRSBBTkQOAtdUT1IDCbDnB1QgTUFDSElORQQBpfMHSAEN6e0HTUFMTCBBSVJQTEFORQcI4PwDTVBFUlNBTkQHB+H8A1NURVJJU0sGDLnqB0JMVUUgRElBTU9ORAYF1fwDQ09MT04IA9D8A01NQQoJ6/wDRVJDSUFMIEFUCBCNRE5UQUlOUyBBUyBNRU1CRVIPDP5FV0lUSCBPVkVSQkFSFCj8RVZFUlRJQ0FMIEJBUiBBVCBFTkQgT0YgSE9SSVpPTlRBTCBTVFJPS0UGC+n8A0RPTExBUiBTSUdOBgqKREVMRU1FTlQgT0YQDfdFIFdJVEggT1ZFUkJBUhYo9EVWRVJUSUNBTCBCQVIgQVQgRU5EIE9GIEhPUklaT05UQUwgU1RST0tFBwbY/ANNIERBU0gHCub8A1FVQUxTIFNJR04HD9f8A1hDTEFNQVRJT04gTUFSSwYJ0vwDRlVMTCBTVE9QBhHl/ANHUkVBVEVSLVRIQU4gU0lHTgYM4/wDSFlQSEVOLU1JTlVTBhHR/ANJREVPR1JBUEhJQyBDT01NQQYS2/wDTEVGVCBDVVJMWSBCUkFDS0VUCwvZ/ANQQVJFTlRIRVNJUwsW3fwDVE9SVE9JU0UgU0hFTEwgQlJBQ0tFVAgM5PwDU1MtVEhBTiBTSUdOBgvf/ANOVU1CRVIgU0lHTgYOuOoHT1JBTkdFIERJQU1PTkQGDOr8A1BFUkNFTlQgU0lHTgcI4vwDTFVTIFNJR04GDdb8A1FVRVNUSU9OIE1BUksGD+j8A1JFVkVSU0UgU09MSURVUwcS3PwDSUdIVCBDVVJMWSBCUkFDS0VUDAva/ANQQVJFTlRIRVNJUwwW3vwDVE9SVE9JU0UgU0hFTEwgQlJBQ0tFVAcS90JPTUFOIE5VTUVSQUwgRUlHSFQVBfpCTEVWRU4UBfxCRklGVFkWAvRCVkUYCP5CIEhVTkRSRUQVA/NCT1VSFAT4Qk5JTkUUA/BCT05FFwj9QiBIVU5EUkVEGAj/QlRIT1VTQU5EFAX2QlNFVkVOFQL1QklYFAP5QlRFThUE8kJIUkVFFQX7QldFTFZFFgHxQk8GCdT8A1NFTUlDT0xPTgYF3AVUSUxERQcgu5YEV08gRE9UUyBPVkVSIE9ORSBET1QgUFVOQ1RVQVRJT04GFPqbB1VQLVBPSU5USU5HIEFJUlBMQU5FBhHhVFZFRSBXSVRIIFVOREVSQkFSBQeqVUVSIFRIQU4MDKxVIE9SIEVRVUFMIFRPAwqzVFNIIFBST0RVQ1QCA6NGSUxFBCO77AdJTkcgQ0FUIEZBQ0UgV0lUSCBIRUFSVC1TSEFQRUQgRVlFUxYKuuwHT1BFTiBNT1VUSAgOh+wHRkFDRSBXSVRIIEhBTE8TEI3sB0VBUlQtU0hBUEVEIEVZRVMTBIjsB09STlMSCoPsB09QRU4gTU9VVEgcD4XsByBBTkQgQ09MRCBTV0VBVCEMhOwHU01JTElORyBFWUVTIROG7AdUSUdIVExZLUNMT1NFRCBFWUVTEgyK7AdTTUlMSU5HIEVZRVMeGK3yByBBTkQgSEFORCBDT1ZFUklORyBNT1VUSCMM8PIHVEhSRUUgSEVBUlRTEwmO7AdVTkdMQVNTRVMSBPLyB1RFQVIDCo/sB1JLSU5HIEZBQ0UCDKztB09LSU5HIFNZTUJPTAEEjOgHTkFJTAMCjegHS0UFB/qZByBTWU1CT0wCC6fyB0VFWklORyBGQUNFAhLU5wdPVyBDQVBQRUQgTU9VTlRBSU4EB8LnB0JPQVJERVIEBcRORkxBS0UEA4NMTUFOBw3ETSBXSVRIT1VUIFNOT1cBAQ5PAgm9TUNDRVIgQkFMTAMC5vMHS1MCCa0BRlQgSFlQSEVOBQnm5gdJQ0UgQ1JFQU0FEazrB1NIRUxMIEZMT1BQWSBESVNLBATO8gdCQUxMBBSUR1dBUkUtRlVOQ1RJT04gU1lNQk9MAhvKngRHRElBTiBDT01CSU5JTkcgQ1VSVkUgQUJPVkUYBcueBEJFTE9XEgnIngRET1QgQUJPVkUWBcaeBEJFTE9XEgrMngRIT09LIEFCT1ZFFwXNngRCRUxPVxIPzp4ETE9ORyBIT09LIEJFTE9XEgrPngRSRVNIIEJFTE9XEgzQ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TUZGIE9GIEFFU0NVTEFQSVVTCQaaTUhFUk1FUwMNg+sHTVBFRCBFTlZFTE9QRQMMzfMHTkRJTkcgUEVSU09OAw6qTFIgQU5EIENSRVNDRU5UBQbbREVRVUFMUwUIoU5PRiBEQVZJRAYHxkVQRVJBVE9SBRTqV1dJVEggTEVGVCBIQUxGIEJMQUNLChDrV1JJR0hUIEhBTEYgQkxBQ0sEEZYBVCBPRiBHVUFSREVEIEFSRUEJBwFIRUFESU5HCQ6WAVBST1RFQ1RFRCBBUkVBCQ2GAVNFTEVDVEVEIEFSRUEKBZgBVFJJTkcJBAJURVhUAwSJ7QdUSU9OBA396wdVRSBPRiBMSUJFUlRZAg6C7QdFQU0gTE9DT01PVElWRQUI3OYHSU5HIEJPV0wDE7xcTk9HUkFQSElDIEZVTEwgU1RPUAMI+vQHVEhPU0NPUEUCCsX3B0lDSyBGSUdVUkUMDcf3ByBMRUFOSU5HIExFRlQVBcj3B1JJR0hUDRDG9wdXSVRIIEFSTVMgUkFJU0VEEgXJ9wdEUkVTUwIJ4OsHT0NLIENIQVJUAwbxR1BXQVRDSAIMz+kHUkFJR0hUIFJVTEVSCATkR05FU1MEBtPmB1dCRVJSWQoHv50HIFNZTUJPTAMXqU5FU1MgT1VUTElORUQgV0hJVEUgU1RBUgMT40RJQ1RMWSBFUVVJVkFMRU5UIFRPBA2cAU5HIFRFUk1JTkFUT1IEGoOZB1BFRCBET1dOLVBPSU5USU5HIFRSSUFOR0xFCBaAmQdMRUZULVBPSU5USU5HIFRSSUFOR0xFCBeCmQdSSUdIVC1QT0lOVElORyBUUklBTkdMRQgUgZkHVVAtUE9JTlRJTkcgVFJJQU5HTEUCAZMBUwIPmecHVURJTyBNSUNST1BIT05FAw7Z8gdGRkVEIEZMQVRCUkVBRAMC0+0HUEECAQJYAQIaVUIDDIhBU0NSSVBUIEVJR0hUCwqMQVFVQUxTIFNJR04KBIVBRklWRQsDhEFPVVIKEI1BTEVGVCBQQVJFTlRIRVNJUwoFi0FNSU5VUwoEiUFOSU5FCgOBQU9ORQoJikFQTFVTIFNJR04KEY5BUklHSFQgUEFSRU5USEVTSVMKBYdBU0VWRU4LAoZBSVgKBYNBVEhSRUULAoJBV08KBIBBWkVSTwQZ+VJFVCBBQk9WRSBSSUdIVFdB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SFJSSUFHRSBSRVRVUk4LEJBIREFUQSBMSU5LIEVTQ0FQRQwFoUhFTEVURREJpUggRk9STSBUV08SEalITUVESVVNIFNIQURFIEZPUk0SHqhIUkVDVEFOR1VMQVIgQ0hFQ0tFUiBCT0FSRCBGT1JNEhmnSFNRVUFSRSBDSEVDS0VSIEJPQVJEIEZPUk0NEZRIVklDRSBDT05UUk9MIEZPVVIaA5FIT05FGgWTSFRIUkVFGwKSSFdPCw2ZSEVORCBPRiBNRURJVU0SBINIVEVYVBMLhEhSQU5TTUlTU0lPTh4Gl0ggQkxPQ0sNBYVIUVVJUlkMBZtIU0NBUEULDpxIRklMRSBTRVBBUkFUT1IMCIxIT1JNIEZFRUQLD51IR1JPVVAgU0VQQVJBVE9SCxWJSEhPUklaT05UQUwgVEFCVUxBVElPTgsJikhMSU5FIEZFRUQLDcXqB01BUktTIENIQVBURVILFJVITkVHQVRJVkUgQUNLTk9XTEVER0UNBaRIV0xJTkUMA4BIVUxMCxCeSFJFQ09SRCBTRVBBUkFUT1ILEM9CU0FNQVJJVEFOIFNPVVJDRQwHj0hISUZUIElOEQOOSE9VVAwEoEhQQUNFDA+BSFRBUlQgT0YgSEVBRElORxQEgkhURVhUDAmaSFVCU1RJVFVURRUJpkggRk9STSBUV08MD5ZIWU5DSFJPTk9VUyBJRExFCxKXV1RZUEUgQSBFTEVDVFJPTklDUwsOn0hVTklUIFNFUEFSQVRPUgsTi0hWRVJUSUNBTCBUQUJVTEFUSU9OAwWv", + "Rk1FVFJZAgEWTgMGzeoHQUdPR1VFAw0WQ0hST05PVVMgSURMRQIWjw5SSUFDIEFCQlJFVklBVElPTiBNQVJLBwfKDkJBUlJFS0gHEYYOQ09MT04gU0tFV0VEIExFRlQUBYcOUklHSFQJCYoOTlRSQUNUSU9OBxS5DkRPVFRFRCBaTEFNQSBBTkdVTEFSFAq4DkhPUklaT05UQUwHEIAORU5EIE9GIFBBUkFHUkFQSAgKvQ5TQVNBIEFCT1ZFDQW+DkJFTE9XBwzADkZFTUlOSU5FIERPVAcTjQ5IQVJLTEVBTiBBU1RFUklTQ1VTEAmMDk1FVE9CRUxVUxAGiw5PQkVMVVMICroOQkFTQSBBQk9WRQ0Fuw5CRUxPVwwNvA4tRVNBU0EgRE9UVEVECA+FDk9SSVpPTlRBTCBDT0xPTgcMkA5MRVRURVIgQUxBUEgOBJIOQkVUSA4GlQ5EQUxBVEgPEpYOT1RMRVNTIERBTEFUSCBSSVNIDgGlDkUODaQORklOQUwgU0VNS0FUSA4Fkw5HQU1BTBMJlA4gR0FSU0hVTkkOApcOSEUQApoOVEgOBJ8OS0FQSA4GoA5MQU1BREgODeYQTUFMQVlBTEFNIEJIQRgC4RBKQRgD6BBMTEEaAukQTEEYA+AQTkdBGQLkEE5BGgLlEE5BGQLiEFlBGALnEFJBGAPqEFNTQRgD4xBUVEEPAqEOSU0OA6IOTlVODgKmDlBFEAutDlJTSUFOIEJIRVRIFgevDkRIQUxBVEgWBq4OR0hBTUFMDgSpDlFBUEgOC6cOUkVWRVJTRUQgUEUPA6oOSVNIDgWoDlNBREhFDwajDkVNS0FUSA8Dqw5ISU4PCc8OT0dESUFOIEZFFgXODktIQVBIFgXNDlpIQUlODxCRDlVQRVJTQ1JJUFQgQUxBUEgOA6wOVEFXDwObDkVUSBIJnA4gR0FSU0hVTkkOA5gOV0FXDgSdDllVREgSA54OIEhFDgSZDlpBSU4HBckOTVVTSUMHEscOT0JMSVFVRSBMSU5FIEFCT1ZFFAXIDkJFTE9XBwywDlBUSEFIQSBBQk9WRQ4FsQ5CRUxPVw4Gsg5ET1RURUQHCcEOUVVTSFNIQVlBBwu2DlJCQVNBIEFCT1ZFDQW3DkJFTE9XCAfCDlVLS0FLSEEIBL8OV0FIQQcPhA5TVUJMSU5FQVIgQ09MT04W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4hhWT0NBTElDIEwbAeMYTBoBwxhSGwHEGFICCLhBTkdFIFNJR04DFL7nB05JUyBSQUNRVUVUIEFORCBCQUxMAwH6TVQCB+rzB1NUIFRVQkUCGMGmB1RSQUdSQU0gRk9SIEFDQ1VNVUxBVElPTg8GmaYHRFZBTkNFDwrRpgdHR1JBVkFUSU9ODwWMpgdTQ0VOVA4HiaYHQkFSUklFUg8Oo6YHT0xEIFJFU09MVVRJT04PDI6mB1JBTkNISU5HIE9VVA4GhqYHQ0VOVFJFDwWhpgdIQU5HRQ8LvaYHTE9TRUQgTU9VVEgTBKamB05FU1MSA8+mB1VSRQ8JzqYHT01QTEVUSU9OEwXSpgdJQU5DRRAHuKYHTlNUQU5DWREElaYHVEFDVBIGnqYHRU5USU9OEgeLpgdSQVJJRVRZDgnIpgdEQVJLRU5JTkcPC6KmB0VDSVNJVkVORVNTEBmPpgdGRUNUSVZFTkVTUyBPUiBESVNUT1JUSU9OEAfHpgdQQVJUVVJFDwvUpgdJRkZJQ1VMVElFUxAKvKYHTUlOSVNITUVOVBEEyaYHTUlORxAIkKYHVkVSR0VOQ0UPBMOmB09VQlQPBaCmB1VUSUVTDgScpgdFQVNFDwzCpgdNQkVMTElTSE1FTlQPCbCmB05DT1VOVEVSUxAHn6YHREVBVk9VUhAJs6YHTEFSR0VNRU5UDwe6pgdURVJOSVRZDwnKpgdYSEFVU1RJT04OB9CmB0ZBSUxVUkUPBbamB0xJR0hUDwiYpgdPTExPV0lORxAH1qYHU1RFUklORw8Kh6YHVUxMIENJUkNMRRIEq6YHTkVTUw4JqKYHR0FUSEVSSU5HFwO/pgcgSU4PDK+mB09JTkcgVE8gTUVFVA8IsqYHUkVBVE5FU1MPCr6mB1VBUkRFRE5FU1MOCM2mB0hBUkRORVNTDwuWpgdPTERJTkcgQkFDSw4IkqYHSU5DUkVBU0UQA8amB05FUg4DnaYHSk9ZDg2KpgdLRUVQSU5HIFNNQUxMDwanpgdJTlNISVAOCdWmB0xBQk9VUklORxAKraYHVyBPUiBNT0RFTA8FpaYHRUdJT04OB8CmB01BU1NJTkcPBrmmB0VBU1VSRQ8EiKYHSVJFRA4M06YHT04gVEhFIFZFUkdFDwmNpgdQUE9TSVRJT04OB6SmB1BBQ0tJTkcQBbSmB1RURVJO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VEVSUwYSwu8HUE9JTlRFRCBCTEFDSyBTVEFSBgrk6wdSQVlTIEFCT1ZFCwXl6wdCRUxPVwsE5usHTEVGVAsF5+sHUklHSFQHEPZDSUdIVFdBUkRTIEFSUk9XUwYO6+sHU1BFRUNIIEJVQkJMRVMFJqNPLUQgQk9UVE9NLUxJR0hURUQgUklHSFRXQVJEUyBBUlJPV0hFQUQILJtXTEVGVC1MSUdIVEVEIERPV05XQVJEUyBFUVVJTEFURVJBTCBBUlJPV0hFQUQIK5lXUklHSFQtTElHSFRFRCBVUFdBUkRTIEVRVUlMQVRFUkFMIEFSUk9XSEVBRAgrmFdUT1AtTElHSFRFRCBMRUZUV0FSRFMgRVFVSUxBVEVSQUwgQVJST1dIRUFEFBSiT1JJR0hUV0FSRFMgQVJST1dIRUFEHxWaV0VRVUlMQVRFUkFMIEFSUk9XSEVBRAYHu1xFTSBEQVNIBgyEQFBFUi1FTSBTUEFDRQIOzugHVU1CUyBET1dOIFNJR04HB83oB1VQIFNJR04DE8hNTkRFUiBDTE9VRCBBTkQgUkFJTgcFiExTVE9STQEimB5JQkVUQU4gQVNUUk9MT0dJQ0FMIFNJR04gLUtIWVVEIFBBGgyZHlNET05HIFRTSFVHUxsUlx5HUkEgR0NBTiAtQ0hBUiBSVEFHUwgbwh9DQU5USUxMQVRJT04gU0lHTiBDQU5HIFRFLVUaCsAfSEVBVlkgQkVBVBoKwR9MSUdIVCBCRUFUGgrDH1NCVUIgLUNIQUwIC6geRElHSVQgRUlHSFQOBKUeRklWRQ8DpB5PVVIOCrEeSEFMRiBFSUdIVBMErh5GSVZFFAOtHk9VUhMEsh5OSU5FEwOqHk9ORRMFsB5TRVZFThQCrx5JWBMFrB5USFJFRRQCqx5XTxMEsx5aRVJPDgSpHk5JTkUOA6EeT05FDgWnHlNFVkVODwKmHklYDgWjHlRIUkVFDwKiHldPDgSgHlpFUk8ICb4fS1UgUlUgS0hBEQ2/HyBCWkhJIE1JRyBDQU4ICeAeTEVUVEVSIC1BDwHoHkEPAtYeQkEQAtceSEEPAsUeQ0EQAsYeSEEPAtEeREEQAsweREERAs0eSEEQAtIeSEEQAtseWkERAtweSEEPDeoeRklYRUQtRk9STSBSQQ8Cwh5HQRACwx5IQQ8C5x5IQQ8Cxx5KQQ8C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SUxJTkcgUk9CT1QgRlJBTUUtMR4B95sHMgoT25gHT1JXQVJELUZBQ0lORyBST0JPVBkF8JsHVU5ORVIJCKBGSU5URUdSQUwJENlcTEVGVCBQQVJFTlRIRVNJUw0N2pgHLUZBQ0lORyBST0JPVBYN7JsHVU5ORVIgRlJBTUUtMSIB7psHMgkR2lxSSUdIVCBQQVJFTlRIRVNJUw4N3JgHLUZBQ0lORyBST0JPVBcN6JsHVU5ORVIgRlJBTUUtMSMB6psHMgkMuVxTRUNUSU9OIFNJR04KDuabB1RBTkRJTkcgUEVSU09OBgGp5wdUBCHo9wdKVVNUSUZJRUQgTE9XRVIgSEFMRiBCTEFDSyBDSVJDTEUZDOD3B1dISVRFIENJUkNMRQQnh5wHTEVGVCBCTEFDSyBMRUZULVBPSU5USU5HIFNNQUxMIFRSSUFOR0xFCQacRkNPUk5FUgoDj0ZST1AJDKJcSEFMRiBCUkFDS0VUCSrv9wdKVVNUSUZJRUQgTE9XRVIgUklHSFQgUVVBUlRFUiBCTEFDSyBDSVJDTEUEC9xHUEFSRU5USEVTSVMEDJ1GUklHSFQgQ09STkVSCwOORlJPUAoMo1xIQUxGIEJSQUNLRVQKKez3B0pVU1RJRklFRCBMT1dFUiBMRUZUIFFVQVJURVIgQkxBQ0sgQ0lSQ0xFBA60R1NRVUFSRSBCUkFDS0VUBBbgR1RPUlRPSVNFIFNIRUxMIEJSQUNLRVQEGJ3qB1dJVEggVVBXQVJEUyBBUlJPVyBBQk9WRQIxweQHUlRPSVNFIFNIRUxMIEJSQUNLRVRFRCBDSksgVU5JRklFRCBJREVPR1JBUEgtNEUwOTECwuQHOEMvBMfkBzUyREQwA8PkB0I4OS8ExeQHNjI1MzADyOQHNTU3MAPA5Ac3MkMvBMTkBzcwQjkwA8bkBzZENxkWquIHTEFUSU4gQ0FQSVRBTCBMRVRURVIgUwIKsEZUQUwgUlVOT1VUAwqtxQdPIExFVFRFUiBBDQGrxQdFDAKRxQdCQQ0JrMUHUkVBVEhZIEFFFAGnxQdFFQGpxQdPFAGixQdJFQGkxQdVDAOaxQdDSEEMApPFB0RBDAGmxQdFDQGoxQdPDAKVxQdHQQwCnsUHSEEMAaHFB0kNAaPFB1UMAp3FB0pBDAKUxQdLQQwCoMUHTEEMApbFB01BDAKXxQdOQQ0CmMUHR0EMAarFB08MApDFB1BBDAKfxQdSQQwCmcUHU0EMApLFB1RBDAGlxQdVDAKcxQdXQQwCm8UHWUEFEK7FB1NJR04gUklTSU5HIFRPTkUBCLLrB1JBQ0tCQUxMBAOc7QdUT1IDDKJCREUgTUFSSyBTSUdOAwKG7QdJTgMBiu0HTQQEi+0HIENBUgMH11dOU1BMVVRPBRPbVVZFUlNBTCBJTlRFUlNFQ1RJT04CDI71B0VBU1VSRSBDSEVTVAMIvJ0HRSBTWU1CT0wCFcpTSUFOR0xFIFdJVEggRE9UIEFCT1ZFDg/G7QdST1VOREVEIENPUk5FUlMOEM1TU0VSSUZTIEFUIEJPVFRPTQ4Iy1NVTkRFUkJBUggYnU8tSEVBREVEIFJJR0hUV0FSRFMgQVJST1cGC6NAVUxBUiBCVUxMRVQLDKntB0ZMQUcgT04gUE9TVAsF0OkHUlVMRVIDBd1AQ09MT04DC7HqB0RFTlQgRU1CTEVNAw63TEdSQU0gRk9SIEVBUlRIDASyTEZJUkUMBrBMSEVBVkVODASxTExBS0UMCLZMTU9VTlRBSU4MB7NMVEhVTkRFUgwFtUxXQVRFUg0DtExJTkQDEvZVUExFIENPTE9OIE9QRVJBVE9SBwbLXERBR0dFUgcq6FRIT1JJWk9OVEFMIEJBUiBXSVRIIERPVUJMRSBWRVJUSUNBTCBTVFJPS0UbFulUVFJJUExFIFZFUlRJQ0FMIFNUUk9LRQcIrURJTlRFR1JBTAcT+FVORVNURUQgR1JFQVRFUi1USEFODgn3VUxFU1MtVEhBTgcE+1NQTFVTCAS0QFJJTUUHF/tVU09MSURVUyBCSU5BUlkgUkVMQVRJT04HBctEVElMREUHHPRVVkVSVElDQUwgQkFSIEJJTkFSWSBSRUxBVElPThQJgFNERUxJTUlURVIUD6pFUklHSFQgVFVSTlNUSUxFFBb1VVdJVEggSE9SSVpPTlRBTCBTVFJPS0UCA8zzB09MTAUFju0HRVlCVVMDBYr1B01CT05FAwPG5wdQSFkECvnmB0lDQUwgRFJJTksJBKDoB0ZJU0gCAqhFVUUEEN9XIExJR0hUIE1PT04gQVJUQQMEuucHTVBFVAEKrkFVR1JJSyBTSUdOAgO35gdMSVADGcmnBFUtVElHQUxBUkkgQVUgTEVOR1RIIE1BUksOCdCnBENPTkpPSU5FUg4F1KcEREFOREEPC9WnBE9VQkxFIERBTkRBDg/SpwRHRU1JTkFUSU9OIE1BUksOCICnBExFVFRFUiBBFgGBpwRBFgGOpwRJFgGRpwRVFQKopwRCQRYCqacESEEVApenBENBFgKYpwRIQRUCo6cEREEWAp6nBERBFwKfpwRIQRYCpKcESEEVAounBEVFFQKUpwRHQRYClacESEEVArKnBEhBFQGCpwRJFgGDpwRJFQKZpwRKQRYCmqcESEEVApKnBEtBFgKTpwRIQRUCracETEEWArOnBExBFwK1pwRMQRUCqqcETUEVAqWnBE5BFgKWpwRHQRYCoKcETkEWApunBFlBFQKQpwRPTxUCpqcEUEEWAqenBEhBFQKspwRSQRYCtKcEUkEVArGnBFNBFgKvpwRIQRYCsKcEU0EVAqGnBFRBFgKipwRIQRYCnKcEVEEXAp2nBEhBFQGEpwRVFgGFpwRVFQKupwRWQRYIiKcET0NBTElDIEweAYmnBEwdAYanBFIeAYenBFIVAqunBFlBDgXRpwRSRVBIQQ4NzKcEU0lHTiBBTlVTVkFSQRQHt6cEVkFHUkFIQRMQyqcEQ0FORFJBIEFOVU5BU0lLQRMNz6cETE9PUEVEIFZJUkFNQRML16cET00gUFVTSFBJS0ETBdOnBFBMVVRBEw7YpwRTSFJJSSBQVVNIUElLQRMGzqcEVklSQU1BFQXNpwRTQVJHQQ4T4qcEVkVESUMgVE9ORSBBTlVEQVRUQRkH4acEU1ZBUklUQQ8M", + "uKcET1dFTCBTSUdOIEFBGgHFpwRJGgHIpwRVGQLCpwRFRRkBuacESRoBuqcESRkCx6cET08ZAbunBFUaAbynBFUZCb+nBFZPQ0FMSUMgTCIBwKcETCEBvacEUiIBvqcEUgILw/IHTUJMRVIgR0xBU1MCBIPzB1JLRVkEDbpBSVNIIExJUkEgU0lHTgMNy0JORUQgQU1QRVJTQU5ECASiU05HTEUHDsJXQkxBQ0sgUEVOVEFHT04NC8pNU0hPR0kgUElFQ0UHCbJCQ0FQSVRBTCBGCASyXE9NTUEHBrhcREFHR0VSCAqLQ0lHSVQgVEhSRUUOAopDV08HF6lCR1JFRUsgU01BTEwgTEVUVEVSIElPVEEHGNbsB05PUlRIIEVBU1QgUE9JTlRJTkcgTEVBRg0S1OwHV0VTVCBQT0lOVElORyBMRUFGCQaZRlQgU0lHTgcMj+sHT0sgSEFORCBTSUdOBxTBQlNBTlMtU0VSSUYgQ0FQSVRBTCBHGgHCQkwaAcRCWQgItVxFTUlDT0xPTggGzkJNQUxMIEYIF9fsB09VVEggRUFTVCBQT0lOVElORyBMRUFGDRLV7AdXRVNUIFBPSU5USU5HIExFQUYHEclNV0hJVEUgU0hPR0kgUElFQ0UDA6LoB1RMRQEYuU5XRUxWRSBQT0lOVEVEIEJMQUNLIFNUQVICF4DqB0lTVEVEIFJJR0hUV0FSRFMgQVJST1dTAh7RQE8gQVNURVJJU0tTIEFMSUdORUQgVkVSVElDQUxMWQQMsOsHQlVUVE9OIE1PVVNFBBj1VENPTlNFQ1VUSVZFIEVRVUFMUyBTSUdOUwQKpUBET1QgTEVBREVSCAvaQFBVTkNUVUFUSU9OBxqqXFMgT1ZFUiBPTkUgRE9UIFBVTkNUVUFUSU9OBAaV6QdIRUFSVFMEGNVUSU5URVJTRUNUSU5HIExPR0lDQUwgQU5EGQLWVE9SBA7JU0pPSU5FRCBTUVVBUkVTBBSHVExPR0lDQUwgQU5EIE9QRVJBVE9SDAuIVE9SIE9QRVJBVE9SBBHs6AdNRU4gSE9MRElORyBIQU5EUwQaiJkHUklOR1MgQUxJR05FRCBIT1JJWk9OVEFMTFkEDurrB1NQRUVDSCBCVUJCTEVTBBPt6AdXT01FTiBIT0xESU5HIEhBTkRTAwi6XC1FTSBEQVNIABOThwRVR0FSSVRJQyBMRVRURVIgQUlOEQOAhwRMUEEQBIGHBEJFVEEQBYSHBERFTFRBEQOPhwRIQUwQBYKHBEdBTUxBEQSZhwRIQUlOEAKFhwRITxICiIcEVEEQAZuHBEkQA4uHBEtBRhECg4cESEEQBY2HBExBTURBEAOOhwRNRU0QA5CHBE5VThAClIcEUFUQBJaHBFFPUEEQBZeHBFJBU0hBEASVhwRTQURFEgOShwRNS0ERA4yHBEhJThECnYcEU1UQA4mHBFRFVBEFmIcESEFOTkERAZqHBE8QAZyHBFUQAoaHBFdPEAOKhwRZT0QQBIeHBFpFVEERAZGHBFUJDJ+HBFdPUkQgRElWSURFUgEHgkxNQlJFTExBCArxTSBPTiBHUk9VTkQJD5RMV0lUSCBSQUlOIERST1BTAQyS7AdOQU1VU0VEIEZBQ0UCDtFXQ0VSVEFJTlRZIFNJR04CBr9AREVSVElFAwiMR08gU1lNQk9MAgqE8wdJQ09STiBGQUNFAwKqRE9OBR3IVCBBQk9WRSBCQVIgQUJPVkUgSU5URVJTRUNUSU9ODAzGVElOVEVSU0VDVElPTgYcylRCRVNJREUgQU5EIEpPSU5FRCBXSVRIIFVOSU9OBg/FVFdJVEggTE9HSUNBTCBPUgsKwVRNSU5VUyBTSUdOCwfCVE9WRVJCQVIDCx9UIFNFUEFSQVRPUgQJ+ldFRCBTWU1CT0wDF/JMVkVSU0FMIFJFQ1lDTElORyBTWU1CT0wCGq9NTUFSUklFRCBQQVJUTkVSU0hJUCBTWU1CT0wBFr1TUCBBUlJPVyBUSFJPVUdIIENJUkNMRQgEg0ZIRUFEDBykRiBCRVRXRUVOIFRXTyBIT1JJWk9OVEFMIEJBUlMNErlXSU4gQSBSRUNUQU5HTEUgQk9YAyDRUkJBUkIgTEVGVCBET1dOIEJBUkIgTEVGVCBIQVJQT09OFw3NUlJJR0hUIEhBUlBPT04IHMxSUklHSFQgRE9XTiBCQVJCIExFRlQgSEFSUE9PThgNz1JSSUdIVCBIQVJQT09OAwqVQ0RPV04gQVJST1cNCqhDIFdJVEggQkFTRQgLjVZCTEFDSyBBUlJPVwgM1UNET1VCTEUgQVJST1cIENnwB1NBTlMtU0VSSUYgQVJST1cIFeVWVFJJQU5HTEUtSEVBREVEIEFSUk9XCAvzQ1dISVRFIEFSUk9XAwn+UkZJU0ggVEFJTAMX8EVSSUdIVCBESUFHT05BTCBFTExJUFNJUwMEpUVUQUNLBxLfTyBXSVRIIENJUkNMRSBBQk9WRQIk9ZgHLUZBQ0lORyBTTkFLRSBIRUFEIFdJVEggQ0xPU0VEIE1PVVRIGgrxmAdPUEVOIE1PVVRIAxHn7QdQT0lOVElORyBBSVJQTEFORQ0K4ZgHVE9NSUMgQk9NQgwL+ZgHRU5FUkdZIFdBVkUMBPubB0ZST0cMB4CYB0dPLUtBUlQMEebtB01JTElUQVJZIEFJUlBMQU5FDAqYmQdSQUNJTkcgQ0FSDQu66gdFRCBUUklBTkdMRQ0E5pgHSUZMRQ0K15gHT0NLRVQgU0hJUAwO6O0HU01BTEwgQUlSUExBTkUSDLzqB1JFRCBUUklBTkdMRQwd7UtUUklBTkdMRSBXSVRIIExFRlQgSEFMRiBCTEFDSxoQ7ktSSUdIVCBIQUxGIEJMQUNLAjbq9gdQRVIgQU5EIExFRlQgQU5EIExPV0VSIFRSSUFOR1VMQVIgVEhSRUUgUVVBUlRFUlMgQkxPQ0sLFYD3B09XRVIgT05FIEVJR0hUSCBCTE9DSxAVmvcHVFJJQU5HVUxBUiBIQUxGIEJMT0NLCi/o9gdSSUdIVCBBTkQgTE9XRVIgVFJJQU5HVUxBUiBUSFJFRSBRVUFSVEVSUyBCTE9DSwYOgU5CTEFERSBTQ0lTU09SUwYfkZ0HQ0VOVFJFIExFRlQgT05FIFNJWFRFRU5USCBCTE9DSxIOsZgHVFdFTEZUSCBDSVJDTEUNEeT3B09ORSBRVUFSVEVSIEJMT0NLDRmSnQdSSUdIVCBPTkUgU0lYVEVFTlRIIEJMT0NLEw6ymAdUV0VMRlRIIENJUkNMRQYShPcHRklWRSBFSUdIVEhTIEJMT0NLBgqAS0hBTEYgQkxPQ0sQJJH3ByBBTkQgTE9XRVIgSEFMRiBJTlZFUlNFIE1FRElVTSBTSEFERQsG4EtDSVJDTEULEoOcB0hFQVZZIFdISVRFIFNRVUFSRQspkvcHSU5WRVJTRSBNRURJVU0gU0hBREUgQU5EIExPV0VSIEhBTEYgQkxPQ0sTDNpLV0hJVEUgQ0lSQ0xFCxannQdMRUZUIE9ORSBRVUFSVEVSIEJMT0NLCwyO9wdNRURJVU0gU0hBREULF6ydB1JJR0hUIE9ORSBRVUFSVEVSIEJMT0NLCyOUnAdWRVJUSUNBTCBMSU5FIFdJVEggVEhSRUUgVElDSyBNQVJLUwY23fYHTEVGVCBCTE9DSyBESUFHT05BTCBMT1dFUiBDRU5UUkUgVE8gTE9XRVIgTUlERExFIFJJR0hUKhLf9gdVUFBFUiBNSURETEUgUklHSFQwBeH2B1JJR0hUIBre9gdMRUZUIFRPIExPV0VSIE1JRERMRSBSSUdIVCgM2/YHVVBQRVIgQ0VOVFJFLgzg9gdNSURETEUgUklHSFQgG9n2B01JRERMRSBMRUZUIFRPIFVQUEVSIENFTlRSRTUM3PYHTUlERExFIFJJR0hUNQXa9gdSSUdIVBoh1/YHVVBQRVIgTUlERExFIExFRlQgVE8gVVBQRVIgQ0VOVFJFNQXY9gdSSUdIVAsP1E9DT1JORVIgV0lUSCBET1QLE5CdB09ORSBTSVhURUVOVEggQkxPQ0sMI7BHUiBMT1dFUiBSSUdIVCBDVVJMWSBCUkFDS0VUIFNFQ1RJT04LFcaZB1FVQURSQU5UIENIRVNTIEJJU0hPUBoEupkHS0lORxsFypkHTklHSFQaBM6ZB1BBV04aBb6ZB1FVRUVOGgTCmQdST09LFQvcS0lSQ1VMQVIgQVJDFBWomQdGQUNFIFdJVEggQ0xPU0VEIEVZRVMeCaaZB09QRU4gRVlFUxQNtpkHTUlDUk9DT01QVVRFUhQP0pkHU1RBTkRJTkcgS05JR0hUFAqymQdURUxFVklTSU9ODgu1mAdSVEVSIENJUkNMRQsTmPcHVE8gTE9XRVIgUklHSFQgRklMTAwH+EtSSUFOR0xFERGc9wdVTEFSIE1FRElVTSBTSEFERQwNsJgHV0VMRlRIIENJUkNMRQYmlZ0HTUlERExFIENFTlRSRSBMRUZUIE9ORSBTSVhURUVOVEggQkxPQ0sUGZadB1JJR0hUIE9ORSBTSVhURUVOVEggQkxPQ0sNGJSdB0xFRlQgT05FIFNJWFRFRU5USCBCTE9DSxIOtJgHVFdFTEZUSCBDSVJDTEUNGZedB1JJR0hUIE9ORSBTSVhURUVOVEggQkxPQ0sTDreYB1RXRUxGVEggQ0lSQ0xFBhCUS09ORSBFSUdIVEggQkxPQ0sKDYL3B1FVQVJURVIgQkxPQ0sGNtL2B1JJR0hUIEJMT0NLIERJQUdPTkFMIExPV0VSIE1JRERMRSBMRUZUIFRPIExPV0VSIENFTlRSRTYF0/YHUklHSFQbIuT2B1VQUEVSIENFTlRSRSBUTyBMT1dFUiBNSURETEUgUklHSFQxBeb2B1JJR0hUKxLi9gdVUFBFUiBNSURETEUgUklHSFQhFNb2B0xFRlQgVE8gTE9XRVIgQ0VOVFJFLwzl9gdNSURETEUgUklHSFQpEuP2B1VQUEVSIE1JRERMRSBSSUdIVCEb1PYHTUlERExFIExFRlQgVE8gTE9XRVIgQ0VOVFJFNgzn9gdNSURETEUgUklHSFQ2BdX2B1JJR0hUDBrQTkRST1AtU0hBRE9XRUQgV0hJVEUgU1FVQVJFDBOTnQdPTkUgU0lYVEVFTlRIIEJMT0NLDSKxR1IgTE9XRVIgTEVGVCBDVVJMWSBCUkFDS0VUIFNFQ1RJT04MBpBOUEVOQ0lMDBXHmQdRVUFEUkFOVCBDSEVTUyBCSVNIT1AbBLuZB0tJTkccBcuZB05JR0hUGwTPmQdQQVdOGwW/mQdRVUVFThsEw5kHUk9PSxYL3UtJUkNVTEFSIEFSQxUVqZkHRkFDRSBXSVRIIENMT1NFRCBFWUVTHwmnmQdPUEVOIEVZRVMVDbeZB01JQ1JPQ09NUFVURVIVD9OZB1NUQU5ESU5HIEtOSUdIVBUKs5kHVEVMRVZJU0lPTg8LtpgHUlRFUiBDSVJDTEUMFb/qB1NIQURPV0VEIFdISVRFIENJUkNMRRsG0k5TUVVBUkUMEpn3B1RPIExPV0VSIExFRlQgRklMTA0H+UtSSUFOR0xFEhGd9wdVTEFSIE1FRElVTSBTSEFERQ0Ns5gHV0VMRlRIIENJUkNMRQYThvcHU0VWRU4gRUlHSFRIUyBCTE9DSwYTg/cHVEhSRUUgRUlHSFRIUyBCTE9DSwwOhfcHUVVBUlRFUlMgQkxPQ0sVFqadB0xFRlQgT05FIFFVQVJURVIgQkxPQ0sVF62dB1JJR0hUIE9ORSBRVUFSVEVSIEJMT0NLBxvt9gdSSUFOR1VMQVIgT05FIFFVQVJURVIgQkxPQ0sCDsPsB1NJREUtRE9XTiBGQUNFAgyVXFdBUkRTIEFOQ09SQQkEkUNSUk9XDRu49wcgQU5EIFJJR0hUIE9ORSBFSUdIVEggQkxPQ0sOCKVDRlJPTSBCQVIOHMVDTEVGVFdBUkRTIE9GIERPV05XQVJEUyBBUlJPVw4GklJUTyBCQVIOEt5DV0lUSCBET1VCTEUgU1RST0tFExWV8AdFUVVJTEFURVJBTCBBUlJPV0hFQUQTEYlSSE9SSVpPTlRBTCBTVFJPS0UTGInwB0xBUkdFIFRSSUFOR0xFIEFSUk9XSEVBRBMZhfAHTUVESVVNIFRSSUFOR0xFIEFSUk9XSEVBRBMMmfEHTk9UQ0hFRCBUQUlMExuR8AdTTUFMTCBFUVVJTEFURVJBTCBBUlJPV0hFQUQZEoHwB1RSSUFOR0xFIEFSUk9XSEVBRBMNsENUSVAgTEVGVFdBUkRTFwqxQ1JJR0hUV0FSRFMIC4ZWQkxBQ0sgQVJST1cOE4lXQ0lSQ0xFRCBXSElURSBBUlJPVwgQvfAHQ09NUFJFU1NFRCBBUlJPVwgM4UNEQVNIRUQgQVJST1cJC9FDT1VCTEUgQVJST1cIEbXwB0ZJTkdFUi1QT1NUIEFSUk9XCD/uUkhBUlBPT04gV0lUSCBCQVJCIExFRlQgQkVTSURFIERPV05XQVJEUyBIQVJQT09OIFdJVEggQkFSQiBSSUdIVCYf41JVUFdBUkRTIEhBUlBPT04gV0lUSCBCQVJCIFJJR0hUHwjgUkZST00gQkFSHwbYUlRPIEJBUh4Fv0NXQVJEUxoO3FJSSUdIVCBGUk9NIEJBUiAG1FJUTyBCQVIfBb5DV0FSRFMJCsXwB0VBVlkgQVJST1cOEMHwB0NPTVBSRVNTRUQgQVJST1cIDchDUEFJUkVEIEFSUk9XUwgP8E9RVUFEUlVQTEUgQVJST1cIBu3sB1JPQ0tFVAgQ0fAHU0FOUy1TRVJJRiBBUlJPVwkMufAHUVVBUkVEIEFSUk9XCBKR8QdUUklBTkdMRSBBUlJPV0hFQUQQDeFWLUhFQURFRCBBUlJPVx0tgVcgTEVGVFdBUkRTIE9GIERPV05XQVJEUyBUUklBTkdMRS1IRUFERUQgQVJST1ceBvFWVE8gQkFSHg+p8AdXSVRIIEJPTEQgU0hBRlQjGPtWRE9VQkxFIEhPUklaT05UQUwgU1RST0tFIwut8AdIRUFWWSBTSEFGVCMSoldMT05HIFRJUCBMRUZUV0FSRFMsCqNXUklHSFRXQVJEUyMMpfAHTUVESVVNIFNIQUZU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QU5VU1ZBUkELBu05VElSWUFLCwv2OVVQQURITUFOSVlBCxDlOVZJU0FSR0EgQU5VREFUVEEbCug5IFdJVEggVEFJTBMH4jlTVkFSSVRBEwbjOVVEQVRUQRkK5zkgV0lUSCBUQUlMCxrUOVlBSlVSVkVESUMgTUlETElORSBTVkFSSVRBBiXhOVRPTkUgQVRIQVJWQVZFRElDIElOREVQRU5ERU5UIFNWQVJJVEELDPQ5Q0FORFJBIEFCT1ZFEgXYOUJFTE9XCwndOURPVCBCRUxPVw0P+TlVQkxFIFJJTkcgQUJPVkUSB9o5U1ZBUklUQQsI0DlLQVJTSEFOQQ0O3DlUSEFLQSBBTlVEQVRUQQsH0jlQUkVOS0hBCyXgOVJJR1ZFRElDIEtBU0hNSVJJIElOREVQRU5ERU5UIFNWQVJJVEENCPg5TkcgQUJPVkULBdE5U0hBUkELEN85VEhSRUUgRE9UUyBCRUxPVwwN2zlSSVBMRSBTVkFSSVRBDA3eOVdPIERPVFMgQkVMT1cLKdU5WUFKVVJWRURJQyBBR0dSQVZBVEVEIElOREVQRU5ERU5UIFNWQVJJVEEWE9Y5SU5ERVBFTkRFTlQgU1ZBUklUQRYb1zlLQVRIQUtBIElOREVQRU5ERU5UIFNWQVJJVEExCtk5IFNDSFJPRURFUgIGo0JSU0lDTEUDH9BTVElDQUwgQkFSIEJFU0lERSBSSUdIVCBUUklBTkdMRQ0V5FVET1VCTEUgTEVGVCBUVVJOU1RJTEUNFuJVVFJJUExFIFJJR0hUIFRVUk5TVElMRQ0Wyk9XSVRIIEhPUklaT05UQUwgU1RST0tFCQmUmAdDQVBBQ0lUT1IJCO5FRUxMSVBTSVMJCd5ARk9VUiBET1RTCQedmQdHTy1LQVJUCRq7YElERU9HUkFQSElDIElURVJBVElPTiBNQVJLCRCxYEtBTkEgUkVQRUFUIE1BUksZC7VgIExPV0VSIEhBTEYaCrNgVVBQRVIgSEFMRhUWsmBXSVRIIFZPSUNFRCBTT1VORCBNQVJLKwu0YCBVUFBFUiBIQUxGCQaEmQdMQURERVIKA3xJTkUNCtBHIEVYVEVOU0lPTg4R71VXSVRIIENJUkNMRSBBQk9WRRoF8FVCRUxPVxMPkJkHRk9VUiBUSUNLIE1BUktTEwr/Rk1JRERMRSBET1QT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AwmgTU5JTkcgU0lHTgIJ0esHU1RFQkFTS0VUAgOaRlRDSAMKg+gHRVIgQlVGRkFMTwYGvu0HQ0xPU0VUBgS98gdQT0xPBgSK5gdXQVZFBQXJ5gdNRUxPTgIfv1ZWRSBBUlJPVyBQT0lOVElORyBESVJFQ1RMWSBMRUZUHQWzUlJJR0hUBQScYERBU0gDDvTnB0lORyBCTEFDSyBGTEFHBwnL6AdIQU5EIFNJR04HCvPnB1dISVRFIEZMQUcDBrBgWSBEQVNIBQSHRkxJTkUGB8/8A09XIExJTkUFCMv8A09WRVJMSU5FAhmS5gdYSU5HIENSRVNDRU5UIE1PT04gU1lNQk9MBxOU5gdHSUJCT1VTIE1PT04gU1lNQk9MAQ3A7AdFQVJZIENBVCBGQUNFBgSp7AdGQUNFAgWS6QdERElORwMavE9HRS1UQUlMRUQgUklHSFRXQVJEUyBBUlJPVwIbmEJJRVJTVFJBU1MgRUxMSVBUSUMgRlVOQ1RJT04DCsvnB0dIVCBMSUZURVICD/BMU1QgU1lSSUFDIENST1NTAQSL6AdIQUxFAgPe7QdFRUwFCrhMIE9GIERIQVJNQQUM/0xDSEFJUiBTWU1CT0wCGazxB0lURSBBUlJPVyBTSEFGVCBXSURUSCBPTkUYCq3xB1RXTyBUSElSRFMGBuZLQlVMTEVUBgvV9AdDSEVTUyBBTEZJTAwG10xCSVNIT1ASF4z0ByBST1RBVEVEIE5JTkVUWSBERUdSRUVTGxu29AdUV08gSFVORFJFRCBTRVZFTlRZIERFR1JFRVMMCsj0B0VRVUlIT1BQRVIWF8v0ByBST1RBVEVEIE5JTkVUWSBERUdSRUVTDATU9AdGRVJaDATUTEtJTkcQF4n0ByBST1RBVEVEIE5JTkVUWSBERUdSRUVTGRuz9AdUV08gSFVORFJFRCBTRVZFTlRZIERFR1JFRVMNBdhMTklHSFQSG4b0ByBST1RBVEVEIEZPUlRZLUZJVkUgREVHUkVFUxsOjfQHTklORVRZIERFR1JFRVMbH5v0B09ORSBIVU5EUkVEIFRISVJUWS1GSVZFIERFR1JFRVMbHcX0B1RIUkVFIEhVTkRSRUQgRklGVEVFTiBERUdSRUVTHBq39AdXTyBIVU5EUkVEIFNFVkVOVFkgREVHUkVFUycTsPQHVFdFTlRZLUZJVkUgREVHUkVFUxIH0PQHLUJJU0hPUBMFzvQHUVVFRU4TBM/0B1JPT0sMBNlMUEFXThAXjvQHIFJPVEFURUQgTklORVRZIERFR1JFRVMZG7j0B1RXTyBIVU5EUkVEIFNFVkVOVFkgREVHUkVFUwwF1UxRVUVFThEXivQHIFJPVEFURUQgTklORVRZIERFR1JFRVMaG7T0B1RXTyBIVU5EUkVEIFNFVkVOVFkgREVHUkVFUwwE1kxST09LEBeL9AcgUk9UQVRFRCBOSU5FVFkgREVHUkVFUxkbtfQHVFdPIEhVTkRSRUQgU0VWRU5UWSBERUdSRUVTDA2h9AdUVVJORUQgQklTSE9QEwSe9AdLSU5HFAWi9AdOSUdIVBMEo/QHUEFXThMFn/QHUVVFRU4TBKD0B1JPT0sHBctLSVJDTEUMHorvByBDT05UQUlOSU5HIEJMQUNLIFNNQUxMIENJUkNMRQ0Ohk1XSVRIIERPVCBSSUdIVBQI7FNXTiBBUlJPVxIT9UtMT1dFUiBMRUZUIFFVQURSQU5UGA72S1JJR0hUIFFVQURSQU5UEgiHTVRXTyBET1RTEhP0S1VQUEVSIExFRlQgUVVBRFJBTlQYDvdLUklHSFQgUVVBRFJBTlQHCOdMTFVCIFNVSVQHFOFPT05DQVZFLVNJREVEIERJQU1PTkQbFOJPIFdJVEggTEVGVFdBUkRTIFRJQ0shD+NPUklHSFRXQVJEUyBUSUNLBwnL9wdST1NTIE1BUksGB8dLRElBTU9ORA0gm+8HIENPTlRBSU5JTkcgQkxBQ0sgTUVESVVNIERJQU1PTkQfDchLU01BTEwgRElBTU9ORB8Smu8HVkVSWSBTTUFMTCBESUFNT05EDgnLTUlOIFNRVUFSRQ4E4kxTVUlUDhDQT1dJVEggQ0VOVFJFRCBET1QHG8foB09XTiBQT0lOVElORyBCQUNLSEFORCBJTkRFWBQFn0xJTkRFWBQPl+sHTEVGVCBIQU5EIElOREVYChi/Sy1QT0lOVElORyBTTUFMTCBUUklBTkdMRRQIvUtUUklBTkdMRQcMwU1SQVVHSFRTIEtJTkcPA8BNTUFOBhnVTkVYQ0xBTUFUSU9OIE1BUksgT1JOQU1FTlQGBJBNRkxBRwok/00gV0lUSCBIT1JJWk9OVEFMIE1JRERMRSBCTEFDSyBTVFJJUEUIBsBOT1JFVFRFCQOu6QdXRVIHEM5XT1VSIFBPSU5URUQgQ1VTUBMEp05TVEFSBwy5TFJPV05JTkcgRkFDRQYWq+sHSEFSRCBTSEVMTCBGTE9QUFkgRElTSwcEjfIHRUFSVAsF4UwgU1VJVAkNhU5WWSBDSEVDSyBNQVJLDBzA9wdTQUxUSVJFIFdJVEggUk9VTkRFRCBDT1JORVJTCAWhVlhBR09OBxGtVk9SSVpPTlRBTCBFTExJUFNFCAfWU1VSR0xBU1MGDJxWTEFSR0UgU1FVQVJFCAnG6gdUSU4gQ1JPU1MHDtlNRUZUIExBTkUgTUVSR0ULF8joB1BPSU5USU5HIEJBQ0tIQU5EIElOREVYFAWcTElOREVYChHFSy1QT0lOVElORyBQT0lOVEVSFA7DS1NNQUxMIFRSSUFOR0xFFAjBS1RSSUFOR0xFBxGGmQdPV0VSIExFRlQgUE9JTlRFUgwNh5kHUklHSFQgUE9JTlRFUggkoO8HWkVOR0UgQ09OVEFJTklORyBCTEFDSyBTTUFMTCBMT1pFTkdFBg6mVk1FRElVTSBESUFNT05EDQeoVkxPWkVOR0UNDP1LU01BTEwgU1FVQVJFDgX7S1FVQVJFDgPQVlRBUgcK3VdPT04gU0VMRU5BBgORTk5JQgYNsUtQQVJBTExFTE9HUkFNBwbx5wdFTk5BTlQJBaBWVEFHT04GFtROUVVFU1RJT04gTUFSSyBPUk5BTUVOVAYJrUtSRUNUQU5HTEUHHMnoB0lHSFQgUE9JTlRJTkcgQkFDS0hBTkQgSU5ERVgVBZ5MSU5ERVgLEtRWLVBPSU5USU5HIFBFTlRBR09OFga7S09JTlRFUhUOuUtTTUFMTCBUUklBTkdMRRUIt0tUUklBTkdMRQYIhE5TQ0lTU09SUwcJxvwDRVNBTUUgRE9UBwqWTEhPR0kgUElFQ0UHDKtWTUFMTCBMT1pFTkdFDAarS1NRVUFSRQ0D0lZUQVIICrpMSUxJTkcgRkFDRQcJ5ExQQURFIFNVSVQHBaFLUVVBUkUMB7PqByBCVVRUT04NHpXvB0NPTlRBSU5JTkcgQkxBQ0sgTUVESVVNIFNRVUFSRR4Mo0tTTUFMTCBTUVVBUkUeEZTvB1ZFUlkgU01BTEwgU1FVQVJFDRmFR1dJVEggQ0VOVFJFIFZFUlRJQ0FMIExJTkUSDuRPTEVGVFdBUkRTIFRJQ0sTEvFLT1dFUiBMRUZUIFFVQURSQU5UGA7yS1JJR0hUIFFVQURSQU5UEg/lT1JJR0hUV0FSRFMgVElDSxMOoktPVU5ERUQgQ09STkVSUxIT8EtVUFBFUiBMRUZUIFFVQURSQU5UGA7zS1JJR0hUIFFVQURSQU5UEhfrS1ZFUlRJQ0FMIEJJU0VDVElORyBMSU5FBwOGTFRBUgcCo+YHVU4JDaXmByBCRUhJTkQgQ0xPVUQWCqbmByBXSVRIIFJBSU4KCbxMV0lUSCBSQVlTDwuk5gdTTUFMTCBDTE9VRAYJj0xURUxFUEhPTkUHEv7qB09VQ0hUT05FIFRFTEVQSE9ORQcI4kdSQVBFWklVTQgmwU9JQU5HTEUgQ09OVEFJTklORyBTTUFMTCBXSElURSBUUklBTkdMRQcX101XTy1XQVkgTEVGVCBXQVkgVFJBRkZJQwYaxugHVVAgUE9JTlRJTkcgQkFDS0hBTkQgSU5ERVgSBZ1MSU5ERVgIEcr3By1QT0lOVElORyBDSEVWUk9OEg61S1NNQUxMIFRSSUFOR0xFEgizS1RSSUFOR0xFGgnsSyBXSVRIIERPVAYM/lVWRVJUSUNBTCBCQVIPB69WRUxMSVBTRQ8Jr0tSRUNUQU5HTEUYFIacByBXSVRIIEhPUklaT05UQUwgQkFSCQ6eVlkgU01BTEwgU1FVQVJFBRuzTy1GRUFUSEVSRUQgUklHSFRXQVJEUyBBUlJPVwEf6/AHSURFLUhFQURFRCBET1dOV0FS", + "RFMgQkFSQiBBUlJPVxYQ+/AHSEVBVlkgQkFSQiBBUlJPVxYQ4/AHTElHSFQgQkFSQiBBUlJPVxYR8/AHTUVESVVNIEJBUkIgQVJST1cWFYPxB1ZFUlkgSEVBVlkgQkFSQiBBUlJPVwwU6PAHTEVGVFdBUkRTIEJBUkIgQVJST1cWEPjwB0hFQVZZIEJBUkIgQVJST1cWEODwB0xJR0hUIEJBUkIgQVJST1cWEfDwB01FRElVTSBCQVJCIEFSUk9XFhWA8QdWRVJZIEhFQVZZIEJBUkIgQVJST1cMFe3wB05PUlRIIEVBU1QgQkFSQiBBUlJPVxcQ/fAHSEVBVlkgQkFSQiBBUlJPVxcQ5fAHTElHSFQgQkFSQiBBUlJPVxcR9fAHTUVESVVNIEJBUkIgQVJST1cXFYXxB1ZFUlkgSEVBVlkgQkFSQiBBUlJPVxIP7PAHV0VTVCBCQVJCIEFSUk9XFxD88AdIRUFWWSBCQVJCIEFSUk9XFxDk8AdMSUdIVCBCQVJCIEFSUk9XFxH08AdNRURJVU0gQkFSQiBBUlJPVxcVhPEHVkVSWSBIRUFWWSBCQVJCIEFSUk9XDBXq8AdSSUdIVFdBUkRTIEJBUkIgQVJST1cXEPrwB0hFQVZZIEJBUkIgQVJST1cXEOLwB0xJR0hUIEJBUkIgQVJST1cXEfLwB01FRElVTSBCQVJCIEFSUk9XFxWC8QdWRVJZIEhFQVZZIEJBUkIgQVJST1cMFe7wB1NPVVRIIEVBU1QgQkFSQiBBUlJPVxcQ/vAHSEVBVlkgQkFSQiBBUlJPVxcQ5vAHTElHSFQgQkFSQiBBUlJPVxcR9vAHTUVESVVNIEJBUkIgQVJST1cXFYbxB1ZFUlkgSEVBVlkgQkFSQiBBUlJPVxIP7/AHV0VTVCBCQVJCIEFSUk9XFxD/8AdIRUFWWSBCQVJCIEFSUk9XFxDn8AdMSUdIVCBCQVJCIEFSUk9XFxH38AdNRURJVU0gQkFSQiBBUlJPVxcVh/EHVkVSWSBIRUFWWSBCQVJCIEFSUk9XDBLp8AdVUFdBUkRTIEJBUkIgQVJST1cUEPnwB0hFQVZZIEJBUkIgQVJST1cUEOHwB0xJR0hUIEJBUkIgQVJST1cUEfHwB01FRElVTSBCQVJCIEFSUk9XFBWB8QdWRVJZIEhFQVZZIEJBUkIgQVJST1cC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9cACUA8B8sACVA8B88ACWA0BqsACRQ4Bq8ACUA4BqcACWA0BmMACSQ4BnMACRQ8BncACUA8BmsACVA8Bm8ACWA4BmcACUA4BlsACVA4Bl8ACWA0Bp8ACTw4BqMACUA4BpcACVA4BpsACWA0BrsACVQ4Bo8ACTw8BpMACUA8BosACWA4Br8ACUA4BscACUg8BsMACWA4BrMACVA4BrcACWA0BtMACWQ4BtcACUA4Bt8ACUg8BtsACWA4BssACVA4Bs8ACWAwCuMUCQ0EOAbnFAlAOAbbFAlQOAbfFAlgNAcLFAkUOAcPFAlAOAcHFAlgNAuPGAkhBDwHkxgJQDwHhxgJUDwHixgJYDgHvxgJFDwHwxgJQDwHtxgJUDwHuxgJYDgHrxgJPDwHsxgJQDwHpxgJUDwHqxgJYDgHyxgJVDwHnxgJPEAHoxgJQEAHlxgJUEAHmxgJYDwHzxgJQDwH1xgJSEAH0xgJYDwHxxgJYDgH4xgJZDwH5xgJQDwH7xgJSEAH6xgJYDwH2xgJUDwH3xgJYDQGwxQJJDgG0xQJFDwG1xQJQDwGyxQJUDwGzxQJYDgGxxQJQDgGuxQJUDgGvxQJYDQG/xQJPDgHAxQJQDgG9xQJUDgG+xQJYDQHGxQJVDgG7xQJPDwG8xQJQDwG6xQJYDgHHxQJQDgHJxQJSDwHIxQJYDgHExQJUDgHFxQJYDQHMxQJZDgHNxQJQDgHPxQJSDwHOxQJYDgHKxQJUDgHLxQJYDAKJwgJEQQ4BisICUA4Bh8ICVA4BiMICWA0Cv8ICREEPAcDCAlAPAb3CAlQPAb7CAlgOAcnCAkUPAcrCAlAPAcjCAlgOAbjCAkkPAbvCAkUQAbzCAlAQAbrCAlgPAbnCAlAPAbbCAlQPAbfCAlgOAcbCAk8PAcfCAlAPAcTCAlQPAcXCAlgOAc3CAlUPAcLCAk8QAcPCAlAQAcHCAlgPAc7CAlAPAdDCAlIQAc/CAlgPAcvCAlQPAczCAlgNAZLCAkUOAZPCAlAOAZHCAlgNAYLCAkkOAYXCAkUPAYbCAlAPAYTCAlgOAYPCAlAOAYDCAlQOAYHCAlgNAY/CAk8OAZDCAlAOAY3CAlQOAY7CAlgNAZbCAlUOAYzCAk8PAYvCAlgOAZfCAlAOAZnCAlIPAZjCAlgOAZTCAlQOAZXCAlgMAZTAAkUNAZPAAlgMAtPBAkZBDgHUwQJQDgHRwQJUDgHSwQJYDQHPwQJJDgHQwQJQDgHNwQJUDgHOwQJYDQHWwQJPDgHXwQJQDgHVwQJYDQHawQJVDgHbwQJQDgHdwQJSDwHcwQJYDgHYwQJUDgHZwQJYDQHgwQJZDgHhwQJQDgHewQJUDgHfwQJYDALkwwJHQQ4B5cMCUA4B4sMCVA4B48MCWA0B8MMCRQ4B8cMCUA4B7sMCVA4B78MCWA0CnMQCR0EPAZ3EAlAPAZrEAlQPAZvEAlgOAajEAkUPAanEAlAPAabEAlQPAafEAlgOAZbEAkkPAZjEAkUQAZnEAlAQAZfEAlgPAZTEAlQPAZXEAlgOAaTEAk8PAaXEAlAPAaLEAlQPAaPEAlgOAazEAlUPAaDEAk8QAaHEAlAQAZ7EAlQQAZ/EAlgPAa3EAlAPAa/EAlIQAa7EAlgPAarEAlQPAavEAlgNAdzDAkkOAeDDAkUPAeHDAlAPAd7DAlQPAd/DAlgOAd3DAlAOAdrDAlQOAdvDAlgNAezDAk8OAe3DAlAOAerDAlQOAevDAlgNAfTDAlUOAejDAk8PAenDAlAPAebDAlQPAefDAlgOAfXDAlAOAffDAlIPAfbDAlgOAfLDAlQOAfPDAlgMAvPEAkhBDgH0xAJQDgHxxAJUDgHyxAJYDQH+xAJFDgH/xAJQDgH9xAJYDQLwxAJJRQ8B78QCWA4B7sQCVA0CoMMCTEEPAaHDAlAPAZ7DAlQPAZ/DAlgOAanDAkUPAarDAlAPAajDAlgOAZnDAkkPAZzDAkUQAZ3DAlAQAZvDAlgPAZrDAlAPAZfDAlQPAZjDAlgOAabDAk8PAafDAlAPAaXDAlgOAa3DAlUPAaPDAk8QAaTDAlAQAaLDAlgPAa7DAlAPAbDDAlIQAa/DAlgPAavDAlQPAazDAlgOAbPDAlkPAbTDAlAPAbbDAlIQAbXDAlgPAbHDAlQPAbLDAlgNAprBAk1BDwGbwQJQDwGYwQJUDwGZwQJYDgGTwQJJDwGWwQJFEAGXwQJQEAGVwQJYDwGUwQJQDwGRwQJUDwGSwQJYDgGhwQJPDwGiwQJQDwGfwQJUDwGgwQJYDgGlwQJVDwGdwQJPEAGewQJQEAGcwQJYDwGmwQJQDwGowQJSEAGnwQJYDwGjwQJUDwGkwQJYDgGqwQJZDwGrwQJQDwGtwQJSEAGswQJYDwGpwQJYDQLywgJOQQ8B88ICUA8B8MICVA8B8cICWA4B+sICRQ8B+8ICUA8B+cICWA4B6sICSQ8B7sICRRAB78ICUBAB7MICVBAB7cICWA8B68ICUA8B6MICVA8B6cICWA4C+MICT1APAfbCAlQPAffCAlgOAvXCAlVPEAH0wgJYDwH8wgJUDQH7xAJPDgH8xAJQDgH5xAJUDgH6xAJYDQL3xAJVTw8B+MQCUA8B9cQCVA8B9sQCWA0C0MQCWEEPAdHEAlAPAc7EAlQPAc/EAlgOAdvEAkUPAdzEAlAPAdrEAlgOAcjEAkkPAczEAkUQAc3EAlAQAcrEAlQQAcvEAlgPAcnEAlAPAcbEAlQPAcfEAlgOAdjEAk8PAdnEAlAPAdbEAlQPAdfEAlgOAtTEAlVPEAHVxAJQEAHSxAJUEAHTxAJYDAGCwAJJDQGGwAJFDgGHwAJQDgGEwAJUDgGFwAJYDQGDwAJQDQGAwAJUDgyVwAJFUkFUSU9OIE1BUksNAYHAAlgMAuLHAkpJDgHmxwJFDwHnxwJQDwHkxwJUDwHlxwJYDgHjxwJQDgHgxwJUDgHhxwJYDQKayAJKSQ8BnsgCRRABn8gCUBABnMgCVBABncgCWA8Bm8gCUA8BmMgCVA8BmcgCWA4BpcgCTw8BpsgCUA8Bo8gCVA8BpMgCWA4BqcgCVQ8BocgCTxABosgCUBABoMgCWA8BqsgCUA8BrMgCUhABq8gCWA8Bp8gCVA8BqMgCWA4Br8gCWQ8BsMgCUA8BrcgCVA8BrsgCWA0B7scCTw4B78cCUA4B7McCVA4B7ccCWA0B8scCVQ4B6scCTw8B68cCUA8B6McCVA8B6ccCWA4B88cCUA4B9ccCUg8B9McCWA4B8McCVA4B8ccCWA0B+McCWQ4B+ccCUA4B+8cCUg8B+scCWA4B9scCVA4B98cCWAwCgcQCS0EOAYLEAlAOAf/DAlQOAYDEAlgNAYzEAkUOAY3EAlAOAYrEAlQOAYvEAlgNAfrDAkkOAf3DAkUPAf7DAlAPAfzDAlgOAfvDAlAOAfjDAlQOAfnDAlgNAYjEAk8OAYnEAlAOAYbEAlQOAYfEAlgNAZDEAlUOAYTEAk8PAYXEAlAPAYPEAlgOAZHEAlAOAZPEAlIPAZLEAlgOAY7EAlQOAY/EAlgMAsHDAkxBDgHCwwJQDgG/wwJUDgHAwwJYDQHMwwJFDgHNwwJQDgHLwwJYDQG5wwJJDgG9wwJFDwG+wwJQDwG7wwJUDwG8wwJYDgG6wwJQDgG3wwJUDgG4wwJYDQHJwwJPDgHKwwJQDgHHwwJUDgHIwwJYDQHQwwJVDgHFwwJPDwHGwwJQDwHDwwJUDwHEwwJYDgHRwwJQDgHTwwJSDwHSwwJYDgHOwwJUDgHPwwJYDQHWwwJZDgHXwwJQDgHZwwJSDwHYwwJYDgHUwwJUDgHVwwJYDAK3wQJNQQ4BuMECUA4BtcECVA4BtsECWA0BwsECRQ4BwcECWA0CtMQCR0EPAbXEAlAPAbLEAlQPAbPEAlgOAb7EAkUPAb/EAlAPAb3EAlgOArHEAklFEAGwxAJYDgG7xAJPDwG8xAJQDwG5xAJUDwG6xAJYDgHCxAJVDwG3xAJPEAG4xAJQEAG2xAJYDwHDxAJQDwHFxAJSEAHExAJYDwHAxAJUDwHBxAJYDQGwwQJJDgGzwQJFDwG0wQJQDwGywQJYDgGxwQJQDgGuwQJUDgGvwQJYDQG/wQJPDgHAwQJQDgG9wQJUDgG+wQJYDQHFwQJVDgG7wQJPDwG8wQJQDwG5wQJUDwG6wQJYDgHGwQJQDgHIwQJSDwHHwQJYDgHDwQJUDgHEwQJYDQHLwQJZDgHMwQJQDgHJwQJUDgHKwQJYDAKFwwJOQQ4BhsMCUA4BhMMCWA0C/8ACQkEPAYDBAlAPAf3AAlQPAf7AAlgOAfjAAkkPAfvAAkUQAfzAAlAQAfrAAlgPAfnAAlAPAfbAAlQPAffAAlgOAYPBAk8P", + "AYTBAlAPAYHBAlQPAYLBAlgOAYfBAlUPAYjBAlAPAYrBAlIQAYnBAlgPAYXBAlQPAYbBAlgOAY3BAlkPAY7BAlAPAZDBAlIQAY/BAlgPAYvBAlQPAYzBAlgNAtnCAkRBDwHawgJQDwHXwgJUDwHYwgJYDgHgwgJFDwHhwgJQDwHfwgJYDgHTwgJJDwHWwgJFEAHVwgJYDwHUwgJQDwHRwgJUDwHSwgJYDgHdwgJPDwHewgJQDwHbwgJUDwHcwgJYDgHkwgJVDwHlwgJQDwHnwgJSEAHmwgJYDwHiwgJUDwHjwgJYDQGPwwJFDgGQwwJQDgGOwwJYDQLixAJHQQ8B48QCUA8B4MQCVA8B4cQCWA4B7MQCRQ8B7cQCUA8B68QCWA4C3sQCSUUQAd/EAlAQAd3EAlgOAenEAk8PAerEAlAPAefEAlQPAejEAlgOAubEAlVPEAHkxAJUEAHlxAJYDQH/wgJJDgGCwwJFDwGDwwJQDwGBwwJYDgGAwwJQDgH9wgJUDgH+wgJYDQKzyAJKSQ8Bt8gCRRABuMgCUBABtcgCVBABtsgCWA8BtMgCUA8BscgCVA8BssgCWA4BvcgCTw8BvsgCUA8Bu8gCVA8BvMgCWA4BwMgCVQ8BusgCTxABucgCWA8BwcgCUA8Bw8gCUhABwsgCWA8Bv8gCWA4BxsgCWQ8Bx8gCUA8BycgCUhAByMgCWA8BxMgCVA8BxcgCWA0BjMMCTw4BjcMCUA4BisMCVA4Bi8MCWA0ClscCUkEPAZfHAlAPAZTHAlQPAZXHAlgOAZ3HAkUPAZ7HAlAPAZvHAlQPAZzHAlgOAZnHAk8PAZrHAlAPAZjHAlgOAaHHAlUPAaLHAlAPAaTHAlIQAaPHAlgPAZ/HAlQPAaDHAlgOAafHAlkPAajHAlAPAarHAlIQAanHAlgPAaXHAlQPAabHAlgNAZPDAlUOAYjDAk8PAYnDAlAPAYfDAlgOAZTDAlAOAZbDAlIPAZXDAlgOAZHDAlQOAZLDAlgNAszIAllJDwHQyAJFEAHRyAJQEAHOyAJUEAHPyAJYDwHNyAJQDwHKyAJUDwHLyAJYDgHXyAJPDwHYyAJQDwHVyAJUDwHWyAJYDgHbyAJVDwHTyAJPEAHUyAJQEAHSyAJYDwHcyAJQDwHZyAJUDwHayAJYDQL2xQJaQQ8B98UCUA8B9MUCVA8B9cUCWA4B/cUCRQ8B/MUCWA4B78UCSQ8B8sUCRRAB88UCUBAB8cUCWA8B8MUCUA8B7cUCVA8B7sUCWA4C+8UCT1APAfrFAlgOAf/FAlUPAfnFAk8QAfjFAlgPAYDGAlAPAYLGAlIQAYHGAlgPAf7FAlgOAYXGAlkPAYbGAlAPAYjGAlIQAYfGAlgPAYPGAlQPAYTGAlgMAZHAAk8NAZLAAlANAY/AAlQNAZDAAlgMAsHAAlBBDgHCwAJQDgG/wAJUDgHAwAJYDQG6wAJJDgG9wAJFDwG+wAJQDwG8wAJYDgG7wAJQDgG4wAJUDgG5wAJYDQHIwAJPDgHJwAJQDgHGwAJUDgHHwAJYDQHMwAJVDgHEwAJPDwHFwAJQDwHDwAJYDgHNwAJQDgHPwAJSDwHOwAJYDgHKwAJUDgHLwAJYDQHSwAJZDgHTwAJQDgHVwAJSDwHUwAJYDgHQwAJUDgHRwAJYDAL+xwJRSQ4BgsgCRQ8Bg8gCUA8BgMgCVA8BgcgCWA4B/8cCUA4B/McCVA4B/ccCWA0BisgCTw4Bi8gCUA4BiMgCVA4BicgCWA0BjsgCVQ4BhsgCTw8Bh8gCUA8BhMgCVA8BhcgCWA4Bj8gCUA4BkcgCUg8BkMgCWA4BjMgCVA4BjcgCWA0BlMgCWQ4BlcgCUA4Bl8gCUg8BlsgCWA4BksgCVA4Bk8gCWAwCyMcCUkEOAcnHAlAOAcbHAlQOAcfHAlgNAdLHAkUOAdPHAlAOAdHHAlgNAc/HAk8OAdDHAlAOAc3HAlQOAc7HAlgNAv3GAlJBDwH8xgJYDgGGxwJFDwGHxwJQDwGExwJUDwGFxwJYDgGCxwJPDwGDxwJQDwGAxwJUDwGBxwJYDgGKxwJVDwH/xgJPEAH+xgJYDwGLxwJQDwGNxwJSEAGMxwJYDwGIxwJUDwGJxwJYDgGQxwJZDwGRxwJQDwGTxwJSEAGSxwJYDwGOxwJUDwGPxwJYDQHWxwJVDgHLxwJPDwHMxwJQDwHKxwJYDgHXxwJQDgHZxwJSDwHYxwJYDgHUxwJUDgHVxwJYDQHcxwJZDgHdxwJQDgHfxwJSDwHexwJYDgHaxwJUDgHbxwJYDAKSxgJTQQ4Bk8YCUA4BkMYCVA4BkcYCWA0BnMYCRQ4BncYCUA4Bm8YCWA0CrccCSEEPAa7HAlAPAavHAlQPAazHAlgOAbjHAkUPAbnHAlAPAbbHAlQPAbfHAlgOAbTHAk8PAbXHAlAPAbLHAlQPAbPHAlgOAbzHAlUPAbDHAk8QAbHHAlAQAa/HAlgPAb3HAlAPAb/HAlIQAb7HAlgPAbrHAlQPAbvHAlgOAcLHAlkPAcPHAlAPAcXHAlIQAcTHAlgPAcDHAlQPAcHHAlgNAYvGAkkOAY7GAkUPAY/GAlAPAY3GAlgOAYzGAlAOAYnGAlQOAYrGAlgNAZnGAk8OAZrGAlAOAZfGAlQOAZjGAlgNArPGAlNBDwG0xgJQDwGxxgJUDwGyxgJYDgG6xgJFDwG7xgJQDwG5xgJYDgGsxgJJDwGvxgJFEAGwxgJQEAGuxgJYDwGtxgJQDwGqxgJUDwGrxgJYDgG3xgJPDwG4xgJQDwG1xgJUDwG2xgJYDgG+xgJVDwG/xgJQDwG8xgJUDwG9xgJYDgHCxgJZDwHDxgJQDwHFxgJSEAHExgJYDwHAxgJUDwHBxgJYDQGgxgJVDgGVxgJPDwGWxgJQDwGUxgJYDgGhxgJQDgGjxgJSDwGixgJYDgGexgJUDgGfxgJYDQGmxgJZDgGnxgJQDgGpxgJSDwGoxgJYDgGkxgJUDgGlxgJYDAKjwgJUQQ4BpMICUA4BocICVA4BosICWA0BrsICRQ4Br8ICUA4BrcICWA0BnMICSQ4Bn8ICRQ8BoMICUA8BnsICWA4BncICUA4BmsICVA4Bm8ICWA0Bq8ICTw4BrMICUA4BqcICVA4BqsICWA0BssICVQ4Bp8ICTw8BqMICUA8BpcICVA8BpsICWA4Bs8ICUA4BtcICUg8BtMICWA4BsMICVA4BscICWAwCjcACVU8OAY7AAlAOAYzAAlgMAuzBAlZBDgHtwQJQDgHqwQJUDgHrwQJYDQLzwQJFUA4B8sECWA0B5MECSQ4B6MECRQ8B6cECUA8B5sECVA8B58ECWA4B5cECUA4B4sECVA4B48ECWA0B8MECTw4B8cECUA4B7sECVA4B78ECWA0B9sECVQ4B98ECUA4B+cECUg8B+MECWA4B9MECVA4B9cECWA0B/MECWQ4B/cECUA4B/8ECUg8B/sECWA4B+sECVA4B+8ECWAwCgsUCV0EOAYPFAlAOAYDFAlQOAYHFAlgNAYvFAkUOAYzFAlAOAYrFAlgNAYjFAk8OAYnFAlAOAYfFAlgNAZXAAlUOAYXFAk8PAYbFAlAPAYTFAlgMAt/IAlhJDgHjyAJFDwHkyAJQDwHhyAJUDwHiyAJYDgHgyAJQDgHdyAJUDgHeyAJYDQHpyAJPDgHqyAJQDgHnyAJUDgHoyAJYDQLmyAJVTw8B5cgCWA0B7cgCWQ4B7sgCUA4B8MgCUg8B78gCWA4B68gCVA4B7MgCWAwC88gCWUkOAffIAkUPAfjIAlAPAfXIAlQPAfbIAlgOAfTIAlAOAfHIAlQOAfLIAlgNAf/IAk8OAYDJAlAOAf3IAlQOAf7IAlgNAYPJAlUOAfvIAk8PAfzIAlAPAfnIAlQPAfrIAlgOAYTJAlAOAYbJAlIPAYXJAlgOAYHJAlQOAYLJAlgNAYnJAlkOAYrJAlAOAYzJAlIPAYvJAlgOAYfJAlQOAYjJAlgMApbFAlpBDgGXxQJQDgGUxQJUDgGVxQJYDQGgxQJFDgGhxQJQDgGfxQJYDQLIxgJIQQ8BycYCUA8BxsYCVA8Bx8YCWA4B08YCRQ8B1MYCUA8B0cYCVA8B0sYCWA4Bz8YCTw8B0MYCUA8BzcYCVA8BzsYCWA4B18YCVQ8By8YCTxABzMYCUBABysYCWA8B2MYCUA8B2sYCUhAB2cYCWA8B1cYCVA8B1sYCWA4B3cYCWQ8B3sYCUA8B4MYCUhAB38YCWA8B28YCVA8B3MYCWA0Bj8UCSQ4BksUCRQ8Bk8UCUA8BkcUCWA4BkMUCUA4BjcUCVA4BjsUCWA0BncUCTw4BnsUCUA4Bm8UCVA4BnMUCWA0BpMUCVQ4BmcUCTw8BmsUCUA8BmMUCWA4BpcUCUA4Bp8UCUg8BpsUCWA4BosUCVA4Bo8UCWA0BqsUCWQ4Bq8UCUA4BrcUCUg8BrMUCWA4BqMUCVA4BqcUCWA0C2sUCWkEPAdvFAlAPAdjFAlQPAdnFAlgOAeDFAkUPAeHFAlAPAd/FAlgOAdLFAkkPAdbFAkUQAdfFAlAQAdTFAlQQAdXFAlgPAdPFAlAPAdDFAlQPAdHFAlgOAd3FAk8PAd7FAlAPAdzFAlgOAePFAlUPAeTFAlAPAebFAlIQAeXFAlgPAeLFAlgOAenFAlkPAerFAlAPAezFAlIQAevFAlgPAefFAlQPAejFAlgCBq9MTiBZQU5HAQSA9QdPLVlPABn/RVogTk9UQVRJT04gQkFHIE1FTUJFUlNISVALFuRURE9NQUlOIEFOVElSRVNUUklDVElPTgsUiVNMRUZUIEJJTkRJTkcgQlJBQ0tFVBANh1NJTUFHRSBCUkFDS0VUCxXlVFJBTkdFIEFOVElSRVNUUklDVElPTgwVvlRFTEFUSU9OQUwgQ09NUE9TSVRJT04MFIpTSUdIVCBCSU5ESU5HIEJSQUNLRVQRDYhTSU1BR0UgQlJBQ0tFVAsSn1RTQ0hFTUEgQ09NUE9TSVRJT04SBqBUUElQSU5HEwmhVFJPSkVDVElPTgwDgVNQT1QLCoJTVFlQRSBDT0xPTgEuxrQEQU5BQkFaQVIgU1FVQVJFIENMT1NJTkcgRE9VQkxFLUxJTkVEIEhFQUQgTUFSSxkJwLQESEVBRCBNQVJLExW9tARVU1RFUi1GSU5BTCBMRVRURVIgTEEmAry0BFJBJgK+tARWQSYCu7QEWUEZEbq0BElOSVRJQUwgTEVUVEVSIFJBERSztARGSU5BTCBDT05TT05BTlQgTUFSSxEexbQESU5JVElBTCBET1VCTEUtTElORUQgSEVBRCBNQVJLGQm/tARIRUFEIE1BUksRCam0BExFVFRFUiAtQRgBgLQEQRgCoLQEQkEZAqG0BEhBGAKQtARDQRkCkbQESEEYApu0BERBGQKWtAREQRoCl7QESEEZApy0BEhBGQKltARaQRoCprQESEEYAo20BEdBGQKOtARIQRgCsbQESEEYApK0BEpBGAKLtARLQRkCjLQESEEZA7K0BFNTQRgCrLQETEEYAqK0BE1BGAKdtAROQRkCj7QER0EZApi0BE5BGQKTtARZQRgCnrQEUEEZAp+0BEhBGAKrtARSQRgCsLQEU0EZAq60BEhBGQKvtARTQRgCmbQEVEEZApq0BEhBGQKjtARTQRoCpLQESEEZApS0BFRBGgKVtARIQRgCrbQEVkEYAqq0BFlBGAKotARaQRkCp7QESEEREMO0BE1BUksgRE9VQkxFIFNIQUQWCsS0BExPTkcgVFNIRUcWBMK0BFNIQUQWBcG0BFRTSEVHEQ24tARTSUdOIEFOVVNWQVJBFhS3tARDQU5EUkEgV0lUSCBPUk5BTUVOVBwFtbQEQklORFUhDra0BCBXSVRIIE9STkFNRU5UFga0tARWSVJBTUEYBbm0BFNBUkdBEgjHtARVQkpPSU5FUhERirQEVk9XRUwgTEVOR1RIIE1BUksXB4e0BFNJR04gQUkdAYi0BFUcAYS0BEUcAYG0BEkcAYa0BE8dAYW0BEUcCom0BFJFVkVSU0VEIEkcAYO0BFUdAYK0BEUBCZPzB0VCUkEgRkFDRQIPjUBSTyBXSURUSCBKT0lORVILDv/9A05PLUJSRUFLIFNQQUNFDQiMQE4tSk9JTkVSCwWLQFNQQUNFAgLiV1VTARCQ8gdJUFBFUi1NT1VUSCBGQUNFASm+ngdOQU1FTk5ZIENPTUJJTklORyBBVFRBQ0hJTkcgVkVSVElDQUwgT01FVBMbwZ4HTE9XRVIgVE9OQUwgUkFOR0UgSU5ESUNBVE9SEwykngdNQVJLIEJPUlpBWUEYB7ieB0NIQVNIS0EfCLmeByBQT0xOQVlBGQq/ngdVUlZFRCBPTUVUGBW0ngdERU1FU1RWRU5OWSBaQURFUlpIS0EZCb2eB1ZPRVRPQ0hJRRgVg54HR09SQVpETyBOSVpLTyBPTiBMRUZUKQWPngdSSUdIVCYRgJ4HUyBLUllaSEVNIE9OIExFRlQzBYyeB1JJR0hUIAafngdWWVNPS08YBqmeB0tBQ0hLQRkEwJ4HUllaSB0IrZ4HIE9OIExFRlQZBqieB1VQTkFZQRgFp54HTE9NS0EYFIaeB01BTE8gUE9WWVNIRSBPTiBMRUZUKAWSngdSSUdIVCUSiZ4HUyBLSE9LSExPTSBPTiBMRUZUMwWVngdSSUdIVCgGmZ4HUllaSEVNJgaengdUUkFOTk8YDYSeB05JWktPIE9OIExFRlQhBZCeB1JJR0hUHhGBngdTIEtSWVpIRU0gT04gTEVGVCsFjZ4HUklHSFQYCLqeB09CTEFDSEtPGQGhngdOGQe1ngdUU0VDSEtBGAq2ngdQT0RDSEFTSElFIhW3ngcgV0lUSCBWRVJUSUNBTCBTVFJPS0UbBqaeB1ZFUlRLQRoNh54HVllTSEUgT04gTEVGVCMFk54HUklHSFQgEoqeB1MgS0hPS0hMT00gT04gTEVGVC4Flp4HUklHSFQjBpueB1JZWkhFTSEGnJ4HVFJBTk5PGAWingdSQVZOTxoFrJ4HWlNFS0EYBaueB1NLT0JBGQ67ngdPUk9DSFlBIE5PWkhLQRkNhZ4HUkVETkUgT04gTEVGVCIFkZ4HUklHSFQZE5qeB1RSQU5OTyBNQUxPIFBPVllTSEUYB6OeB1RJS0hBWUEZBbyeB09DSEtBGQyCngdTQVRBIE9OIExFRlQhBY6eB1JJR0hUHgmYngdTIEtSWVpIRU0YBqWeB1VEQVJLQRgOiJ4HVllTT0tPIE9OIExFRlQiBZSeB1JJR0hUHxKLngdTIEtIT0tITE9NIE9OIExFRlQtBZeeB1JJR0hUIgadngdSWVpIRU0YCbOeB1pBREVSWkhLQRkDoJ4HRUxPGgOqngdWT0sTGLCeB1RPTkFMIFJBTkdFIE1BUksgTVJBQ0hOTyQGsZ4HU1ZFVExPJAmyngdUUkVTVkVUTE8JDe+eB05FVU1FIENIQVNIS0ERCNueB0VMWVVTVEtBDxL1ngdERU1FU1RWRU5OWSBLTFlVQ0gRBu2eB1JCSVRTQRAP654HT1VCTEUgWkFQWUFUQVlBEAPBnwdVREEQC9OeB1ZBIFYgQ0hFTE5VDwSDnwdGSVRBDw/engdHT0xVQkNISUsgQk9SWlkZB+CeB01SQUNITlkZBuGeB1NWRVRMWRkF354HVElLSFkaCOKeB1JFU1ZFVExZDwfungdLSEFNSUxPEAXUngdMWVVDSBAFhJ8HT0JZTEEQBNCeB1JZVUsUBtGeByBUSUtIWRICgZ8HWkgQBr+fB1VGSVNNQQ8Gp58HTUVDSElLFRSrnwcgS0xZVUNIRU5FUE9TVE9ZQU5OWR0Hqp8HUE9WT0ROWR0DqZ8HVk9ZFgeonwdQT1ZPRE5ZDwXCnwdORU1LQQ8GwJ8HT0JMQUtPEASvnwdTT0tBFBu0nwcgS0xZVUNIRVZBWUEgTkVQT1NUT1lBTk5B", + "WUEhCLOfB1NWRVRMQVlBFhKynwdSWVVLT1ZBWUEgU1ZFVExBWUEVCLCfB1NWRVRMQVlBFQuxnwdUUkVTVkVUTEFZQQ8F3J4HUEFMS0ERBtKeB1JBS0xJVBECw58HVUsQCNieB0VSRVZPREtBGA/ZngcgTkVQT1NUT1lBTk5BWUEQCfCeB09EQ0hBU0hJRREIkJ8HTEtVTElaTVkPE+yeB1JFVkVSU0VEIENIRUxZVVNUS0EQAoKfB09HDyL8ngdTS0FNRVlUU0EgRFZPRUNIRUxOQVlBIEtMWVVDSEVWQVlBJg77ngdORVBPU1RPWUFOTkFZQSYI+Z4HUFJPU1RBWUEmCPqeB1NWRVRMQVlBGRX3ngdLTFlVQ0hFTkVQT1NUT1lBTk5BWUEgDfaeB1ZBWUEgU1ZFVExBWUElB/ieB1RJS0hBWUEZCfGeB01SQUNITkFZQRkI8p4HU1ZFVExBWUEZB/SeB1RJS0hBWUEaCvOeB1JFU1ZFVExBWUEQCP2eB0xPWkhJVElFGAqAnwcgUyBLUllaSEVNGwj+ngdaQVBZQVRPWRkI/54HWkFLUllUT0UQBYafB1RBVFlBFQ+RnwcgTkVQT1NUT1lBTk5BWUEWEo6fB1MgRFZVTVlBIFpBUFlBVFlNSRgHiJ8HS1JZWkhFTR8Lip8HIEkgWkFQWUFUT1kYBY2fB1JPR09NGAiHnwdaQVBZQVRPWSAKiZ8HIEkgS1JZWkhFTSMLj58HUE9EQ0hBU0hJRU0WCYufB1pBS1JZVEFZQR8LjJ8HIFMgWkFQWUFUT1kRBtaeB09QSVRTQRcJ154HIFMgT0NIS09NGBTangdXSVRIIFNPUk9DSFlBIE5PWkhLQRERm58HUkVMQSBEVk9FQ0hFTE5BWUEiDJ6fByBLTFlVQ0hFVkFZQR8LnJ8HT0tSWVpIRVZBWUEgCZ2fB1BPVk9ETkFZQSkMn58HIEtMWVVDSEVWQVlBFgiinwdHUk9NTkFZQR4WoJ8HIFdJVEggU0lOR0xFIFpBUFlBVEFZQRoLpZ8HT0tSWVpIRVZBWUElCqafByBQT1ZPRE5BWUEbCaOfB1BPVk9ETkFZQSQWpJ8HIFdJVEggRE9VQkxFIFpBUFlBVEFZQSoQoZ8HU0lOR0xFIFpBUFlBVEFZQRYVmZ8HS0xZVUNIRU5FUE9TVE9ZQU5OQVlBHQmYnwdQT1ZPRE5BWUEXCbWfB1JZVUtPVkFZQSAJuZ8HIEdST01OQVlBKRa3nwcgV0lUSCBTSU5HTEUgWkFQWUFUQVlBJQu8nwdPS1JZWkhFVkFZQTAKvZ8HIFBPVk9ETkFZQSYJup8HUE9WT0ROQVlBLxa7nwcgV0lUSCBET1VCTEUgWkFQWUFUQVlBNRC4nwdTSU5HTEUgWkFQWUFUQVlBIQm2nwdQT1ZPRE5BWUEhB76fB1RSWUFTS0EZB5SfB1pIRVZBWUEWDpOfB01SQUNITk9USUtIQVlBFg6XnwdORVBPU1RPWUFOTkFZQRYNlZ8HUE9MVVBPVk9ETkFZQRgHlp8HVk9ETkFZQRcHkp8HUk9TVEFZQRYPmp8HVElLSEFZQSBQVVROQVlBFw2snwdSWUFTT0dMQVNOQVlBHAmtnwdQT1ZPRE5BWUEcCa6fB1NUUkVMTkFZQQ8e6J4HVlJBS0hJWUEgS0xZVUNIRVZBWUEgTVJBQ0hOQVlBJAjnngdQUk9TVEFZQSQI6Z4HU1ZFVExBWUEkC+qeB1RSRVNWRVRMQVlBGAnkngdNUkFDSE5BWUEYCOOeB1BST1NUQVlBGAjlngdTVkVUTEFZQRgL5p4HVFJFU1ZFVExBWUEPCNWeB1pBTk9aSEVLEQfdngdQWUFUQVlBEAaFnwdNRVlUU0EJH8SeB1BSSVpOQUsgTU9ESUZJRVIgRElSRUNUSU9OIEZMSVAaBcWeB0tSWVpIGgfCngdMRVZFTC0yIAHDngczGgPGngdST0cBBd/zB09NQklFAQKNQFdKAgT//QNOQlNQAwGMQEoCAotAU1A=", + }; + + private static final String[] NAMES; + private static final int[] CODE_POINTS; + + static { + byte[] data = Base64.getDecoder().decode(String.join("", ENCODED)); + Cursor cursor = new Cursor(); + int count = readVarint(data, cursor); + if (count != ENTRY_COUNT) { + throw new IllegalStateException("Invalid generated Perl scalar-name count: " + count); + } + NAMES = new String[count]; + CODE_POINTS = new int[count]; + String previous = ""; + for (int index = 0; index < count; index++) { + int prefixLength = readVarint(data, cursor); + int suffixLength = readVarint(data, cursor); + int codePoint = readVarint(data, cursor); + if (prefixLength > previous.length() + || suffixLength > data.length - cursor.offset) { + throw new IllegalStateException("Invalid generated Perl scalar-name data"); + } + String suffix = new String( + data, cursor.offset, suffixLength, StandardCharsets.US_ASCII); + cursor.offset += suffixLength; + String name = previous.substring(0, prefixLength) + suffix; + NAMES[index] = name; + CODE_POINTS[index] = codePoint; + previous = name; + } + if (cursor.offset != data.length) { + throw new IllegalStateException("Trailing generated Perl scalar-name data"); + } + } + + public static int codePoint(String name) { + if (name == null) return -1; + int index = Arrays.binarySearch(NAMES, name); + return index < 0 ? -1 : CODE_POINTS[index]; + } + + static int entryCount() { + return NAMES.length; + } + + private static int readVarint(byte[] data, Cursor cursor) { + int value = 0; + int shift = 0; + while (cursor.offset < data.length && shift < 35) { + int current = data[cursor.offset++] & 0xff; + value |= (current & 0x7f) << shift; + if ((current & 0x80) == 0) return value; + shift += 7; + } + throw new IllegalStateException("Invalid generated Perl scalar-name varint"); + } + + private static final class Cursor { + private int offset; + } + + private PerlUnicodeScalarNameData() { + } +} diff --git a/src/main/java/org/perlonjava/runtime/regex/RegexDiagnosticFormatter.java b/src/main/java/org/perlonjava/runtime/regex/RegexDiagnosticFormatter.java index 34bdb45566..229f19de24 100644 --- a/src/main/java/org/perlonjava/runtime/regex/RegexDiagnosticFormatter.java +++ b/src/main/java/org/perlonjava/runtime/regex/RegexDiagnosticFormatter.java @@ -11,7 +11,35 @@ static String marked(String pattern, int characterOffset, String message) { /** Renders the exact Perl form, including whitespace before the closing delimiter. */ static String markedPerl(String pattern, int characterOffset, String message) { - return marked(pattern, characterOffset, message, true); + return marked(pattern, characterOffset, + normalizePerlMessage(pattern, characterOffset, message), true); + } + + private static String normalizePerlMessage( + String pattern, int characterOffset, String message) { + if ("Sequence (?<... not terminated".equals(message) + && pattern != null && characterOffset > 0 + && characterOffset <= pattern.length()) { + char first = pattern.charAt(characterOffset - 1); + if (first != '_' && !Character.isLetterOrDigit(first)) { + return "Group name must start with a non-digit word character"; + } + } + return expandUselessModifier(message); + } + + private static String expandUselessModifier(String message) { + if (message == null || !message.startsWith("Useless (?") + || !message.endsWith(")")) { + return message; + } + int modifierIndex = message.length() - 2; + char modifier = message.charAt(modifierIndex); + if (modifier != 'c' && modifier != 'g' && modifier != 'o') return message; + boolean negative = modifierIndex > 9 + && message.charAt(modifierIndex - 1) == '-'; + return message + " - " + (negative ? "don't use" : "use") + " /" + + (modifier == 'c' ? "gc" : String.valueOf(modifier)) + " modifier"; } private static String marked(String pattern, int characterOffset, String message, diff --git a/src/main/java/org/perlonjava/runtime/regex/RegexFlags.java b/src/main/java/org/perlonjava/runtime/regex/RegexFlags.java index d07c13f602..9a0a7cd9e2 100644 --- a/src/main/java/org/perlonjava/runtime/regex/RegexFlags.java +++ b/src/main/java/org/perlonjava/runtime/regex/RegexFlags.java @@ -2,8 +2,6 @@ import org.perlonjava.runtime.runtimetypes.PerlCompilerException; -import static java.util.regex.Pattern.*; - /** * @param isGlobalMatch g flag - match globally (find all occurrences) * @param keepCurrentPosition c flag - continue matching from last match position @@ -121,39 +119,6 @@ static boolean hasInlinePreserveModifier(String pattern) { return false; } - public int toPatternFlags() { - int flags = 0; - - // UNIX_LINES ensures that . only excludes \n (not \r, \u0085, etc.) - // This matches Perl's behavior where . excludes only \n - flags |= UNIX_LINES; - - // /u flag enables Unicode semantics for \w, \d, \s - // /a flag (ASCII-restrict) disables Unicode semantics - if (isUnicode && !isAscii) { - flags |= UNICODE_CHARACTER_CLASS; - } - - if (isCaseInsensitive) { - flags |= CASE_INSENSITIVE; - // /a restricts character classes such as \w but retains Unicode - // case folding. Only /aa forbids ASCII/non-ASCII fold crossings. - if (!isAsciiStrict) { - flags |= UNICODE_CASE; - } - } - if (isMultiLine) { - flags |= MULTILINE; - } - if (isDotAll) { - flags |= DOTALL; - } - if (isExtended) { - flags |= COMMENTS; - } - return flags; - } - public RegexFlags with(String positiveFlags, String negativeFlags) { boolean newFlagN = this.isNonCapturing; boolean newIsCaseInsensitive = this.isCaseInsensitive; diff --git a/src/main/java/org/perlonjava/runtime/regex/RegexMarkers.java b/src/main/java/org/perlonjava/runtime/regex/RegexMarkers.java index 6f61e87932..329a1ded59 100644 --- a/src/main/java/org/perlonjava/runtime/regex/RegexMarkers.java +++ b/src/main/java/org/perlonjava/runtime/regex/RegexMarkers.java @@ -1,61 +1,66 @@ package org.perlonjava.runtime.regex; +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + /** - * Shared placeholder markers used by the string-interpolation parser to - * stand in for regex constructs that PerlOnJava cannot compile literally - * (because they require features unsupported by the underlying Java regex - * engine — e.g. arbitrary {@code (?{ CODE })} code blocks and - * {@code (??{ CODE })} recursive/dynamic patterns). - * - *

    The markers are emitted by {@code StringSegmentParser} when a code - * block can't be constant-folded. {@link RegexPreprocessor} detects them - * and reports "not implemented": - *

      - *
    • {@link #CODE_BLOCK} — a hard error under default die mode, - * or a no-op fallback only when {@link #CODE_BLOCK_NOOP_ENV} is set. - * Plain {@code JPERL_UNIMPLEMENTED=warn} still reports the unsupported - * feature without pretending the callback ran.
    • - *
    • {@link #RECURSIVE_PATTERN} — a hard error under default die mode, - * or a warning under {@code JPERL_UNIMPLEMENTED=warn} followed by - * the soft {@code (?:} fallback so the surrounding pattern still - * compiles (many CPAN modules build dynamic patterns that happen - * to work with the empty-group fallback; under warn mode we want - * tests to continue but the user must see a diagnostic).
    • - *
    - * - *

    Why these specific spellings? The preprocessor performs some - * {@code /i} case-fold expansions (notably for {@code K}↔{@code k}↔ - * Kelvin sign U+212A, {@code µ}↔U+00B5↔U+03BC, and {@code Å}↔ - * U+212B↔{@code å}) by rewriting matching code points into alternations. - * If the marker contained any of these "problem" letters it would be - * silently rewritten under {@code /i}, bypassing the detection check and - * leaving a garbled placeholder embedded in the compiled pattern (observed - * bug: {@code (?{UNIMPLEMENTED_CODE_BLOC(?:\QK\E|\Qk\E|\QK\E)})}). Keeping - * the markers free of {@code k}, {@code K}, {@code µ}, {@code å} (and - * their Unicode counterparts) guarantees the detection check always - * matches regardless of flags. + * Source-only markers that carry frontend regex diagnostics into native Joni + * compilation without changing executable pattern text. */ public final class RegexMarkers { /** - * Environment variable that permits non-constant {@code (?{ CODE })} - * blocks to compile as empty no-op groups. This is deliberately opt-in: - * normal PerlOnJava code must fail loudly because callbacks are not - * executed. + * Source-only marker for a literal {@code \\E} encountered without an + * active quote or case-modification region. The frontend consumes that + * escape, but RuntimeRegex still needs its provenance to emit Perl's + * construction-time diagnostic. It is removed before backend compilation. */ - public static final String CODE_BLOCK_NOOP_ENV = "JPERL_REGEX_CODE_BLOCK_NOOP"; + public static final String LITERAL_USELESS_CASE_ESCAPE = "\uFDD0\uFDEF"; - /** - * Marker for a {@code (?{ CODE })} code block that could not be - * constant-folded at parse time. Contains no fold-affected letters. - */ - public static final String CODE_BLOCK = "(?{UNIMPLEMENTED_CODE_BLOC})"; + private static final String LITERAL_DIAGNOSTIC_PREFIX = "\uFDD0\uFDD2"; + private static final String LITERAL_DIAGNOSTIC_SUFFIX = "\uFDD3\uFDEF"; + // Keep identity markers inside the byte domain. Their Latin-1 members + // preserve the source's lexical utf8 flag through literal materialization: + // byte source stays octets, while `use utf8` source stays Unicode. + private static final String LITERAL_IDENTITY_PREFIX = "\u001D\u00FE"; + private static final String LITERAL_IDENTITY_SUFFIX = "\u00FF\u001C"; + private static final Pattern LITERAL_DIAGNOSTIC = Pattern.compile( + Pattern.quote(LITERAL_DIAGNOSTIC_PREFIX) + "([A-Za-z0-9_-]+)" + + Pattern.quote(LITERAL_DIAGNOSTIC_SUFFIX)); + private static final Pattern LITERAL_IDENTITY = Pattern.compile( + Pattern.quote(LITERAL_IDENTITY_PREFIX) + "[0-9]+" + + Pattern.quote(LITERAL_IDENTITY_SUFFIX)); - /** - * Marker for a {@code (??{ CODE })} recursive/dynamic pattern that - * could not be constant-folded at parse time. Contains no - * fold-affected letters. - */ - public static final String RECURSIVE_PATTERN = "(??{UNIMPLEMENTED_RECURSIVE_PATTERN})"; + /** Distinguish two lexical custom-charname literals without changing matcher source. */ + public static String literalIdentity(long identity) { + return LITERAL_IDENTITY_PREFIX + Math.max(0, identity) + + LITERAL_IDENTITY_SUFFIX; + } + + /** Encode a frontend diagnostic while retaining the literal regex spelling. */ + public static String literalDiagnostic(String diagnostic) { + return LITERAL_DIAGNOSTIC_PREFIX + + Base64.getUrlEncoder().withoutPadding().encodeToString( + diagnostic.getBytes(StandardCharsets.UTF_8)) + + LITERAL_DIAGNOSTIC_SUFFIX; + } + + /** Return the first frontend diagnostic carried by a literal pattern. */ + public static String firstLiteralDiagnostic(String pattern) { + if (pattern == null) return null; + Matcher matcher = LITERAL_DIAGNOSTIC.matcher(pattern); + if (!matcher.find()) return null; + return new String(Base64.getUrlDecoder().decode(matcher.group(1)), + StandardCharsets.UTF_8); + } + + /** Remove all source-only diagnostic markers before backend compilation. */ + public static String stripLiteralDiagnostics(String pattern) { + if (pattern == null) return null; + return LITERAL_IDENTITY.matcher( + LITERAL_DIAGNOSTIC.matcher(pattern).replaceAll("")).replaceAll(""); + } private RegexMarkers() {} } diff --git a/src/main/java/org/perlonjava/runtime/regex/RegexPreprocessor.java b/src/main/java/org/perlonjava/runtime/regex/RegexPreprocessor.java deleted file mode 100644 index 2d7cfd83c4..0000000000 --- a/src/main/java/org/perlonjava/runtime/regex/RegexPreprocessor.java +++ /dev/null @@ -1,1792 +0,0 @@ -package org.perlonjava.runtime.regex; - -import com.ibm.icu.lang.UCharacter; -import org.perlonjava.runtime.operators.WarnDie; -import org.perlonjava.runtime.runtimetypes.GlobalVariable; -import org.perlonjava.runtime.runtimetypes.PerlCompilerException; -import org.perlonjava.runtime.runtimetypes.PerlJavaUnimplementedException; -import org.perlonjava.runtime.runtimetypes.RuntimeScalar; - -import java.util.LinkedHashSet; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import static java.lang.Character.isAlphabetic; - -/** - * The RegexPreprocessor class provides functionality to preprocess regular expressions - * to make them compatible with Java's regex engine. It handles various regex constructs - * and modifies them as necessary to adhere to Java's regex syntax requirements. - */ -public class RegexPreprocessor { - - // Regex escape rules: - // - // \[ as-is - // \120 becomes: \0120 - Java requires octal sequences to start with zero - // \0 becomes: \00 - Java requires the extra zero - // (?#...) inline comment is removed - // \N{name} named Unicode character or character sequence - // \N{U+263D} Unicode character - // \G \G is removed, it is handled separately - // - // inside [ ... ] - // space becomes: "\ " unless the /xx flag is used (flag_xx) - // \120 becomes: \0120 - Java requires octal sequences to start with zero - // \0 becomes: \00 - Java requires the extra zero - // \N{name} named Unicode character or character sequence - // \N{U+263D} Unicode character - // [:ascii:] becomes: \p{ASCII} - // [:^ascii:] becomes: \P{ASCII} - // \b is moved, Java doesn't support \b inside [...] - // [xx \b xx] becomes: (?:[xx xx]|\b) - Java doesn't support \b as a character - // - // WIP: - // named capture (? ... ) replace underscore in name - - private static final Map SPECIAL_SINGLE_CHAR_FOLDS = Map.of( - 0x00B5, 0x03BC, - 0x212A, 0x006B, - 0x212B, 0x00E5 - ); - private static final Map SPECIAL_SINGLE_CHAR_REVERSE_FOLDS = Map.of( - 0x03BC, 0x00B5, - 0x006B, 0x212A, - 0x00E5, 0x212B - ); - static int captureGroupCount; - static boolean deferredUnicodePropertyEncountered; - static boolean inlinePFlagEncountered; - /** - * Tracks named capture groups already emitted in the current pattern. - * Used to detect duplicate names like `(?a)|(?b)` (legal in Perl, - * rejected by Java). Duplicates get a synthetic suffix added by - * {@link #handleNamedCapture}; {@link CaptureNameEncoder#decodeGroupName} - * strips the suffix back off when reporting names to user code via - * `%+` / `%-`. - */ - static java.util.Set seenNamedCaptures = new java.util.HashSet<>(); - static java.util.Map> emittedNamedCaptures = new java.util.LinkedHashMap<>(); - static int duplicateNameCounter; - static List warningsOnUse = new ArrayList<>(); - private static final ThreadLocal EMIT_WARNINGS = ThreadLocal.withInitial(() -> true); - - static boolean shouldEmitWarnings() { - return EMIT_WARNINGS.get(); - } - - static void recordWarningOnUse(String message) { - warningsOnUse.add(message); - } - - static List getWarningsOnUse() { - return new ArrayList<>(warningsOnUse); - } - - static void markDeferredUnicodePropertyEncountered() { - deferredUnicodePropertyEncountered = true; - } - - static boolean hadDeferredUnicodePropertyEncountered() { - return deferredUnicodePropertyEncountered; - } - - static boolean hadInlinePFlag() { - return inlinePFlagEncountered; - } - - /** - * Preprocesses a given regex string to make it compatible with Java's regex engine. - * This involves handling various constructs and escape sequences that Java does not - * natively support or requires in a different format. - * - * @param s The regex string to preprocess. - * @param regexFlags The regex flags to use. - * @return A preprocessed regex string compatible with Java's regex engine. - * @throws PerlCompilerException If there are unmatched parentheses in the regex. - */ - static String preProcessRegex(String s, RegexFlags regexFlags) { - return preProcessRegex(s, regexFlags, true); - } - - static String preProcessRegex(String s, RegexFlags regexFlags, boolean emitWarnings) { - boolean previousEmitWarnings = EMIT_WARNINGS.get(); - EMIT_WARNINGS.set(emitWarnings); - try { - return preProcessRegexInternal(s, regexFlags); - } finally { - EMIT_WARNINGS.set(previousEmitWarnings); - } - } - - private static String preProcessRegexInternal(String s, RegexFlags regexFlags) { - if (s == null) { - s = ""; - } - captureGroupCount = 0; - deferredUnicodePropertyEncountered = false; - inlinePFlagEncountered = false; - seenNamedCaptures.clear(); - emittedNamedCaptures.clear(); - duplicateNameCounter = 0; - warningsOnUse.clear(); - - s = removeUnderscoresFromEscapes(s); - s = normalizeQuantifiers(s); - - // Expand multi-character case folds when case-insensitive flag is set - if (regexFlags.isCaseInsensitive() && !regexFlags.isAsciiStrict()) { - s = expandMultiCharFolds(materializeFoldableHexEscapes(s), regexFlags); - } - - StringBuilder sb = new StringBuilder(); - handleRegex(s, 0, sb, regexFlags, false); - return sb.toString(); - } - - private static int findRegularCharacterClassEnd(String pattern, int classStart) { - boolean escaped = false; - for (int i = classStart + 1; i < pattern.length(); i++) { - char ch = pattern.charAt(i); - if (escaped) { - escaped = false; - if (ch == 'c' && i + 1 < pattern.length()) { - i++; - } - continue; - } - if (ch == '\\') { - escaped = true; - continue; - } - // A POSIX character class such as [[:blank:]] has its own - // bracket pair inside the surrounding regular class. Do not - // mistake the POSIX closing bracket for the end of the outer - // class; otherwise /i preprocessing case-folds syntax letters - // (notably the k in "blank") as literal class contents. - if (ch == '[' && i + 1 < pattern.length() - && (pattern.charAt(i + 1) == ':' - || pattern.charAt(i + 1) == '.' - || pattern.charAt(i + 1) == '=')) { - char delimiter = pattern.charAt(i + 1); - String terminator = String.valueOf(delimiter) + ']'; - int nestedEnd = pattern.indexOf(terminator, i + 2); - if (nestedEnd >= 0) { - i = nestedEnd + 1; - continue; - } - } - if (ch == ']') { - return i; - } - } - return -1; - } - - /** - * Expand characters with multi-character case folds into alternations. - * For example: ß → (?:ß|ss|SS|Ss|sS) - * This is needed because Java's UNICODE_CASE flag doesn't handle multi-char folds. - */ - private static String expandMultiCharFolds(String pattern, RegexFlags regexFlags) { - StringBuilder result = new StringBuilder(); - int i = 0; - int len = pattern.length(); - boolean inCharClass = false; - boolean escaped = false; - - while (i < len) { - char ch = pattern.charAt(i); - - // Skip extended character classes (?[...]]) entirely - they handle their own case folding - if (!escaped && ch == '(' && i + 2 < len && pattern.charAt(i + 1) == '?' && pattern.charAt(i + 2) == '[') { - // Find the end of the extended char class - int depth = 1; - int j = i + 3; // Start after (?[ - while (j < len && depth > 0) { - char c = pattern.charAt(j); - if (c == '\\' && j + 1 < len) { - // Skip escaped character - j += 2; - continue; - } - if (c == ']' && j + 1 < len && pattern.charAt(j + 1) == ')') { - depth--; - if (depth == 0) { - break; - } - } - if (c == '(' && j + 2 < len && pattern.charAt(j + 1) == '?' && pattern.charAt(j + 2) == '[') { - depth++; - } - j++; - } - // Append (?[ ... ]) - the whole extended char class unchanged - result.append(pattern, i, j + 2); - i = j + 2; - continue; - } - - // POSIX/collating/equivalence-class tokens nested inside a - // regular character class are regex syntax, not literal class - // contents. Preserve the complete token before considering - // Unicode case-fold expansion of individual characters. - if (!escaped && inCharClass && ch == '[' && i + 1 < len - && (pattern.charAt(i + 1) == ':' - || pattern.charAt(i + 1) == '.' - || pattern.charAt(i + 1) == '=')) { - char delimiter = pattern.charAt(i + 1); - int nestedEnd = pattern.indexOf(String.valueOf(delimiter) + ']', i + 2); - if (nestedEnd >= 0) { - result.append(pattern, i, nestedEnd + 2); - i = nestedEnd + 2; - continue; - } - } - - // Track if we're inside a character class [...] - if (!escaped) { - if (ch == '[') { - int classEnd = findRegularCharacterClassEnd(pattern, i); - if (classEnd > i) { - String classExpansion = expandMultiCharFoldClass( - pattern.substring(i, classEnd + 1), regexFlags); - if (classExpansion != null) { - result.append(classExpansion); - i = classEnd + 1; - continue; - } - } - inCharClass = true; - } else if (ch == ']') { - inCharClass = false; - } - } - - // Skip the name of a named capture group / backreference. Group - // names are syntactic identifiers, not pattern text, so the fold - // expansion must not touch them — otherwise `(?...)` under /i - // becomes `(?...)` and Java rejects the resulting name. - if (!escaped && !inCharClass && ch == '(' && i + 2 < len - && pattern.charAt(i + 1) == '?' - && (pattern.charAt(i + 2) == '<' || pattern.charAt(i + 2) == '\'' - || (pattern.charAt(i + 2) == 'P' && i + 3 < len - && (pattern.charAt(i + 3) == '<' || pattern.charAt(i + 3) == '\'' || pattern.charAt(i + 3) == '=')))) { - // (?... | (?'name'... | (?P... | (?P'name'... | (?P=name) - int nameStart; - char closer; - if (pattern.charAt(i + 2) == 'P') { - if (pattern.charAt(i + 3) == '=') { - // (?P=name) — name terminates at ')' - nameStart = i + 4; - closer = ')'; - } else { - nameStart = i + 4; - closer = pattern.charAt(i + 3) == '<' ? '>' : '\''; - } - } else { - nameStart = i + 3; - closer = pattern.charAt(i + 2) == '<' ? '>' : '\''; - } - // Reject lookbehind: (?<= or (?' && nameStart < len - && (pattern.charAt(nameStart) == '=' || pattern.charAt(nameStart) == '!')) { - // Not a named capture; fall through to normal handling. - } else { - int closeIdx = pattern.indexOf(closer, nameStart); - if (closeIdx > nameStart) { - // Append the literal `(?` (or variant) verbatim, no folding. - result.append(pattern, i, closeIdx + 1); - i = closeIdx + 1; - continue; - } - } - } - - // Handle escape sequences - if (ch == '\\' && !escaped) { - escaped = true; - result.append(ch); - i++; - continue; - } - - // If this is an escaped character or we're in a char class, don't expand - if (escaped || inCharClass) { - if (!escaped && inCharClass) { - int codePoint = pattern.codePointAt(i); - String specialClassExpansion = expandSpecialSingleCharFoldInCharClass(codePoint); - if (specialClassExpansion != null) { - result.append(specialClassExpansion); - i += Character.charCount(codePoint); - continue; - } - } - - // Skip over \p{...}, \P{...}, \x{...}, \o{...} constructs without case folding - // Note: \N{...} is handled separately below - it needs case-folding for special chars - if (escaped && (ch == 'p' || ch == 'P' || ch == 'x' || ch == 'o') - && i + 1 < len && pattern.charAt(i + 1) == '{') { - result.append(ch); - i++; - // Now append everything up to and including the closing '}' - while (i < len && pattern.charAt(i) != '}') { - result.append(pattern.charAt(i)); - i++; - } - if (i < len) { - result.append(pattern.charAt(i)); // append '}' - i++; - } - escaped = false; - continue; - } - - // Handle \N{...} specially - resolve and apply case-folding if needed - if (escaped && ch == 'N' && i + 1 < len && pattern.charAt(i + 1) == '{') { - int endBrace = pattern.indexOf('}', i + 2); - if (endBrace != -1) { - String charName = pattern.substring(i + 2, endBrace).trim(); - try { - int codePoint = UnicodeResolver.getCodePointFromName(charName); - // Check if this character needs special case-fold expansion - String charClassExpansion = expandSpecialSingleCharFoldInCharClass(codePoint); - if (charClassExpansion != null) { - // Remove the backslash that was already appended - result.setLength(result.length() - 1); - if (inCharClass) { - // Inside regular [...], append chars directly - result.append(charClassExpansion); - } else { - // Not inside [...], wrap in character class - // This handles extended char class context like (?[ \N{KELVIN SIGN} ]) - result.append('[').append(charClassExpansion).append(']'); - } - } else { - // No special expansion needed, keep the original \N{...} - result.append(ch); - for (int j = i + 1; j <= endBrace; j++) { - result.append(pattern.charAt(j)); - } - } - i = endBrace + 1; - escaped = false; - continue; - } catch (IllegalArgumentException e) { - // Unknown character name, pass through as-is - result.append(ch); - i++; - escaped = false; - continue; - } - } - } - - result.append(ch); - escaped = false; - i++; - continue; - } - - // Check if this character has a multi-char fold - int codePoint = pattern.codePointAt(i); - if (!regexFlags.isAsciiStrict() && MultiCharFoldMapper.hasMultiCharFold(codePoint)) { - // Expand it (e.g., ß → (?:ß|ss|SS|Ss|sS)) - String expansion = MultiCharFoldMapper.expandToAlternation(codePoint); - result.append(expansion); - i += Character.charCount(codePoint); - } else { - // Check if we're at the start of a reverse fold sequence (e.g., ss → ß) - boolean foundReverseFold = false; - // Try longest sequences first (3, then 2 characters) - for (int seqLen = 3; seqLen >= 2 && !foundReverseFold; seqLen--) { - if (i + seqLen <= len) { - String sequence = pattern.substring(i, i + seqLen); - if (!regexFlags.isAsciiStrict() && MultiCharFoldMapper.hasReverseFold(sequence)) { - // Expand to include both the sequence and its reverse fold - result.append("(?:"); - result.append(sequence); - for (int reverseFoldChar : MultiCharFoldMapper.getReverseFolds(sequence)) { - result.append("|"); - result.appendCodePoint(reverseFoldChar); - } - result.append(")"); - i += seqLen; - foundReverseFold = true; - } - } - } - - if (!foundReverseFold) { - String specialExpansion = regexFlags.isAsciiStrict() ? null - : MultiCharFoldMapper.expandSimpleFoldToAlternation(codePoint); - if (specialExpansion == null && !regexFlags.isAsciiStrict()) { - specialExpansion = expandSpecialSingleCharFold(codePoint); - } - if (specialExpansion != null) { - result.append(specialExpansion); - } else { - result.appendCodePoint(codePoint); - } - i += Character.charCount(codePoint); - } - } - - escaped = false; - } - - return result.toString(); - } - - private static String expandMultiCharFoldClass(String charClass, RegexFlags regexFlags) { - if (regexFlags.isAsciiStrict() || charClass.length() < 3 || charClass.charAt(1) == '^') return null; - - LinkedHashSet folds = new LinkedHashSet<>(); - LinkedHashSet simpleVariants = new LinkedHashSet<>(); - boolean escaped = false; - for (int i = 1; i < charClass.length() - 1; ) { - int codePoint = charClass.codePointAt(i); - if (!escaped && codePoint == '\\') { - escaped = true; - i++; - continue; - } - if (escaped) { - escaped = false; - i += Character.charCount(codePoint); - continue; - } - if (codePoint == '-' || codePoint == '[' || codePoint == ']') return null; - String fold = MultiCharFoldMapper.getMultiCharFold(codePoint); - if (fold != null) folds.add(Pattern.quote(fold)); - simpleVariants.addAll(MultiCharFoldMapper.getSimpleFoldVariants(codePoint)); - i += Character.charCount(codePoint); - } - if (folds.isEmpty() && simpleVariants.isEmpty()) return null; - - StringBuilder expandedClass = new StringBuilder(charClass.substring(0, charClass.length() - 1)); - simpleVariants.forEach(expandedClass::appendCodePoint); - expandedClass.append(']'); - if (folds.isEmpty()) return expandedClass.toString(); - - StringBuilder expansion = new StringBuilder("(?:").append(expandedClass); - for (String fold : folds) expansion.append('|').append(fold); - return expansion.append(')').toString(); - } - - /** - * Materialize only hex escapes relevant to full case folds. Keeping all - * other escapes intact avoids turning escaped regex metacharacters into - * syntax while allowing sequences such as \x{73}\x{73} to be recognized - * as the reverse fold of sharp-s. - */ - private static String materializeFoldableHexEscapes(String pattern) { - StringBuilder result = new StringBuilder(pattern.length()); - for (int i = 0; i < pattern.length(); ) { - if (pattern.charAt(i) == '\\' && i + 3 < pattern.length() - && pattern.charAt(i + 1) == 'x' && pattern.charAt(i + 2) == '{') { - int close = pattern.indexOf('}', i + 3); - if (close > i + 3) { - try { - int codePoint = Integer.parseInt(pattern.substring(i + 3, close), 16); - if (Character.isValidCodePoint(codePoint) - && (MultiCharFoldMapper.hasMultiCharFold(codePoint) - || MultiCharFoldMapper.hasSimpleFold(codePoint) - || MultiCharFoldMapper.isFoldComponent(codePoint))) { - result.appendCodePoint(codePoint); - i = close + 1; - continue; - } - } catch (NumberFormatException ignored) { - // Leave malformed escapes to the normal regex parser. - } - } - } - int codePoint = pattern.codePointAt(i); - result.appendCodePoint(codePoint); - i += Character.charCount(codePoint); - } - return result.toString(); - } - - private static String expandSpecialSingleCharFold(int codePoint) { - // Compute full case fold for this code point. - int folded = UCharacter.foldCase(codePoint, true); - - // Trigger expansion only if this code point participates in one of the known problematic folds. - // We key off the folded form so that e.g. 'k' and 'K' will match Kelvin sign under /i. - if (!SPECIAL_SINGLE_CHAR_FOLDS.containsKey(codePoint) - && !SPECIAL_SINGLE_CHAR_REVERSE_FOLDS.containsKey(folded) - && !SPECIAL_SINGLE_CHAR_REVERSE_FOLDS.containsKey(codePoint)) { - return null; - } - - LinkedHashSet variants = new LinkedHashSet<>(); - variants.add(codePoint); - variants.add(folded); - - Integer reverse = SPECIAL_SINGLE_CHAR_REVERSE_FOLDS.get(folded); - if (reverse != null) { - variants.add(reverse); - } - Integer reverse2 = SPECIAL_SINGLE_CHAR_REVERSE_FOLDS.get(codePoint); - if (reverse2 != null) { - variants.add(reverse2); - } - - // Include upper/lower variants of all participating code points. - // This keeps behavior stable even if the Java regex engine doesn't map the special ones. - LinkedHashSet expanded = new LinkedHashSet<>(); - for (Integer cp : variants) { - expanded.add(cp); - expanded.add(UCharacter.toLowerCase(cp)); - expanded.add(UCharacter.toUpperCase(cp)); - expanded.add(UCharacter.foldCase(cp, true)); - } - - StringBuilder sb = new StringBuilder("(?:"); - boolean first = true; - for (Integer cp : expanded) { - if (!first) { - sb.append("|"); - } - first = false; - sb.append(Pattern.quote(new String(Character.toChars(cp)))); - } - sb.append(")"); - return sb.toString(); - } - - private static String expandSpecialSingleCharFoldInCharClass(int codePoint) { - int folded = UCharacter.foldCase(codePoint, true); - - if (!SPECIAL_SINGLE_CHAR_FOLDS.containsKey(codePoint) - && !SPECIAL_SINGLE_CHAR_REVERSE_FOLDS.containsKey(folded) - && !SPECIAL_SINGLE_CHAR_REVERSE_FOLDS.containsKey(codePoint)) { - return null; - } - - LinkedHashSet variants = new LinkedHashSet<>(); - variants.add(codePoint); - variants.add(folded); - - Integer reverse = SPECIAL_SINGLE_CHAR_REVERSE_FOLDS.get(folded); - if (reverse != null) { - variants.add(reverse); - } - Integer reverse2 = SPECIAL_SINGLE_CHAR_REVERSE_FOLDS.get(codePoint); - if (reverse2 != null) { - variants.add(reverse2); - } - - LinkedHashSet expanded = new LinkedHashSet<>(); - for (Integer cp : variants) { - expanded.add(cp); - expanded.add(UCharacter.toLowerCase(cp)); - expanded.add(UCharacter.toUpperCase(cp)); - expanded.add(UCharacter.foldCase(cp, true)); - } - - StringBuilder sb = new StringBuilder(); - for (Integer cp : expanded) { - appendCharClassLiteral(sb, cp); - } - return sb.toString(); - } - - private static void appendCharClassLiteral(StringBuilder sb, int codePoint) { - // Escape only the few metacharacters with special meaning inside [...]. - if (codePoint == '\\' || codePoint == ']' || codePoint == '-') { - sb.append('\\'); - } - sb.appendCodePoint(codePoint); - } - - /** - * Remove underscores from \x{...} and \o{...} escape sequences. - * Perl allows underscores in numeric literals for readability, but Java doesn't. - * Example: \x{_1_0000} becomes \x{10000} - */ - private static String removeUnderscoresFromEscapes(String pattern) { - StringBuilder result = new StringBuilder(); - int i = 0; - int len = pattern.length(); - - while (i < len) { - if (i + 2 < len && pattern.charAt(i) == '\\' && - (pattern.charAt(i + 1) == 'x' || pattern.charAt(i + 1) == 'o') && - pattern.charAt(i + 2) == '{') { - // Found \x{ or \o{ - result.append(pattern.charAt(i)); // \ - result.append(pattern.charAt(i + 1)); // x or o - result.append('{'); - i += 3; - - // Copy content until }, removing underscores - while (i < len && pattern.charAt(i) != '}') { - char ch = pattern.charAt(i); - if (ch != '_') { - result.append(ch); - } - i++; - } - - if (i < len) { - result.append('}'); // Closing brace - i++; - } - } else { - result.append(pattern.charAt(i)); - i++; - } - } - - return result.toString(); - } - - /** - * Normalize quantifiers to Java regex format. - * Perl allows {,n} to mean {0,n} (omitting minimum). - * Perl allows spaces inside quantifiers like {2, 5} or { , 2 }. - * Java requires explicit {0,n} and no spaces (unless in /x mode). - * Example: {,2} becomes {0,2}, { , 2 } becomes {0,2} - */ - private static String normalizeQuantifiers(String pattern) { - StringBuilder result = new StringBuilder(); - int i = 0; - int len = pattern.length(); - boolean inCharClass = false; - boolean escaped = false; - - while (i < len) { - char ch = pattern.charAt(i); - - if (escaped) { - result.append(ch); - escaped = false; - i++; - continue; - } - - if (ch == '\\') { - result.append(ch); - escaped = true; - i++; - continue; - } - - if (ch == '[') { - inCharClass = true; - result.append(ch); - i++; - continue; - } - - if (ch == ']' && inCharClass) { - inCharClass = false; - result.append(ch); - i++; - continue; - } - - if (ch == '{' && !inCharClass) { - // Potential quantifier - int start = i; - i++; - StringBuilder quantifier = new StringBuilder(); - - // Read the quantifier content - while (i < len && pattern.charAt(i) != '}') { - quantifier.append(pattern.charAt(i)); - i++; - } - - if (i < len && pattern.charAt(i) == '}') { - // We have a complete quantifier - String content = quantifier.toString().trim(); - - // Check if it's a {,n} pattern or has spaces - if (content.matches("\\s*,\\s*\\d+\\s*")) { - // {,n} pattern - add 0 at the start - content = content.replaceAll("\\s*,\\s*(\\d+)\\s*", "0,$1"); - result.append('{').append(content).append('}'); - i++; - } else if (content.contains(",") && content.matches(".*\\s+.*")) { - // Has comma and spaces - remove spaces - content = content.replaceAll("\\s+", ""); - result.append('{').append(content).append('}'); - i++; - } else { - // Normal quantifier, keep as-is - result.append('{').append(quantifier).append('}'); - i++; - } - } else { - // Unclosed {, not a quantifier - keep as-is - result.append('{').append(quantifier); - } - } else { - result.append(ch); - i++; - } - } - - return result.toString(); - } - - /** - * Preprocesses a given regex string to make it compatible with Java's regex engine. - * This involves handling various constructs and escape sequences that Java does not - * natively support or requires in a different format. - * - * @param s The regex string to preprocess. - * @param offset The position in the string. - * @param sb The string builder to append the preprocessed regex to. - * @param regexFlags The regex flags to use. - * @param stopAtClosingParen A flag indicating whether to stop processing at the first closing parenthesis. - * @return The position in the string after the preprocessed regex. - * @throws PerlCompilerException If there are unmatched parentheses in the regex. - */ - static int handleRegex(String s, int offset, StringBuilder sb, RegexFlags regexFlags, boolean stopAtClosingParen) { - final int length = s.length(); - boolean lastWasQuantifiable = false; // Track if the last thing can be quantified - - // Remove \G from the pattern string for Java compilation - if (s.startsWith("\\G", offset)) { - offset += 2; - // Also strip any quantifier that followed \G (e.g. \G? in (\G?[ac])?) - // Since \G is a zero-width assertion, \G? is effectively nothing - if (offset < length) { - char next = s.charAt(offset); - if (next == '?' || next == '*' || next == '+') { - offset++; - } - } - } - - while (offset < length) { - final int c = s.codePointAt(offset); - boolean isQuantifier = false; - - switch (c) { - case '*': - case '+': - case '?': - // Check if the previous item can be quantified - if (!lastWasQuantifiable) { - // Distinguish "Nested quantifiers" from "Quantifier follows nothing": - // If the last char in sb is a quantifier, this is a nested quantifier - if (sb.length() > 0) { - char lc = sb.charAt(sb.length() - 1); - boolean esc = sb.length() >= 2 && sb.charAt(sb.length() - 2) == '\\'; - if (!esc && (lc == '*' || lc == '+' || lc == '?' || lc == '}')) { - regexError(s, offset + 1, "Nested quantifiers"); - } - } - regexError(s, offset + 1, "Quantifier follows nothing"); - } - - // Check if this might be a possessive quantifier - boolean isPossessive = offset + 1 < length && s.charAt(offset + 1) == '+'; - - // Check if this might be a non-greedy quantifier - boolean isNonGreedy = offset + 1 < length && s.charAt(offset + 1) == '?'; - - // Check for nested quantifiers (but not possessive or non-greedy) - if (!isPossessive && !isNonGreedy && sb.length() > 0) { - char lastChar = sb.charAt(sb.length() - 1); - // Also check if the previous character was a backslash (escaped) - boolean isEscaped = sb.length() >= 2 && sb.charAt(sb.length() - 2) == '\\'; - if (!isEscaped && (lastChar == '*' || lastChar == '+' || lastChar == '?')) { - regexError(s, offset + 1, "Nested quantifiers"); - } - } - - sb.append(Character.toChars(c)); - - // If possessive or non-greedy, also append the following character - if (isPossessive) { - sb.append('+'); - offset++; // Skip the extra + - lastWasQuantifiable = false; // Can't quantify a possessive quantifier - } else if (isNonGreedy) { - sb.append('?'); - offset++; // Skip the extra ? - lastWasQuantifiable = false; // Can't quantify a non-greedy quantifier - } else { - lastWasQuantifiable = false; // Regular quantifier - } - break; - - case '\\': // Handle escape sequences - offset = RegexPreprocessorHelper.handleEscapeSequences(s, sb, c, offset, regexFlags); - lastWasQuantifiable = true; - break; - - case '[': // Handle character classes - offset = handleCharacterClass(s, regexFlags.isExtendedWhitespace(), sb, c, offset); - lastWasQuantifiable = true; // Character classes can be quantified - break; - - case '(': - offset = handleParentheses(s, offset, length, sb, c, regexFlags, stopAtClosingParen); - lastWasQuantifiable = true; - break; - - case ')': - if (stopAtClosingParen) { - return offset; - } - regexError(s, offset, "Unmatched ) in regex"); - break; - - case '#': - if (regexFlags.isExtended() || regexFlags.isExtendedWhitespace()) { - // Consume comment to end of line - while (offset < length) { - if (s.codePointAt(offset) == '\n') { - break; - } - offset++; - } - break; - } else { - sb.append(Character.toChars(c)); - lastWasQuantifiable = true; - break; - } - - case '{': - // Only treat '{' as a quantifier if the previous item is quantifiable. - // Otherwise, '{' must be a literal (Perl allows literal braces). - if (!lastWasQuantifiable) { - // Literal '{' (not a quantifier), escape for Java regex - sb.append("\\{"); - lastWasQuantifiable = true; - } else { - // Parse as quantifier (may return literal braces if invalid quantifier) - int[] quantResult = handleQuantifier(s, offset, sb); - offset = quantResult[0]; - boolean wasLiteral = quantResult[1] != 0; - - if (wasLiteral) { - // Braces were treated as literal (e.g., {} or {,}) - // The escaped \} is quantifiable - lastWasQuantifiable = true; - } else { - // Valid quantifier - // Check for possessive quantifier {n,m}+ - if (offset + 1 < length && s.charAt(offset + 1) == '+') { - sb.append('+'); - offset++; // Skip the extra + - } - // Check for non-greedy quantifier {n,m}? - else if (offset + 1 < length && s.charAt(offset + 1) == '?') { - sb.append('?'); - offset++; // Skip the extra ? - } - - isQuantifier = true; - lastWasQuantifiable = false; // Can't quantify a quantifier - } - } - break; - - case '^': - sb.append(Character.toChars(c)); - lastWasQuantifiable = false; // Can't quantify anchors - break; - - case '|': - sb.append(Character.toChars(c)); - lastWasQuantifiable = false; // Next item starts fresh - break; - - default: // Append normal characters - sb.append(Character.toChars(c)); - lastWasQuantifiable = true; - break; - } - - // Check for nested quantifiers - if (isQuantifier && offset + 1 < length) { - char nextChar = s.charAt(offset + 1); - // Don't flag *+, ++, ?+ as nested quantifiers (they're possessive) - // Don't flag *?, +?, ??, }? as nested quantifiers (they're non-greedy) - boolean isModifier = (nextChar == '+' || nextChar == '?'); - if (!isModifier && (nextChar == '*' || nextChar == '+' || nextChar == '?')) { - regexError(s, offset + 2, "Nested quantifiers"); - } - // For '{', only flag as nested if it's actually a valid quantifier - if (nextChar == '{' && isValidQuantifierAt(s, offset + 1)) { - regexError(s, offset + 2, "Nested quantifiers"); - } - } - - offset += Character.charCount(c); - } - - return offset; - } - - static void regexError(String s, int offset, String errMsg) { - if (offset > s.length()) { - offset = s.length(); - } - - - // "Error message in regex; marked by <-- HERE in m/regex <-- HERE remaining/" - String before = s.substring(0, offset); - String after = s.substring(offset); - - // When marker is at the end, no space before <-- HERE - String marker = after.isEmpty() ? " <-- HERE" : " <-- HERE "; - - throw new PerlCompilerException(errMsg + " in regex; marked by <-- HERE in m/" + - before + marker + after + "/"); - } - - private static int handleParentheses(String s, int offset, int length, StringBuilder sb, int c, RegexFlags regexFlags, boolean stopAtClosingParen) { - // Check for incomplete (? - if (offset + 1 >= length) { - regexError(s, offset + 1, "Sequence (? incomplete"); - } - - int c2 = s.codePointAt(offset + 1); - - // Check for (*...) verb patterns FIRST, before checking (? - if (c2 == '*') { - // Java-backend compatibility for (*...) control verbs such as - // (*FAIL). Alpha assertions are routed to Joni before preprocessing. - - // Find the verb name (up to ':' or ')') - int verbNameEnd = offset + 2; - while (verbNameEnd < length) { - int cp = s.codePointAt(verbNameEnd); - if (cp == ':' || cp == ')') break; - verbNameEnd++; - } - String verbName = s.substring(offset + 2, verbNameEnd); - - // Perl's (*FAIL) / (*F) is a zero-width assertion that can never - // succeed. Java's empty negative lookahead has exactly that - // declarative behavior and preserves surrounding backtracking. - if ((verbName.equals("FAIL") || verbName.equals("F")) - && verbNameEnd < length && s.codePointAt(verbNameEnd) == ')') { - sb.append("(?!)"); - return verbNameEnd; - } - - // Find the end of the verb for error reporting - int verbEnd = offset + 2; - while (verbEnd < length && s.codePointAt(verbEnd) != ')') { - verbEnd++; - } - if (verbEnd < length) { - verbEnd++; // Include the closing paren - } - - // Extract the verb name for error reporting - String verb = s.substring(offset, Math.min(verbEnd, length)); - - // Replace with empty non-capturing group as placeholder - sb.append("(?:)"); - - // Throw error that can be caught by JPERL_UNIMPLEMENTED=warn - regexUnimplemented(s, offset + 2, - "Regex control verb " + verb + " not implemented"); - - return verbEnd; // Skip past the entire verb construct - } else if (c2 == '?') { - if (offset + 2 >= length) { - // Marker should be after the ? - regexError(s, offset + 2, "Sequence (? incomplete"); - } - - int c3 = s.codePointAt(offset + 2); - - // For sequences that need a 4th character - int c4 = (offset + 3 < length) ? s.codePointAt(offset + 3) : -1; - - if (c3 == '#') { - // Remove inline comments (?# ... ) - offset = handleSkipComment(offset, s, length); - // Comment is completely removed - don't append anything, just return - return offset; // offset points to ')', caller will increment past it - } else if (c3 == '@') { - // Handle (?@...) which is not implemented - regexUnimplemented(s, offset + 3, "Sequence (?@...) not implemented"); - } else if (c3 == '{') { - // Check if this is our special unimplemented marker - if (s.startsWith(RegexMarkers.CODE_BLOCK, offset)) { - if (!regexFlags.allowEvalGroup()) { - if (allowRegexCodeBlockNoop()) { - regexUnimplementedSoft(s, offset + 2, - "Eval-group not allowed at runtime, use re 'eval'"); - } else if (isUnimplementedWarnMode()) { - regexUnimplemented(s, offset + 2, - "Eval-group not allowed at runtime, use re 'eval'"); - } else { - regexError(s, offset + 2, - "Eval-group not allowed at runtime, use re 'eval'"); - } - } - sb.append("(?:"); - offset = offset + RegexMarkers.CODE_BLOCK.length() - 1; - } else { - // Handle (?{ ... }) code blocks - try constant folding - offset = handleCodeBlock(s, offset, length, sb, regexFlags); - } - } else if (c3 == '?' && c4 == '{') { - // Check if this is the unimplemented marker for (??{...}). - // Under JPERL_UNIMPLEMENTED=warn, warn and fall through to the - // existing non-constant handling (which appends "(?:"); under - // die mode, abort with a clean diagnostic. Either way the user - // sees the issue — silent substitution would be a lie. - if (s.startsWith(RegexMarkers.RECURSIVE_PATTERN, offset)) { - regexUnimplementedSoft(s, offset + 3, - "(??{...}) recursive/dynamic regex patterns not implemented"); - if (isUnimplementedWarnMode()) { - // The marker includes the source construct's closing - // parenthesis. Emit a complete empty-group fallback - // and return its closing position so the dynamic - // construct is not parsed a second time below. - sb.append("(?:)"); - offset += RegexMarkers.RECURSIVE_PATTERN.length() - 1; - return offset; - } - } - // Handle (??{ ... }) recursive/dynamic regex patterns - // These insert a regex pattern at runtime based on code execution - - // Skip the (??{ part to find the code content - int codeStart = offset + 4; - int codeOffset = findRegexCodeBlockClosingBrace(s, codeStart); - if (codeOffset < 0) { - regexError(s, offset + 3, - "Unmatched '{' in (??{...}) dynamic pattern"); - } - // codeOffset points at the closing '}' - String codeBlock = s.substring(codeStart, codeOffset).trim(); - offset = codeOffset + 1; // Skip past '}' - - // For simple constant expressions, inline the value as a regex pattern. - // (??{1}) means "evaluate 1 and use result as pattern" → matches literal "1" - // (??{"[x]"}) → matches character class [x] - if (isSimpleConstant(codeBlock)) { - String value = evaluateSimpleConstant(codeBlock); - if (value != null) { - // Insert the constant value as a non-capturing group pattern. - // Run through handleRegex to process any regex constructs - // (e.g. (?[...]) from regex_sets transformation). - sb.append("(?:"); - handleRegex(value, 0, sb, regexFlags, false); - } else { - // Fallback: empty non-capturing group - sb.append("(?:"); - } - } else { - // Non-constant: replace with empty non-capturing group - sb.append("(?:"); - } - - // offset now points at ')' closing the (??{...}) construct - // Fall through to common ')' handling at end of handleParentheses - } else if (c3 == ';') { - // (?;...) is not recognized - marker should be after ; - regexError(s, offset + 3, "Sequence (?;...) not recognized"); - } else if (c3 == '\\') { - // (?\...) is not recognized - marker should be after \ - regexError(s, offset + 3, "Sequence (?\\...) not recognized"); - } else if (c3 == '<' && (isAlphabetic(c4) || c4 == '_')) { - // Handle named capture (? ... ) - name can start with letter or underscore - offset = handleNamedCapture(c3, s, offset, length, sb, regexFlags); - } else if (c3 == '<') { - // Invalid character after (?< - if (offset + 3 < length) { - // For (?<;x, the marker should be after the invalid character (the ;) - regexError(s, offset + 4, "Group name must start with a non-digit word character"); - } else { - // Pattern ends after (?< - regexError(s, offset + 3, "Sequence (?<... not terminated"); - } - } else if (c3 == '\'') { - // Handle named capture (?'name' ... ) - offset = handleNamedCapture(c3, s, offset, length, sb, regexFlags); - } else if (c3 == '[') { - // Handle extended bracketed character class (?[...]) - return ExtendedCharClass.handleExtendedCharacterClass(s, offset, sb, regexFlags); - } else if ((c3 >= 'a' && c3 <= 'z') || c3 == '-' || c3 == '^' || c3 == ':' || c3 == ')') { - // Handle (?modifiers: ... ) construct and non-capturing groups - return RegexPreprocessorHelper.handleFlagModifiers(s, offset, sb, regexFlags); - } else if (c3 == ':') { - // Handle non-capturing group (?:...) - sb.append("(?:"); - offset = handleRegex(s, offset + 3, sb, regexFlags, true); - } else if (c3 == '=') { - // Positive lookahead (?=...) - sb.append("(?="); - offset = handleRegex(s, offset + 3, sb, regexFlags, true); - } else if (c3 == '!') { - // Negative lookahead (?!...) - sb.append("(?!"); - offset = handleRegex(s, offset + 3, sb, regexFlags, true); - } else if (c3 == '>') { - // Atomic group (?>...) - non-backtracking group - sb.append("(?>"); - offset = handleRegex(s, offset + 3, sb, regexFlags, true); - } else if (Character.isDigit(c3)) { - // Recursive subpattern reference (?1), (?2), etc. - // These refer to the subpattern with that number and are recursive - regexUnimplemented(s, offset + 2, "Sequence (?" + ((char) c3) + "...) not recognized"); - } else if (c3 == '&') { - // Named group recursion (?&name) - Perl feature not yet implemented - regexUnimplemented(s, offset + 2, "Sequence (?&...) not recognized"); - } else { - // Unknown sequence - show the actual character - String seq = "(?"; - if (offset + 2 < length) { - seq += Character.toString((char) s.codePointAt(offset + 2)); - } - regexError(s, offset + 2, "Sequence " + seq + "...) not recognized"); - } - } else { - // Regular parenthesis - offset = handleRegularParentheses(s, offset, length, sb, regexFlags); - } - - // Ensure the closing parenthesis is consumed - if (offset >= length || s.codePointAt(offset) != ')') { - // Change this error message based on what we're looking for - regexError(s, offset - 1, "Unmatched ("); - } - sb.append(')'); - return offset; - } - - private static int handleRegularParentheses(String s, int offset, int length, StringBuilder sb, RegexFlags regexFlags) { - if (regexFlags.isNonCapturing()) { - // Check if it's already a non-capturing group - boolean isNonCapturing = offset + 1 < length && - s.charAt(offset + 1) == '?' && - s.charAt(offset + 2) == ':'; - - // If not already non-capturing and not a special construct, make it non-capturing - if (!isNonCapturing && s.charAt(offset + 1) != '?') { - sb.append("(?:"); - } else { - sb.append('('); - if (!isNonCapturing) { - captureGroupCount++; // Only increment for capturing groups - } - } - } else { - sb.append('('); - captureGroupCount++; // Increment counter for capturing groups - } - - return handleRegex(s, offset + 1, sb, regexFlags, true); - } - - private static int handleNamedCapture(int c, String s, int offset, int length, StringBuilder sb, RegexFlags regexFlags) { - int start = offset + 3; // Skip past '(?<' - int end = c == '<' - ? s.indexOf('>', start) - : s.indexOf('\'', start); - if (end == -1) { - regexError(s, offset, "Unterminated named capture in regex"); - } - String name = s.substring(start, end); - // Encode underscores for Java regex compatibility - String encodedName = CaptureNameEncoder.encodeGroupName(name); - String originalEncodedName = encodedName; - // Perl allows the same capture group name to appear in multiple - // alternation branches (e.g. `(?\d+)|(?foo)`). Java's regex - // engine rejects duplicates outright, so we suffix subsequent - // occurrences with a synthetic marker; CaptureNameEncoder.decodeGroupName - // strips the marker back off when reporting names to user code. - if (!seenNamedCaptures.add(encodedName)) { - encodedName = encodedName + CaptureNameEncoder.DUPLICATE_MARKER + (duplicateNameCounter++); - } - emittedNamedCaptures.computeIfAbsent(originalEncodedName, k -> new java.util.ArrayList<>()).add(encodedName); - sb.append("(?<").append(encodedName).append(">"); - captureGroupCount++; // Increment counter for capturing groups - return handleRegex(s, end + 1, sb, regexFlags, true); // Process content inside the group - } - - static java.util.List namedBackreferenceTargets(String perlName) { - String encodedName = CaptureNameEncoder.encodeGroupName(perlName); - java.util.List emitted = emittedNamedCaptures.get(encodedName); - if (emitted == null || emitted.isEmpty()) { - return java.util.Collections.singletonList(encodedName); - } - return emitted; - } - - private static int handleCharacterClass(String s, boolean flag_xx, StringBuilder sb, int c, int offset) { - final int length = s.length(); - int classStart = sb.length(); - sb.append(Character.toChars(c)); // Append the '[' - offset++; - - - // Check if the bracket is properly closed - int bracketEnd = offset; - int depth = 1; - boolean inEscape = false; - - while (bracketEnd < length && depth > 0) { - char ch = s.charAt(bracketEnd); - if (inEscape) { - inEscape = false; - // \cX consumes the next character (control-character escape), - // even if that character is ']' or '\' (e.g., \c], \c\). - if (ch == 'c' && bracketEnd + 1 < length) { - bracketEnd++; // skip the control-char target - } - } else if (ch == '\\') { - inEscape = true; - } else if (ch == '[') { - // Don't increment depth - [ is just a literal inside a character class - } else if (ch == ']') { - depth--; - } - bracketEnd++; - } - - if (depth > 0) { - regexError(s, offset, "Unmatched ["); - } - - // Check for POSIX syntax at the start of character class - if (offset < length && s.charAt(offset) == '[') { - // Check for [[=...=]] or [[.....]] - if (offset + 1 < length) { - char nextChar = s.charAt(offset + 1); - if (nextChar == '=' || nextChar == '.') { - // Look for closing syntax - int searchPos = offset + 2; - while (searchPos < length - 1) { - if (s.charAt(searchPos) == nextChar && s.charAt(searchPos + 1) == ']') { - // Found complete POSIX syntax - String syntaxType = nextChar == '=' ? "[= =]" : "[. .]"; - regexError(s, searchPos + 2, "POSIX syntax " + syntaxType + " is reserved for future extensions"); - } - searchPos++; - } - } - } - } - - StringBuilder rejected = new StringBuilder(); - offset = RegexPreprocessorHelper.handleRegexCharacterClassEscape(offset, s, sb, length, flag_xx, rejected); - String processedClass = sb.substring(classStart); - if (processedClass.startsWith("[^")) { - sb.setLength(classStart); - sb.append("(?:\\x{FFFD}<[0-9A-F]+>|"); - sb.append(processedClass); - sb.append(')'); - } - // Note: rejected is kept for future use but currently \b is handled by direct substitution to \x08 - return offset; - } - -// public static void hexPrinter(String emojiString) { -// // Print each code point as a hex value -// System.out.println("String: <<" + emojiString + ">>"); -// System.out.println("Hexadecimal representation:"); -// emojiString.codePoints() -// .forEach(codePoint -> System.out.printf("U+%04X ", codePoint)); -// -// // Optional: Print raw UTF-16 encoding -// System.out.println("\nUTF-16 Encoding:"); -// for (char c : emojiString.toCharArray()) { -// System.out.printf("\\u%04X ", (int) c); -// } -// System.out.println("\n\n"); -// } - -// private static String generateGraphemeClusterRegex() { -// return "(?x: # Free-spacing mode\n" + -// " # Basic grapheme cluster\n" + -// " \\P{M}\\p{M}*\n" + -// " |\n" + -// -// " \\uD83D\\uDC4B\\uD83C\\uDFFB" + // Special case -// " |\n" + -// " \\uD83C \\uDDFA \\uD83C \\uDDF8" + // Special case -// " |\n" + -// -// " # Regional indicators for flags\n" + -// " (?:[\uD83C][\uDDE6-\uDDFF]){2}\n" + -// " |\n" + -// " # Emoji with modifiers and ZWJ sequences\n" + -// " (?:[\uD83C-\uDBFF\uDC00-\uDFFF]|[\u2600-\u27BF])\n" + -// " (?:[\uD83C][\uDFFB-\uDFFF])?\n" + -// " (?:\u200D\n" + -// " (?:[\uD83C-\uDBFF\uDC00-\uDFFF]|[\u2600-\u27BF])\n" + -// " (?:[\uD83C][\uDFFB-\uDFFF])?\n" + -// " )*\n" + -// " (?:[\uFE00-\uFE0F])?\n" + -// ")"; -// } - - /** - * Handles predefined character classes within the regex. - * - * @param offset The current offset in the regex string. - * @param s The regex string. - * @param sb The StringBuilder to append processed characters. - * @param length The length of the regex string. - * @return The updated offset after processing the character class. - */ - static int handleCharacterClass(int offset, String s, StringBuilder sb, int length) { - // Check for POSIX syntax [= =] or [. .] - if (offset + 3 < length && s.charAt(offset) == '[' && - (s.charAt(offset + 1) == '=' || s.charAt(offset + 1) == '.')) { - char syntaxChar = s.charAt(offset + 1); - // Look for closing syntax - int closePos = offset + 2; - while (closePos < length - 1) { - if (s.charAt(closePos) == syntaxChar && s.charAt(closePos + 1) == ']') { - // Found POSIX syntax - String syntaxType = syntaxChar == '=' ? "[= =]" : "[. .]"; - // Point to after the ']' that closes the POSIX syntax - regexError(s, closePos + 2, "POSIX syntax " + syntaxType + " is reserved for future extensions"); - } - closePos++; - } - } - int endDelimiter = s.indexOf(":]", offset); - if (endDelimiter > -1) { - String potentialClass = s.substring(offset, endDelimiter + 2); - String mapping = CharacterClassMapper.getMappedClass(potentialClass); - if (mapping != null) { - sb.append(mapping); - return endDelimiter + 1; - } - } - sb.append("\\["); - return offset; - } - - /** - * Skips over inline comments within the regex. - * - * @param offset The current offset in the regex string. - * @param s The regex string. - * @param length The length of the regex string. - * @return The updated offset after skipping the comment. - */ - private static int handleSkipComment(int offset, String s, int length) { - // comment (?# ... ) - int offset3 = offset; - while (offset3 < length) { - final int c3 = s.codePointAt(offset3); - switch (c3) { - case ')': - return offset3; - case '\\': - offset3++; - break; - default: - break; - } - offset3++; - } - return offset; // possible error - end of comment not found - } - - // Lookbehind errors don't show position - static void regexErrorNoPosition(String errMsg) { - throw new PerlCompilerException(errMsg); - } - - static void regexErrorSimple(String s, String errMsg) { - throw new PerlCompilerException(errMsg + " in regex m/" + s + "/"); - } - - /** - * Throws PerlJavaUnimplementedException with proper error formatting including marker and context. - * Used for regex features that are valid Perl but not yet implemented in PerlOnJava. - */ - static void regexUnimplemented(String s, int offset, String errMsg) { - if (offset > s.length()) { - offset = s.length(); - } - - // "Error message in regex; marked by <-- HERE in m/regex <-- HERE remaining/" - String before = s.substring(0, offset); - String after = s.substring(offset); - - // When marker is at the end, no space before <-- HERE - String marker = after.isEmpty() ? " <-- HERE" : " <-- HERE "; - - throw new PerlJavaUnimplementedException(errMsg + " in regex; marked by <-- HERE in m/" + - before + marker + after + "/"); - } - - /** - * Soft variant of {@link #regexUnimplemented}: under - * {@code JPERL_UNIMPLEMENTED=warn} the caller emits a best-effort fallback - * construct (e.g. an empty non-capturing group) and this method warns so - * the user still sees the issue, letting compilation of the surrounding - * pattern continue. Under the default die mode it behaves identically to - * {@code regexUnimplemented} and throws, aborting the regex compile. - * - *

    The intent of {@code JPERL_UNIMPLEMENTED=warn} is to let test runs - * keep going past unsupported features, not to silently hide them. Using - * this helper (instead of silent fallback) ensures the user always sees a - * diagnostic. - */ - static void regexUnimplementedSoft(String s, int offset, String errMsg) { - if (!isUnimplementedWarnMode()) { - regexUnimplemented(s, offset, errMsg); - return; - } - - if (offset > s.length()) { - offset = s.length(); - } - String before = s.substring(0, offset); - String after = s.substring(offset); - String marker = after.isEmpty() ? " <-- HERE" : " <-- HERE "; - - String message = errMsg + " in regex; marked by <-- HERE in m/" + - before + marker + after + "/\n"; - if (shouldEmitWarnings()) { - WarnDie.warn(new RuntimeScalar(message), new RuntimeScalar()); - } - } - - private static boolean isUnimplementedWarnMode() { - return "warn".equals( - GlobalVariable.getGlobalHash("main::ENV") - .get("JPERL_UNIMPLEMENTED").toString()); - } - - private static int findClosingBrace(String s, int start, int length) { - int depth = 1; - int pos = start; - while (pos < length && depth > 0) { - char ch = s.charAt(pos); - if (ch == '{') { - depth++; - } else if (ch == '}') { - depth--; - if (depth == 0) { - return pos; - } - } else if (ch == '\\' && pos + 1 < length) { - pos++; // Skip escaped character - } - pos++; - } - return -1; // Not found - } - - // Find matching parenthesis - private static int findMatchingParen(String s, int start, int length) { - int depth = 1; - int pos = start + 1; // Start after the opening paren - while (pos < length && depth > 0) { - char ch = s.charAt(pos); - if (ch == '(') { - depth++; - } else if (ch == ')') { - depth--; - if (depth == 0) { - return pos; - } - } else if (ch == '\\' && pos + 1 < length) { - pos++; // Skip escaped character - } - pos++; - } - return -1; // Not found - } - - - /** - * Handle a potential quantifier starting with '{'. - * Returns int[2]: [0] = new offset, [1] = 1 if literal braces (not a quantifier), 0 if valid quantifier - */ - private static int[] handleQuantifier(String s, int offset, StringBuilder sb) { - int start = offset; // Position of '{' - int end = s.indexOf('}', start); - - if (end == -1) { - // No closing brace - treat as literal (escape for Java regex) - sb.append("\\{"); - return new int[]{offset, 1}; // literal - } - - String quantifier = s.substring(start + 1, end); - String[] parts = quantifier.split(",", -1); - - // A valid quantifier must have at least one number: {n}, {n,}, or {n,m} - // Perl treats {}, {,}, and non-numeric content as literal braces - boolean hasFirstNumber = false; - boolean hasSecondNumber = false; - boolean isValid = true; - - try { - // Check first number - if (!parts[0].isEmpty()) { - // Check for leading zeros - if (parts[0].length() > 1 && parts[0].charAt(0) == '0') { - regexError(s, start + 1, "Invalid quantifier in {,}"); - } - - long n = Long.parseLong(parts[0]); - if (n > Integer.MAX_VALUE) { - regexError(s, start + 1, "Quantifier in {,} bigger than " + Integer.MAX_VALUE); - } - hasFirstNumber = true; - } - - // Check second number if present - if (parts.length > 1 && !parts[1].isEmpty()) { - // Check for leading zeros - if (parts[1].length() > 1 && parts[1].charAt(0) == '0') { - int commaPos = quantifier.indexOf(','); - regexError(s, start + 1 + commaPos + 1, "Invalid quantifier in {,}"); - } - - long m = Long.parseLong(parts[1]); - if (m > Integer.MAX_VALUE) { - int commaPos = quantifier.indexOf(','); - regexError(s, start + 1 + commaPos, "Quantifier in {,} bigger than " + Integer.MAX_VALUE); - } - hasSecondNumber = true; - } - } catch (NumberFormatException e) { - // Not a valid quantifier - contains non-numeric content - isValid = false; - } - - // Valid quantifier forms: {n}, {n,}, {n,m}, {,m} - // Invalid (literal): {}, {,}, {abc}, etc. - if (!isValid || (!hasFirstNumber && !hasSecondNumber)) { - // Not a valid quantifier - treat opening brace as literal (escape for Java regex). - // Don't consume content up to '}' — it may contain regex metacharacters - // (like parentheses, character classes, etc.) that need proper processing. - sb.append("\\{"); - return new int[]{start, 1}; // literal, offset stays at '{' so caller increments past it - } - - // Valid quantifier - pass through to Java - sb.append(s, start, end + 1); - return new int[]{end, 0}; // valid quantifier - } - - /** - * Check if position offset in string s starts a valid quantifier (for nested quantifier detection). - * A valid quantifier is {n}, {n,}, {n,m}, or {,m} where n and m are numbers. - */ - private static boolean isValidQuantifierAt(String s, int offset) { - if (offset >= s.length() || s.charAt(offset) != '{') { - return false; - } - - int end = s.indexOf('}', offset); - if (end == -1) { - return false; - } - - String content = s.substring(offset + 1, end); - if (content.isEmpty()) { - return false; // {} is not a valid quantifier - } - - String[] parts = content.split(",", -1); - boolean hasFirstNumber = false; - boolean hasSecondNumber = false; - - try { - if (!parts[0].isEmpty()) { - Long.parseLong(parts[0]); - hasFirstNumber = true; - } - if (parts.length > 1 && !parts[1].isEmpty()) { - Long.parseLong(parts[1]); - hasSecondNumber = true; - } - } catch (NumberFormatException e) { - return false; - } - - // Valid if at least one number is present - return hasFirstNumber || hasSecondNumber; - } - - - - /** - * Handles (?{...}) code blocks in regex patterns. - * For simple constant expressions, replaces them with empty named capture groups. - * This allows pack.t tests to work without full (?{...}) implementation. - * - * @param s The regex string - * @param offset Current position (at '(' of '(?{') - * @param length Length of the regex string - * @param sb StringBuilder to append the processed regex - * @param regexFlags The regex flags - * @return New offset after processing the code block - */ - private static int handleCodeBlock(String s, int offset, int length, StringBuilder sb, RegexFlags regexFlags) { - // Find the matching closing brace - int codeStart = offset + 3; // Skip '(?{' - int codeEnd = findRegexCodeBlockClosingBrace(s, codeStart); - - if (codeEnd < 0) { - regexError(s, offset + 2, "Unmatched '{' in (?{...}) code block"); - } - - // Extract the code block content - String codeBlock = s.substring(codeStart, codeEnd).trim(); - - // Try to detect simple constant expressions - // This handles the common cases in pack.t without full parser integration - if (isSimpleConstant(codeBlock)) { - // Replace with an empty named capture group - // This allows the regex to compile and match correctly - // Generate a unique name for this code block capture - // Java regex requires capture group names to start with a letter - String captureName = "codeblock" + captureGroupCount++; - - // Append a named capture group that matches empty string - // This allows us to store the constant value without affecting the match - sb.append("(?<").append(captureName).append(">"); - - // Return offset pointing to the ')' so handleGroup can consume it - // codeEnd points to the '}', the next char should be ')' - if (codeEnd + 1 < length && s.charAt(codeEnd + 1) == ')') { - return codeEnd + 1; // Point to ')' for handleGroup to consume - } - return codeEnd + 1; // Just skip past '}' if no ')' found - } - - if (!regexFlags.allowEvalGroup()) { - if (allowRegexCodeBlockNoop()) { - regexUnimplementedSoft(s, offset + 2, - "Eval-group not allowed at runtime, use re 'eval'"); - } else if (isUnimplementedWarnMode()) { - regexUnimplemented(s, offset + 2, - "Eval-group not allowed at runtime, use re 'eval'"); - } else { - regexError(s, offset + 2, - "Eval-group not allowed at runtime, use re 'eval'"); - } - } - sb.append("(?:"); - - // Return offset pointing to the ')' so handleGroup can consume it - if (codeEnd + 1 < length && s.charAt(codeEnd + 1) == ')') { - return codeEnd + 1; // Point to ')' for handleGroup to consume - } - return codeEnd + 1; // Just skip past '}' if no ')' found - } - - /** - * Find the brace that closes a regex code block while ignoring braces in - * ordinary single- and double-quoted Perl strings. Runtime string patterns - * still pass through this compatibility parser, so values such as - * {@code (??{"{"})} must not make the source brace depth unbalanced. - */ - private static int findRegexCodeBlockClosingBrace(String source, int codeStart) { - int depth = 1; - char quote = 0; - for (int i = codeStart; i < source.length(); i++) { - char ch = source.charAt(i); - if (ch == '\\' && i + 1 < source.length()) { - i++; - continue; - } - if (quote != 0) { - if (ch == quote) quote = 0; - continue; - } - if (ch == '\'' || ch == '"') { - quote = ch; - } else if (ch == '{') { - depth++; - } else if (ch == '}' && --depth == 0) { - return i; - } - } - return -1; - } - - private static boolean allowRegexCodeBlockNoop() { - return "1".equals(GlobalVariable.getGlobalHash("main::ENV") - .get(RegexMarkers.CODE_BLOCK_NOOP_ENV).toString()); - } - - /** - * {{ ... }} - * Handles the common patterns used in pack.t tests. - * - * @param codeBlock The code block content (without (?{ and })) - * @return true if this is a simple constant we can handle - */ - private static boolean isSimpleConstant(String codeBlock) { - // Handle common constant patterns from pack.t: - // - undef - // - 'string' - // - "string" - // - numbers (integer or float) - // - simple arithmetic (e.g., 1.36514538e37) - - if (codeBlock.equals("undef")) { - return true; - } - - // String literals - if ((codeBlock.startsWith("'") && codeBlock.endsWith("'")) || - (codeBlock.startsWith("\"") && codeBlock.endsWith("\""))) { - return true; - } - - // Numeric literals (including scientific notation) - if (codeBlock.matches("[+-]?\\d+(\\.\\d+)?([eE][+-]?\\d+)?")) { - return true; - } - - // Simple arithmetic expressions (for pack.t compatibility) - // Just check if it looks like a number-only expression - return codeBlock.matches("[\\d\\s+\\-*/().eE]+"); - } - - /** - * Evaluates a simple constant code block expression and returns its string value. - * Used by (??{...}) to inline constant patterns. - * - * @param codeBlock The code block content - * @return The string value, or null if it can't be evaluated - */ - private static String evaluateSimpleConstant(String codeBlock) { - if (codeBlock.equals("undef")) { - return ""; - } - - // String literals — strip quotes and return content - if (codeBlock.startsWith("\"") && codeBlock.endsWith("\"")) { - return codeBlock.substring(1, codeBlock.length() - 1); - } - if (codeBlock.startsWith("'") && codeBlock.endsWith("'")) { - return codeBlock.substring(1, codeBlock.length() - 1); - } - - // Numeric literals and simple arithmetic — return as-is (matches literal digits) - if (codeBlock.matches("[+-]?\\d+(\\.\\d+)?([eE][+-]?\\d+)?")) { - return codeBlock; - } - - // Simple arithmetic — too complex to evaluate, return null - return null; - } -} diff --git a/src/main/java/org/perlonjava/runtime/regex/RegexPreprocessorHelper.java b/src/main/java/org/perlonjava/runtime/regex/RegexPreprocessorHelper.java deleted file mode 100644 index f14c2c1737..0000000000 --- a/src/main/java/org/perlonjava/runtime/regex/RegexPreprocessorHelper.java +++ /dev/null @@ -1,1330 +0,0 @@ -package org.perlonjava.runtime.regex; - -import org.perlonjava.runtime.operators.WarnDie; -import org.perlonjava.runtime.runtimetypes.RuntimeScalar; - -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; - -import static org.perlonjava.runtime.regex.UnicodeResolver.translateUnicodeProperty; - -public class RegexPreprocessorHelper { - static final String ASCII_WHITESPACE_CLASS = "[\\t\\n\\u000B\\f\\r\\x20]"; - static final String ASCII_NON_WHITESPACE_CLASS = "[^\\t\\n\\u000B\\f\\r\\x20]"; - static final String UNICODE_WHITESPACE_CLASS = "[\\t\\n\\u000B\\f\\r\\x20\\u0085\\u00A0\\u1680\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000]"; - static final String UNICODE_NON_WHITESPACE_CLASS = "[^\\t\\n\\u000B\\f\\r\\x20\\u0085\\u00A0\\u1680\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000]"; - - static int handleEscapeSequences(String s, StringBuilder sb, int c, int offset, RegexFlags regexFlags) { - sb.append(Character.toChars(c)); // This appends the backslash - final int length = s.length(); - - offset++; - if (offset >= length) { - return offset; - } - - char nextChar = s.charAt(offset); - - // Check for numeric backreferences vs octal escapes - // Perl disambiguation rules (from perlrebackslash): - // 1. If the backslash is followed by a single digit, it's a backreference. - // 2. If the first digit following the backslash is a 0, it's an octal escape. - // 3. If the number N (in decimal) and Perl has already seen N capture groups, - // it's a backreference. Otherwise, it's an octal escape. - // - // Examples: - // \100 with 100 capture groups -> backreference to group 100 - // \100 with 0 capture groups -> octal 100 = '@' - // \037 with 0 capture groups -> octal 037 = unit separator (used in Archive::Tar) - // \9 is always a backreference (single digit rule) - boolean isOctalNotBackref = false; - if (nextChar >= '1' && nextChar <= '9') { - // Parse all consecutive digits to get the full number - int endDigits = offset; - while (endDigits < length && s.charAt(endDigits) >= '0' && s.charAt(endDigits) <= '9') { - endDigits++; - } - String digitStr = s.substring(offset, endDigits); - int refNum = Integer.parseInt(digitStr); - - // Rule 3: If refNum > captureGroupCount, it's an octal escape (if valid octal) - if (refNum > RegexPreprocessor.captureGroupCount) { - // Check if all digits are octal (0-7) - boolean allOctal = true; - for (int i = 0; i < digitStr.length(); i++) { - char d = digitStr.charAt(i); - if (d > '7') { - allOctal = false; - break; - } - } - if (allOctal && digitStr.length() >= 2) { - // This is an octal escape, not a backreference - isOctalNotBackref = true; - } - } - } - - if (!isOctalNotBackref && nextChar >= '1' && nextChar <= '9') { - // This is a backreference like \1, \2, etc. - int refNum = nextChar - '0'; - - // Check if we have ANY capture groups at all - // If there are no groups, this is always an error - // But if there are groups, allow forward references - if (RegexPreprocessor.captureGroupCount == 0) { - sb.setLength(sb.length() - 1); // Remove the backslash - RegexPreprocessor.regexError(s, offset + 1, "Reference to nonexistent group"); - } - // Forward references are allowed when there are capture groups - // Perl allows forward references like (\3|b)\2(a) where \3 refers to group 3 - // which hasn't been captured yet. This is valid and the reference just won't match - // until group 3 is actually captured. - - sb.append(nextChar); - return offset; - } - if (nextChar == 'k' && offset + 1 < length && s.charAt(offset + 1) == '\'') { - // Handle \k'name' backreference (Perl syntax) - offset += 2; // Skip past \k' - int endQuote = s.indexOf('\'', offset); - if (endQuote != -1) { - String name = s.substring(offset, endQuote); - // Convert to Java syntax \k - appendNamedBackreference(sb, name); - return endQuote; // Return position at closing quote - } else { - RegexPreprocessor.regexError(s, offset - 2, "Unterminated \\k'...' backreference"); - } - } - if (nextChar == 'k' && offset + 1 < length && s.charAt(offset + 1) == '<') { - // Handle \k backreference (also valid Perl syntax) - offset += 2; // Skip past \k< - int endAngle = s.indexOf('>', offset); - if (endAngle != -1) { - String name = s.substring(offset, endAngle); - appendNamedBackreference(sb, name); - return endAngle; // Return position at closing > - } else { - RegexPreprocessor.regexError(s, offset - 2, "Unterminated \\k<...> backreference"); - } - } - if (nextChar == 'g') { - if (offset + 1 < length && s.charAt(offset + 1) == '{') { - // Handle \g{name} backreference - offset += 2; // Skip past \g{ - int endBrace = s.indexOf('}', offset); - if (endBrace != -1) { - String ref = s.substring(offset, endBrace).trim(); // Trim whitespace - - // Check if it's numeric (including negative) - try { - int groupNum = Integer.parseInt(ref); - if (groupNum == 0) { - RegexPreprocessor.regexError(s, offset - 2, "Reference to invalid group 0"); - } else if (groupNum < 0) { - // Handle relative backreference - int absoluteRef = RegexPreprocessor.captureGroupCount + groupNum + 1; - if (absoluteRef > 0) { - sb.setLength(sb.length() - 1); // Remove the backslash - sb.append("\\").append(absoluteRef); - } else { - RegexPreprocessor.regexError(s, offset - 2, "Reference to nonexistent or unclosed group"); - } - } else { - // Positive numeric reference - // If there are no groups at all, this is an error - if (RegexPreprocessor.captureGroupCount == 0) { - RegexPreprocessor.regexError(s, offset - 2, "Reference to nonexistent group"); - } - // Otherwise allow forward references - sb.setLength(sb.length() - 1); // Remove the backslash - sb.append("\\").append(groupNum); - } - } catch (NumberFormatException e) { - // It's a named reference. - appendNamedBackreference(sb, ref); - } - offset = endBrace; - } - } else if (offset + 1 < length && Character.isDigit(s.charAt(offset + 1))) { - // Handle \g0, \g1, etc. - int start = offset + 1; - int end = start; - while (end < length && Character.isDigit(s.charAt(end))) { - end++; - } - String numStr = s.substring(start, end); - int groupNum = Integer.parseInt(numStr); - - if (groupNum == 0) { - RegexPreprocessor.regexError(s, offset, "Reference to invalid group 0"); - } else if (RegexPreprocessor.captureGroupCount == 0) { - // No groups at all - this is an error - RegexPreprocessor.regexError(s, offset, "Reference to nonexistent group"); - } - // Otherwise allow forward references - they're valid in Perl - - sb.setLength(sb.length() - 1); // Remove the backslash - sb.append("\\").append(groupNum); - return end - 1; // -1 because the main loop will increment - } else if (offset + 1 < length && s.charAt(offset + 1) == '-') { - // Handle \g-1, \g-2, etc. - int start = offset + 1; - int end = start + 1; // Skip the minus - while (end < length && Character.isDigit(s.charAt(end))) { - end++; - } - String numStr = s.substring(start, end); - int relativeRef = Integer.parseInt(numStr); - int absoluteRef = RegexPreprocessor.captureGroupCount + relativeRef + 1; - - if (absoluteRef > 0) { - sb.setLength(sb.length() - 1); // Remove the backslash - sb.append("\\").append(absoluteRef); - } else { - RegexPreprocessor.regexError(s, offset, "Reference to nonexistent group"); - } - return end - 1; - } - } else if (nextChar == 's' || nextChar == 'S') { - sb.setLength(sb.length() - 1); // Remove the backslash - // Default regexes must keep byte-string \s ASCII-only. Explicit /u - // compiles the primary pattern with Unicode whitespace, and the - // UTF-8 target variant is widened after preprocessing. - boolean unicodeWhitespace = regexFlags.isUnicode() && !regexFlags.isAscii(); - if (nextChar == 's') { - sb.append(unicodeWhitespace ? UNICODE_WHITESPACE_CLASS : ASCII_WHITESPACE_CLASS); - } else { - sb.append(unicodeWhitespace ? UNICODE_NON_WHITESPACE_CLASS : ASCII_NON_WHITESPACE_CLASS); - } - return offset; - } else if (nextChar == 'h') { - // \h - horizontal whitespace - sb.setLength(sb.length() - 1); // Remove the backslash - sb.append("[\\t\\x20\\xA0\\x{1680}\\x{2000}-\\x{200A}\\x{202F}\\x{205F}\\x{3000}]"); - return offset; - } else if (nextChar == 'H') { - // \H - not horizontal whitespace - sb.setLength(sb.length() - 1); // Remove the backslash - sb.append("[^\\t\\x20\\xA0\\x{1680}\\x{2000}-\\x{200A}\\x{202F}\\x{205F}\\x{3000}]"); - return offset; - } else if (nextChar == 'v') { - // \v - vertical whitespace - sb.setLength(sb.length() - 1); // Remove the backslash - sb.append("[\\n\\x0B\\f\\r\\x85\\x{2028}\\x{2029}]"); - return offset; - } else if (nextChar == 'V') { - // \V - not vertical whitespace - sb.setLength(sb.length() - 1); // Remove the backslash - sb.append("[^\\n\\x0B\\f\\r\\x85\\x{2028}\\x{2029}]"); - return offset; - } else if (nextChar == 'K') { - // Syntax-aware admission routes real KEEP assertions to Joni. A - // \K reaching the Java preprocessor is literal, for example in a - // character class or a \Q...\E region. - sb.setLength(sb.length() - 1); - sb.append('K'); - return offset; - } else if ((nextChar == 'b' || nextChar == 'B') && offset + 1 < length && s.charAt(offset + 1) == '{') { - // Handle \b{...} and \B{...} boundary assertions - boolean negated = (nextChar == 'B'); - offset += 2; // Skip past \b{ or \B{ - int endBrace = s.indexOf('}', offset); - if (endBrace != -1) { - String boundaryType = s.substring(offset, endBrace).trim(); - sb.setLength(sb.length() - 1); // Remove the backslash - - if (negated) { - // Negated boundaries - wrap in negative lookaround - sb.append("(?!"); - } - - switch (boundaryType) { - case "gcb": - // Grapheme cluster boundary - // This is a simplified version - a full implementation would be more complex - sb.append("(?= '0' && c2 <= '7') { - // Potential octal sequence - parse it - int octalValue = c2 - '0'; - int octalLength = 1; - - // Read up to 2 more octal digits - for (int i = 1; i <= 2 && offset + i < length; i++) { - int nextDigit = s.codePointAt(offset + i); - if (nextDigit >= '0' && nextDigit <= '7') { - octalValue = octalValue * 8 + (nextDigit - '0'); - octalLength++; - } else { - break; - } - } - - // Check if value is > 255 (requires hex conversion) - if (octalValue > 255) { - // Convert to hex for Java regex - sb.setLength(sb.length() - 1); // Remove the backslash - sb.append(String.format("\\x{%X}", octalValue)); - offset += octalLength - 1; // -1 because caller will increment - } else if (octalValue <= 255 && octalLength == 3) { - // Standard 3-digit octal - convert to hex for Java regex - // Using \x{hex} avoids issues with \0mnn parsing and ensures - // all 3 digits are consumed (e.g., \177 → \x{7F}) - sb.setLength(sb.length() - 1); // Remove the backslash - sb.append(String.format("\\x{%X}", octalValue)); - offset += octalLength - 1; // -1 because caller will increment - } else if (c2 == '0' && octalLength == 1) { - // Single \0 becomes \00 - sb.append('0'); - sb.append('0'); - } else { - // Short octal or single digit, pass through - sb.append(Character.toChars(c2)); - } - } else if (c2 == '8' || c2 == '9') { - // \8 and \9 are not valid octals - treat as literal digits - sb.setLength(sb.length() - 1); // Remove the backslash - sb.append(Character.toChars(c2)); - } else if (c2 == 'x' && offset + 1 < length && s.charAt(offset + 1) == '{') { - // \x{...} hex escape - parse and normalize the hex value. - // Perl stops at the first non-hex character (after removing underscores). - offset += 2; // Skip past x{ - int endBrace = -1; - for (int i = offset; i < length; i++) { - if (s.charAt(i) == '}') { - endBrace = i; - break; - } - } - if (endBrace != -1) { - String hexStr = s.substring(offset, endBrace).trim().replace("_", ""); - // Extract valid hex prefix - int validLen = 0; - for (int i = 0; i < hexStr.length(); i++) { - char ch = hexStr.charAt(i); - if ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')) { - validLen++; - } else { - break; - } - } - int value; - if (validLen == 0) { - value = 0; // No valid hex digits → \x00 - } else { - value = Integer.parseInt(hexStr.substring(0, validLen), 16); - } - sb.append(String.format("x{%X}", value)); - offset = endBrace; - } else { - // No closing brace - pass through as-is - sb.append('x'); - } - // offset now points to '}', caller will increment - } else if (c2 == 'x') { - // Bare \xNN (no braces) - Perl takes up to 2 hex digits. - // If fewer than 2 valid hex digits, stop at first non-hex char. - // Java's Pattern requires exactly 2 hex digits for \xHH, so normalize. - int hexVal = 0; - int hexDigits = 0; - int pos = offset + 1; // position after 'x' - while (hexDigits < 2 && pos < length) { - char ch = s.charAt(pos); - if ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')) { - hexVal = hexVal * 16 + Character.digit(ch, 16); - hexDigits++; - pos++; - } else { - break; - } - } - if (hexDigits == 2) { - // Standard \xHH - pass through (Java handles it natively) - sb.append('x'); - sb.append(s.charAt(offset + 1)); - sb.append(s.charAt(offset + 2)); - offset += 2; - } else { - // 0 or 1 hex digits - use \x{H} format for Java - sb.append(String.format("x{%X}", hexVal)); - offset = pos - 1; // -1 because caller will increment - } - } else if (c2 == 'e') { - // Perl \e is ESC (0x1B); Java regex has no \e alias - sb.setLength(sb.length() - 1); - sb.append("\\x1B"); - } else if (c2 == 'a') { - // Perl \a is BEL (0x07) - sb.setLength(sb.length() - 1); - sb.append("\\x07"); - } else if (c2 == 'u') { - // Perl's regex engine does not treat backslash-u plus four - // digits as a Unicode escape (code points use hex braces). In a runtime pattern the - // unrecognized backslash is passed through and `u` is matched - // literally. Joni otherwise interprets that sequence Java-style, - // changing diagnostic-text patterns into a NUL - // match instead of matching the diagnostic text. - sb.setLength(sb.length() - 1); - sb.append('u'); - } else { - // Other escape sequences, pass through - sb.append(Character.toChars(c2)); - } - } - return offset; - } - - private static void appendNamedBackreference(StringBuilder sb, String perlName) { - java.util.List targets = RegexPreprocessor.namedBackreferenceTargets(perlName); - sb.setLength(sb.length() - 1); // Remove the already-appended backslash - if (targets.size() == 1) { - sb.append("\\k<").append(targets.get(0)).append(">"); - return; - } - - sb.append("(?:"); - for (int i = 0; i < targets.size(); i++) { - if (i > 0) { - sb.append('|'); - } - sb.append("\\k<").append(targets.get(i)).append(">"); - } - sb.append(')'); - } - - /** - * Handles escape sequences within character classes. - * - * @param offset The current offset in the regex string. - * @param s The regex string. - * @param sb The StringBuilder to append processed characters. - * @param length The length of the regex string. - * @param flag_xx A flag indicating whether to treat spaces as tokens. - * @param rejected A StringBuilder to collect rejected sequences. - * @return The updated offset after processing the character class. - */ - static int handleRegexCharacterClassEscape(int offset, String s, StringBuilder sb, int length, boolean flag_xx, - StringBuilder rejected) { - // inside [ ... ] - // space becomes: "\ " unless the /xx flag is used (flag_xx) - // \120 becomes: \0120 - Java requires octal sequences to start with zero - // \0 becomes: \00 - Java requires the extra zero - // [:ascii:] becomes: \p{ASCII} - // [:^ascii:] becomes: \P{ASCII} - // \b is rejected, Java doesn't support \b inside [...] - boolean first = true; - boolean afterCaret = false; - int lastChar = -1; // Track last character for range validation - boolean wasEscape = false; // Track if last char was from escape sequence - - // POSIX syntax checking - if (offset < length && s.charAt(offset) == '[') { - // Check for [[=...=]] or [[.....]] - if (offset + 1 < length) { - char nextChar = s.charAt(offset + 1); - if (nextChar == '=' || nextChar == '.') { - // Look for closing syntax - int searchPos = offset + 2; - while (searchPos < length - 1) { - if (s.charAt(searchPos) == nextChar && s.charAt(searchPos + 1) == ']') { - // Found complete POSIX syntax - String syntaxType = nextChar == '=' ? "[= =]" : "[. .]"; - // IMPORTANT: Use searchPos + 2, not offset + 2 - RegexPreprocessor.regexError(s, searchPos + 2, "POSIX syntax " + syntaxType + " is reserved for future extensions"); - } - searchPos++; - } - } - } - } - - while (offset < length) { - final int c = s.codePointAt(offset); - switch (c) { - case ']': - // Special case: ] immediately after [ or [^ is a literal ] - if (first || afterCaret) { - sb.append("\\]"); - first = false; - afterCaret = false; - lastChar = ']'; - wasEscape = false; - break; - } else { - sb.append(Character.toChars(c)); - return offset; - } - case '^': - if (first) { - afterCaret = true; - } else { - // A second caret is the first ordinary member of a - // negated class, as in [^^]. Only ']' immediately - // after the leading negation caret is literal; leaving - // afterCaret set made the real closing bracket literal - // and consumed the rest of the pattern as class text. - afterCaret = false; - } - sb.append(Character.toChars(c)); - first = false; - lastChar = -1; // Reset for special chars - wasEscape = false; - break; - case '-': - // Check for invalid range - if (lastChar != -1 && !wasEscape && offset + 1 < length) { - int nextPos = offset + 1; - int nextChar = s.codePointAt(nextPos); - - // Skip if next is ], then it's a literal - - if (nextChar != ']') { - // Check if next is start of POSIX class like [:alpha:] - // In that case, the hyphen is literal, not a range - if (nextChar == '[' && nextPos + 1 < length && s.charAt(nextPos + 1) == ':') { - // Next is a POSIX class, hyphen is literal - sb.append(Character.toChars(c)); - first = false; - afterCaret = false; - lastChar = -1; - wasEscape = false; - break; - } - - // Handle escaped next character - int rangeEndCharCount = 1; // How many chars to skip for range end - if (nextChar == '\\' && nextPos + 1 < length) { - nextChar = s.codePointAt(nextPos + 1); - rangeEndCharCount = 2; // Escaped char is 2 chars - // Special handling for escape sequences - if (nextChar == 'b' || nextChar == 'N' || nextChar == 'p' || nextChar == 'P') { - // These are special escapes, can't be in range - nextChar = -1; - } else if (nextChar == 'x' && nextPos + 2 < length && s.charAt(nextPos + 2) == '{') { - // Parse \x{NNNN} as range endpoint - int endBrace = s.indexOf('}', nextPos + 3); - if (endBrace != -1) { - String hex = s.substring(nextPos + 3, endBrace).trim().replace("_", ""); - // Extract valid hex prefix (Perl stops at first non-hex char) - int vLen = 0; - for (int i = 0; i < hex.length(); i++) { - char ch = hex.charAt(i); - if ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')) { - vLen++; - } else { - break; - } - } - if (vLen == 0) { - nextChar = 0; - } else { - nextChar = Integer.parseInt(hex.substring(0, vLen), 16); - } - rangeEndCharCount = endBrace - nextPos + 1; - } - } else if (nextChar == 'o' && nextPos + 2 < length && s.charAt(nextPos + 2) == '{') { - // Parse \o{NNNN} as range endpoint - int endBrace = s.indexOf('}', nextPos + 3); - if (endBrace != -1) { - String oct = s.substring(nextPos + 3, endBrace).trim().replace("_", ""); - try { - nextChar = Integer.parseInt(oct, 8); - rangeEndCharCount = endBrace - nextPos + 1; - } catch (NumberFormatException e) { - nextChar = -1; - } - } - } else if (nextChar >= '0' && nextChar <= '7') { - // Parse bare octal escape (\NNN) as range endpoint - // e.g., \237 → octal 237 = 159 - int octalVal = nextChar - '0'; - int digits = 1; - for (int k = 2; k <= 3 && nextPos + k < length; k++) { - int d = s.codePointAt(nextPos + k); - if (d >= '0' && d <= '7') { - octalVal = octalVal * 8 + (d - '0'); - digits++; - } else { - break; - } - } - if (digits >= 2) { - // Multi-digit octal: use computed value - nextChar = octalVal; - rangeEndCharCount = 1 + digits; // backslash + digits - } - // Single digit \N stays as-is (rangeEndCharCount = 2) - } - } - - if (nextChar != -1) { - if (nextChar < lastChar) { - String rangeStart = Character.toString(lastChar); - String rangeEnd = Character.toString(nextChar); - RegexPreprocessor.regexError(s, offset + 2, - "Invalid [] range \"" + rangeStart + "-" + rangeEnd + "\" in regex"); - } - // Valid range - append the dash and range end, then skip past range end - sb.append(Character.toChars(c)); // Append the '-' - // Append and skip the range end character so it won't be processed again - // This prevents the range end from being used as a range start - for (int i = 0; i < rangeEndCharCount; i++) { - sb.append(s.charAt(nextPos + i)); - } - offset += rangeEndCharCount; // Skip past range end - first = false; - afterCaret = false; - lastChar = -1; // Range complete, next dash is literal or starts new range - wasEscape = false; - break; - } - } - } - sb.append(Character.toChars(c)); - first = false; - afterCaret = false; - lastChar = -1; // Reset after dash - wasEscape = false; - break; - case '[': - // Check if this could be a POSIX character class like [:ascii:] - if (offset + 1 < length && s.charAt(offset + 1) == ':') { - // This might be a POSIX character class - offset = RegexPreprocessor.handleCharacterClass(offset, s, sb, length); - first = false; - afterCaret = false; - lastChar = -1; // POSIX classes can't be range endpoints - wasEscape = false; - } else { - // It's just a literal [ inside a character class - sb.append("\\["); // Escape it for Java regex - first = false; - afterCaret = false; - lastChar = '['; - wasEscape = false; - } - break; - case '\\': // Handle escape sequences - sb.append(Character.toChars(c)); - offset++; - wasEscape = true; - if (offset < length && (s.charAt(offset) == 'p' || s.charAt(offset) == 'P') - && offset + 1 < length && s.charAt(offset + 1) == '{') { - // Handle \p{...} and \P{...} inside character class - // Translate Perl Unicode property names to Java-compatible patterns - boolean pNegated = (s.charAt(offset) == 'P'); - int pEndBrace = s.indexOf('}', offset + 2); - if (pEndBrace != -1) { - String property = s.substring(offset + 2, pEndBrace).trim(); - try { - String translatedProperty = UnicodeResolver.translateUnicodeProperty( - property, pNegated); - // Remove the backslash that was already appended - sb.setLength(sb.length() - 1); - // Append the translated property (e.g., a character class pattern from ICU4J) - sb.append(translatedProperty); - offset = pEndBrace; - } catch (IllegalArgumentException e) { - // If translation fails, pass through as-is and let Java handle it - // (works for standard Java properties like \p{L}, \p{IsAlphabetic}, etc.) - sb.append(Character.toChars(s.charAt(offset))); - } - } else { - sb.append(Character.toChars(s.charAt(offset))); - } - lastChar = -1; // Unicode properties can't be range endpoints - } else if (offset < length && s.charAt(offset) == 'K') { - // KEEP is not active inside a class. Preserve Perl's - // literal K while emitting Java-compatible syntax. - sb.setLength(sb.length() - 1); - sb.append('K'); - lastChar = 'K'; - } else if (offset < length && s.charAt(offset) == 'N') { - if (offset + 1 < length && s.charAt(offset + 1) == '{') { - // Handle \N{...} constructs - offset += 2; // Skip past \N{ - int endBrace = s.indexOf('}', offset); - if (endBrace != -1) { - String content = s.substring(offset, endBrace).trim(); - // Check if content is a quantifier - if (content.matches("\\d+(?:\\s*,\\s*\\d*)?")) { - // Can't use quantifiers inside character class - RegexPreprocessor.regexError(s, offset - 2, "Quantifier \\N{" + content + "} not allowed inside character class"); - } else { - // The class scanner has already copied the - // leading backslash. Append only the escape - // body so the result is \x{...}, not - // \\x{...} (a class containing literal - // backslash/x/braces characters). - int codePoint = UnicodeResolver.getCodePointFromName(content); - sb.append("x{").append(Integer.toHexString(codePoint)).append('}'); - offset = endBrace; - } - } else { - RegexPreprocessor.regexError(s, offset, "Unmatched brace in \\N{name} construct"); - } - } else { - // Plain \N - but inside character class we can't use [^\n] - // We need to handle this differently - maybe reject it - RegexPreprocessor.regexError(s, offset - 1, "\\N (non-newline) not supported inside character class"); - } - lastChar = -1; // Can't use \N in ranges - } else if (offset + 1 < length && s.charAt(offset) == 'o' && s.charAt(offset + 1) == '{') { - // Handle \o{...} octal escape construct in character class - offset += 2; // Skip past \o{ - int endBrace = s.indexOf('}', offset); - if (endBrace != -1) { - String octalStr = s.substring(offset, endBrace).trim(); - // Remove underscores (Perl allows them in number literals) - octalStr = octalStr.replace("_", ""); - try { - // Parse as octal and convert to hex - int value = Integer.parseInt(octalStr, 8); - sb.append(String.format("x{%X}", value)); - offset = endBrace; - lastChar = value; - } catch (NumberFormatException e) { - RegexPreprocessor.regexError(s, offset, "Invalid octal number in \\o{...}"); - } - } else { - RegexPreprocessor.regexError(s, offset, "Missing right brace on \\o{}"); - } - } else if (offset + 1 < length && s.charAt(offset) == 'x' && s.charAt(offset + 1) == '{') { - // Handle \x{...} hex escape construct in character class - offset += 2; // Skip past x{ - int endBrace = s.indexOf('}', offset); - if (endBrace != -1) { - String hexStr = s.substring(offset, endBrace).trim(); - // Remove underscores (Perl allows them in number literals) - hexStr = hexStr.replace("_", ""); - // Extract valid hex prefix (Perl stops at first non-hex char) - int validLen = 0; - for (int i = 0; i < hexStr.length(); i++) { - char ch = hexStr.charAt(i); - if ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')) { - validLen++; - } else { - break; - } - } - int value; - if (validLen == 0) { - value = 0; // No valid hex digits → \x00 - } else { - value = Integer.parseInt(hexStr.substring(0, validLen), 16); - } - sb.append(String.format("x{%X}", value)); - offset = endBrace; - lastChar = value; - } else { - RegexPreprocessor.regexError(s, offset, "Missing right brace on \\x{}"); - } - } else if (s.codePointAt(offset) == 'x') { - // Bare \xNN inside a character class has the same - // up-to-two-hex-digit semantics as it does outside a - // class. Consume the digits here so they do not become - // independent range endpoints (for example, Perl's - // [\x00-\ ] was previously misread as [0- ]). - int hexValue = 0; - int hexDigits = 0; - int pos = offset + 1; - while (hexDigits < 2 && pos < length) { - char ch = s.charAt(pos); - if ((ch >= '0' && ch <= '9') - || (ch >= 'a' && ch <= 'f') - || (ch >= 'A' && ch <= 'F')) { - hexValue = hexValue * 16 + Character.digit(ch, 16); - hexDigits++; - pos++; - } else { - break; - } - } - if (hexDigits == 2) { - sb.append('x'); - sb.append(s.charAt(offset + 1)); - sb.append(s.charAt(offset + 2)); - offset += 2; - } else { - sb.append(String.format("x{%X}", hexValue)); - offset = pos - 1; - } - lastChar = hexValue; - } else if (s.codePointAt(offset) == 'b') { - // \b inside character class = backspace in Perl - // Java doesn't support \b in [...], so convert to \x08 - // Remove the \ that was already appended to sb - sb.setLength(sb.length() - 1); - // Use \x08 directly in the class (works for ranges too) - sb.append("\\x08"); - // Don't increment offset here - the outer loop will do it - lastChar = 0x08; // Backspace character for range validation - first = false; - afterCaret = false; - } else if (s.codePointAt(offset) == 'c' && offset + 1 < length) { - // \cX control-character escape: consume the next character - // and convert to a hex escape so Java doesn't mis-parse - // sequences like \c\, \c[, \c] (where the next char is - // special inside a character class). - // Perl semantics: ord(uc(X)) XOR 0x40, low 8 bits. - int ctrl = s.codePointAt(offset + 1); - if (ctrl >= 'a' && ctrl <= 'z') { - ctrl = ctrl - 'a' + 'A'; // upper-case ASCII letter - } - int value = (ctrl ^ 0x40) & 0xFF; - // Remove the backslash that was already appended - sb.setLength(sb.length() - 1); - sb.append(String.format("\\x{%X}", value)); - offset++; // skip past the control-char target (outer loop bumps past it) - lastChar = value; - first = false; - afterCaret = false; - wasEscape = true; - break; - } else if (s.codePointAt(offset) == 'Q' || s.codePointAt(offset) == 'E') { - warnUnrecognizedCharacterClassEscape((char) s.codePointAt(offset)); - sb.append(Character.toChars(s.codePointAt(offset))); - lastChar = s.codePointAt(offset); - } else { - int c2 = s.codePointAt(offset); - if (c2 >= '0' && c2 <= '7') { - // Potential octal sequence - parse it - int octalValue = c2 - '0'; - int octalLength = 1; - - // Read up to 2 more octal digits - for (int i = 1; i <= 2 && offset + i < length; i++) { - int nextDigit = s.codePointAt(offset + i); - if (nextDigit >= '0' && nextDigit <= '7') { - octalValue = octalValue * 8 + (nextDigit - '0'); - octalLength++; - } else { - break; - } - } - - // Check if value is > 255 (requires hex conversion) - if (octalValue > 255) { - // Convert to hex for Java regex - sb.append(String.format("x{%X}", octalValue)); - offset += octalLength - 1; // -1 because outer loop will increment - lastChar = octalValue; - } else if (octalValue <= 255 && octalLength == 3) { - // Standard 3-digit octal - convert to hex for Java regex - // Using \x{hex} avoids issues with \0mnn parsing and ensures - // correct range validation (e.g., [\177-\237]) - sb.append(String.format("x{%X}", octalValue)); - offset += octalLength - 1; // -1 because outer loop will increment - lastChar = octalValue; - } else if (c2 == '0' && octalLength == 1) { - // Single \0 becomes \00 - sb.append('0'); - sb.append('0'); - lastChar = 0; - } else { - // Short octal (1-2 digits) — prepend 0 for Java - // In Perl, \1-\7 inside [] are octal; in Java, \N is a backreference - sb.append('0'); - for (int j = 0; j < octalLength; j++) { - sb.append(Character.toChars(s.codePointAt(offset + j))); - } - offset += octalLength - 1; - lastChar = octalValue; - } - } else if (c2 == '8' || c2 == '9') { - // \8 and \9 are not valid octals - treat as literal digits - // Remove the backslash that was already appended - sb.setLength(sb.length() - 1); - sb.append(Character.toChars(c2)); - lastChar = c2; - } else if (flag_xx && (c2 == ' ' || c2 == '\t')) { - // Java COMMENTS mode drops escaped horizontal - // whitespace in character classes. Spell it as hex - // so a Perl /xx literal survives Java compilation. - sb.setLength(sb.length() - 1); - sb.append(c2 == ' ' ? "\\x20" : "\\x09"); - lastChar = c2; - } else { - // Other escape sequences - sb.append(Character.toChars(c2)); - // Remember the actual character for range validation - if (c2 != 'p' && c2 != 'P') { // Skip property escapes - lastChar = c2; - } else { - lastChar = -1; - } - } - } - first = false; - afterCaret = false; - break; - case ' ': - if (flag_xx) { - // Perl /xx ignores unescaped horizontal whitespace even - // inside a bracketed class. Do not let it affect whether - // a following ^ is the class negator or whether - is an - // endpoint. Java COMMENTS mode also ignores it, but only - // after our class parser has already made those decisions. - break; - } else { - // make this space a "token", even inside /x - sb.append("\\ "); - } - first = false; - afterCaret = false; - lastChar = c; - wasEscape = false; - break; - case '\t': - if (flag_xx) { - break; - } else { - sb.append("\\t"); - } - first = false; - afterCaret = false; - lastChar = c; - wasEscape = false; - break; - case '\n': - sb.append("\\n"); - first = false; - afterCaret = false; - lastChar = c; - wasEscape = false; - break; - case '\r': - sb.append("\\r"); - first = false; - afterCaret = false; - lastChar = c; - wasEscape = false; - break; - case '\f': - sb.append("\\f"); - first = false; - afterCaret = false; - lastChar = c; - wasEscape = false; - break; - case 0x0B: - sb.append("\\x{B}"); - first = false; - afterCaret = false; - lastChar = c; - wasEscape = false; - break; - case '(', ')', '*', '<', '>', '\'', '"', '`', '@', '#', '=', '&': - // NOTE: '?' is deliberately NOT in this list. None of these - // characters need to be escaped inside a Java regex character - // class, so the backslash is purely cosmetic — except that a - // backslashed '?' combines with a preceding `\c` to form - // `\c\?`, which Java then parses as `\c\` (control-backslash - // = U+001C) followed by a literal '?', silently corrupting - // patterns like `[\n\t\c?]` (Perl: matches LF, TAB, DEL; - // pre-fix: also matched U+001C). See - // dev/modules/json_test_parity.md and t/99_binary.t in the - // CPAN JSON distribution for a motivating example. - sb.append('\\'); - sb.append(Character.toChars(c)); - first = false; - afterCaret = false; - lastChar = c; - wasEscape = false; - break; - default: - sb.append(Character.toChars(c)); - first = false; - afterCaret = false; - lastChar = c; - wasEscape = false; - break; - } - offset++; - } - return offset; - } - - private static void warnUnrecognizedCharacterClassEscape(char escape) { - String message = "Unrecognized escape \\" + escape + " in character class passed through in regex"; - RegexPreprocessor.recordWarningOnUse(message); - if (!RegexPreprocessor.shouldEmitWarnings()) { - return; - } - WarnDie.warnWithCategory( - new RuntimeScalar(message), - new RuntimeScalar(""), - "regexp"); - } - - static int handleFlagModifiers(String s, int offset, StringBuilder sb, RegexFlags regexFlags) { - int start = offset + 2; // Skip past '(?' - int colonPos = s.indexOf(':', start); - int closeParen = s.indexOf(')', start); - - if (closeParen == -1) { - RegexPreprocessor.regexError(s, offset, "Unterminated ( in regex"); - } - - int flagsEnd = (colonPos == -1 || closeParen < colonPos) ? closeParen : colonPos; - String flags = s.substring(start, flagsEnd); - - // Check for invalid (?^- pattern - if (flags.startsWith("^-")) { - RegexPreprocessor.regexError(s, start + 1, "Sequence (?^-...) not recognized"); - } - - // Check for invalid (?^d pattern - if (flags.startsWith("^d")) { - RegexPreprocessor.regexError(s, start + 2, "Sequence (?^d...) not recognized"); - } - - // Split into positive and negative parts - String[] parts = flags.split("-", 2); - String positiveFlags = parts[0]; - String negativeFlags = parts.length > 1 ? parts[1] : ""; - - warnForUselessMatchOnlyFlags(positiveFlags, false); - warnForUselessMatchOnlyFlags(negativeFlags, true); - - // Check for mutually exclusive modifiers - if (positiveFlags.contains("l") && positiveFlags.contains("u")) { - // Find position of second flag - int lPos = positiveFlags.indexOf('l'); - int uPos = positiveFlags.indexOf('u'); - int errorPos = Math.max(lPos, uPos); - RegexPreprocessor.regexError(s, start + errorPos + 1, "Regexp modifiers \"l\" and \"u\" are mutually exclusive"); - } - - // Check for d and a being mutually exclusive - if (positiveFlags.contains("d") && positiveFlags.contains("a")) { - // Find position of second flag - int dPos = positiveFlags.indexOf('d'); - int aPos = positiveFlags.indexOf('a'); - int errorPos = Math.max(dPos, aPos); - RegexPreprocessor.regexError(s, start + errorPos + 1, "Regexp modifiers \"d\" and \"a\" are mutually exclusive"); - } - - // Check for duplicate modifiers - if (positiveFlags.indexOf('l') != positiveFlags.lastIndexOf('l')) { - int secondL = positiveFlags.lastIndexOf('l'); - RegexPreprocessor.regexError(s, start + secondL + 1, "Regexp modifier \"l\" may not appear twice"); - } - - // Check for 'a' appearing more than twice - int aCount = positiveFlags.length() - positiveFlags.replace("a", "").length(); - if (aCount > 2) { - // Find position of third 'a' - int pos = -1; - for (int i = 0; i < 3; i++) { - pos = positiveFlags.indexOf('a', pos + 1); - } - RegexPreprocessor.regexError(s, start + pos + 1, "Regexp modifier \"a\" may appear a maximum of twice"); - } - - // Check for modifiers in negative part that shouldn't be there - if (negativeFlags.contains("l")) { - int lPos = negativeFlags.indexOf('l'); - RegexPreprocessor.regexError(s, start + parts[0].length() + 1 + lPos + 1, "Regexp modifier \"l\" may not appear after the \"-\""); - } - - // Handle caret case - if (!positiveFlags.isEmpty() && positiveFlags.charAt(0) == '^') { - positiveFlags = positiveFlags.substring(1); - Set negSet = new HashSet<>(); - for (char c : (negativeFlags + "imnsx").toCharArray()) { - negSet.add(c); - } - // Remove any negative flags that appear in positive flags - for (char c : positiveFlags.toCharArray()) { - negSet.remove(c); - } - negativeFlags = negSet.stream() - .map(String::valueOf) - .collect(Collectors.joining()); - } - - RegexFlags newFlags = regexFlags.with(positiveFlags, negativeFlags); - - if (positiveFlags.indexOf('p') >= 0) { - RegexPreprocessor.inlinePFlagEncountered = true; - } - - if (positiveFlags.isEmpty() - && negativeFlags.isEmpty() - && (colonPos == -1 || closeParen < colonPos)) { - offset = RegexPreprocessor.handleRegex(s, closeParen + 1, sb, newFlags, true); - if (offset < s.length()) { - offset--; - } - return offset; - } - - // Handle `n` flags - if (positiveFlags.indexOf('n') >= 0) { - positiveFlags = positiveFlags.replace("n", ""); - } - if (negativeFlags.indexOf('n') >= 0) { - negativeFlags = negativeFlags.replace("n", ""); - } - - // Filter flags to only include Java-supported ones - positiveFlags = filterSupportedFlags(positiveFlags); - negativeFlags = filterSupportedFlags(negativeFlags); - - // Build the new flag string - sb.append("(?"); - sb.append(positiveFlags); - if (!negativeFlags.isEmpty()) { - sb.append('-').append(negativeFlags); - } - - if (colonPos == -1 || closeParen < colonPos) { - // Case: `(?flags)pattern` - sb.append(")"); - offset = RegexPreprocessor.handleRegex(s, closeParen + 1, sb, newFlags, true); - // The closing parenthesis, if any, is consumed by the caller - if (offset < s.length()) { - offset--; - } - return offset; - } - - // Case: `(?flags:pattern)` - sb.append(":"); - offset = RegexPreprocessor.handleRegex(s, colonPos + 1, sb, newFlags, true); - - // Ensure the closing parenthesis is consumed - if (offset >= s.length() || s.codePointAt(offset) != ')') { - RegexPreprocessor.regexError(s, offset, "Unterminated ( in regex"); - } - sb.append(')'); - return offset; - } - - private static void warnForUselessMatchOnlyFlags(String flags, boolean negative) { - if (!RegexPreprocessor.shouldEmitWarnings()) { - return; - } - boolean suppressNegativeG = negative && flags.indexOf('c') >= 0; - for (int i = 0; i < flags.length(); i++) { - char flag = flags.charAt(i); - if (flag != 'c' && flag != 'g' && flag != 'o') { - continue; - } - if (negative && flag == 'g' && suppressNegativeG) { - continue; - } - String prefix = negative ? "?-" : "?"; - WarnDie.warn( - new RuntimeScalar("Useless (" + prefix + flag + ")"), - new RuntimeScalar("")); - } - } - - /** - * Filters out regex flags that are not supported by Java's regex engine. - * - * @param flags The flags string to filter - * @return The filtered flags string containing only Java-supported flags - */ - private static String filterSupportedFlags(String flags) { - // Java supports: i, m, s, x, u, d - // We need to remove: a, l, p, and any other Perl-specific flags - StringBuilder filtered = new StringBuilder(); - for (char c : flags.toCharArray()) { - switch (c) { - case 'i': // case-insensitive - case 'm': // multi-line - case 's': // single-line (dotall) - case 'x': // extended/comments - case 'u': // Unicode case - case 'd': // Unix lines - filtered.append(c); - break; - // Skip unsupported flags - case 'a': // ASCII - case 'l': // locale - case 'p': // preserve - case 'n': // no capture (already handled separately) - // These are Perl flags not supported in Java - break; - default: - // Unknown flag - you might want to warn or error here - break; - } - } - return filtered.toString(); - } - -} diff --git a/src/main/java/org/perlonjava/runtime/regex/RegexQuoteMeta.java b/src/main/java/org/perlonjava/runtime/regex/RegexQuoteMeta.java index e4cca7bbf2..4d6b77ec2e 100644 --- a/src/main/java/org/perlonjava/runtime/regex/RegexQuoteMeta.java +++ b/src/main/java/org/perlonjava/runtime/regex/RegexQuoteMeta.java @@ -1,7 +1,9 @@ package org.perlonjava.runtime.regex; +import org.perlonjava.runtime.WarningBitsRegistry; import org.perlonjava.runtime.operators.WarnDie; import org.perlonjava.runtime.runtimetypes.RuntimeScalar; +import org.perlonjava.runtime.runtimetypes.WarningFlags; import java.util.ArrayList; import java.util.List; @@ -10,6 +12,7 @@ public class RegexQuoteMeta { private static final ThreadLocal> WARNINGS_ON_USE = ThreadLocal.withInitial(ArrayList::new); private static final ThreadLocal CALL_SITE_WARNING_STATE = new ThreadLocal<>(); private static final ThreadLocal CALL_SITE_WARNING_BITS = new ThreadLocal<>(); + private static final ThreadLocal PARSER_WARNING_BITS = new ThreadLocal<>(); private static final ThreadLocal MATCH_TARGET_NAME = new ThreadLocal<>(); public static void setCallSiteWarningState(int state) { @@ -24,6 +27,20 @@ public static String getCallSiteWarningBits() { return CALL_SITE_WARNING_BITS.get(); } + public static boolean isCallSiteWarningExplicitlyDisabled() { + Integer state = CALL_SITE_WARNING_STATE.get(); + return state != null && state < 0; + } + + public static void setParserWarningBits(String bits) { + if (bits == null) PARSER_WARNING_BITS.remove(); + else PARSER_WARNING_BITS.set(bits); + } + + public static String getParserWarningBits() { + return PARSER_WARNING_BITS.get(); + } + public static void setMatchTargetName(String name) { MATCH_TARGET_NAME.set(name); } @@ -129,15 +146,44 @@ private static void warnUnrecognizedCharClassEscape(char c) { /** Emit a regex-construction warning using the lexical state captured at the quote site. */ public static void warnAtConstruction(String message) { + warnAtConstruction(message, false); + } + + static void warnAtConstruction(String message, boolean strictDefault) { // This warning belongs to construction of the interpolated pattern. // Retaining it on the cached RuntimeRegex re-emits it for every match // and can leak a warning-enabled compilation into a no-warnings use. Integer state = CALL_SITE_WARNING_STATE.get(); + RuntimeScalar warning = new RuntimeScalar(message); + RuntimeScalar where = new RuntimeScalar(""); + String warningBits = CALL_SITE_WARNING_BITS.get(); + if (warningBits == null) { + // Synthetic/interpolated regex wrappers do not always have a + // dedicated quote opcode. Use the active statement mask rather + // than a stale warning-state value from an earlier qr//. + warningBits = WarningBitsRegistry.getRuntimeWarningBits(); + } + if (warningBits != null) { + String category = warningCategory(message); + boolean enabled = WarningFlags.isEnabledInBits(warningBits, category); + if (!enabled && !isCallSiteWarningExplicitlyDisabled()) { + enabled = strictDefault + || (WarningFlags.isGlobalWarningVariableEnabled() + && !WarningFlags.isWarningSuppressedAtRuntime(category)); + } + if (!enabled) { + return; + } + if (WarningFlags.isFatalInBits(warningBits, category)) { + WarnDie.die(warning, where); + } else { + WarnDie.warn(warning, where); + } + return; + } if (state != null && state == 0) { return; } - RuntimeScalar warning = new RuntimeScalar(message); - RuntimeScalar where = new RuntimeScalar(""); if (state != null && state == 2) { WarnDie.die(warning, where); } else if (state != null) { @@ -146,4 +192,26 @@ public static void warnAtConstruction(String message) { WarnDie.warnWithCategory(warning, where, "regexp"); } } + + /** Perl assigns a few lexer diagnostics to broader warning categories. */ + static String warningCategory(String message) { + if (message != null && message.startsWith("Useless use of \\E")) { + return "misc"; + } + if (message != null && message.contains("is more clearly written simply as")) { + return "syntax"; + } + if (message != null && message.startsWith("Variable length ") + && message.contains("lookbehind with capturing is experimental")) { + return "experimental::vlb"; + } + if (message != null + && (message.startsWith( + "The Unicode property wildcards feature is experimental") + || message.startsWith( + "Using just the single character results returned by \\p{} in (?[...])"))) { + return "experimental::uniprop_wildcards"; + } + return "regexp"; + } } diff --git a/src/main/java/org/perlonjava/runtime/regex/RuntimeRegex.java b/src/main/java/org/perlonjava/runtime/regex/RuntimeRegex.java index fbeeb788a8..606c484648 100644 --- a/src/main/java/org/perlonjava/runtime/regex/RuntimeRegex.java +++ b/src/main/java/org/perlonjava/runtime/regex/RuntimeRegex.java @@ -3,11 +3,14 @@ import org.joni.exception.SyntaxException; import org.perlonjava.backend.bytecode.InterpreterState; import org.perlonjava.runtime.WarningBitsRegistry; +import org.perlonjava.runtime.NamedCharacterExpansion; +import org.perlonjava.runtime.NamedCharacterExpansionMap; import org.perlonjava.runtime.operators.PerlUtfString; import org.perlonjava.runtime.operators.Time; import org.perlonjava.runtime.operators.StringOperators; import org.perlonjava.runtime.operators.WarnDie; import org.perlonjava.runtime.perlmodule.Utf8; +import org.perlonjava.runtime.perlmodule.Warnings; import org.perlonjava.runtime.runtimetypes.*; import java.nio.charset.StandardCharsets; @@ -23,10 +26,10 @@ import java.util.regex.PatternSyntaxException; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; import static org.perlonjava.runtime.regex.RegexFlags.fromModifiers; import static org.perlonjava.runtime.regex.RegexFlags.validateModifiers; -import static org.perlonjava.runtime.regex.RegexPreprocessor.preProcessRegex; import static org.perlonjava.runtime.regex.RegexQuoteMeta.escapeQ; import static org.perlonjava.runtime.runtimetypes.RuntimeScalarCache.getScalarInt; import static org.perlonjava.runtime.runtimetypes.RuntimeScalarCache.scalarUndef; @@ -39,6 +42,11 @@ */ public class RuntimeRegex extends RuntimeBase implements RuntimeScalarReference { + /** Returns optimization facts selected by the primary compiled Joni pattern. */ + public org.joni.Regex.OptimizationInfo getOptimizationInfo() { + return recursivePattern == null ? null : recursivePattern.engineRegex().getOptimizationInfo(); + } + /** * Keep a literal target's SV stable across repeated execution of one regex call site. * Perl stores pos() on the literal SV in the compiled optree; rematerializing it on @@ -64,10 +72,6 @@ public static RuntimeScalar stabilizeLiteralTarget(RuntimeScalar literal, int ca // Debug flag for regex compilation (set at class load time) private static final boolean DEBUG_REGEX = System.getenv("DEBUG_REGEX") != null; - // Constants for regex pattern flags - private static final int CASE_INSENSITIVE = Pattern.CASE_INSENSITIVE; - private static final int MULTILINE = Pattern.MULTILINE; - private static final int DOTALL = Pattern.DOTALL; private static final Pattern USER_DEFINED_PROPERTY_PATTERN = Pattern.compile("\\\\([pP])\\{((?:[A-Za-z_][A-Za-z0-9_]*::)*(?:Is|In)[A-Za-z_][A-Za-z0-9_]*)}"); private static final Pattern MALFORMED_USER_DEFINED_PROPERTY_PATTERN = @@ -82,73 +86,6 @@ public static RuntimeScalar stabilizeLiteralTarget(RuntimeScalar literal, int ca private static final Set REPORTED_DEBUG_COMPILATIONS = ConcurrentHashMap.newKeySet(); - private static String makeDelimitedTokenRepetitionsPossessive(String pattern) { - Deque groups = new ArrayDeque<>(); - List insertions = new ArrayList<>(); - boolean escaped = false; - boolean inClass = false; - - for (int i = 0; i < pattern.length(); i++) { - char ch = pattern.charAt(i); - if (escaped) { - escaped = false; - continue; - } - if (ch == '\\') { - escaped = true; - continue; - } - if (ch == '[') { - inClass = true; - continue; - } - if (ch == ']' && inClass) { - inClass = false; - continue; - } - if (inClass) continue; - - if (ch == '(') { - groups.push(new DelimitedGroup(i)); - } else if (ch == '|' && !groups.isEmpty()) { - groups.peek().hasAlternation = true; - } else if (ch == ')' && !groups.isEmpty()) { - DelimitedGroup group = groups.pop(); - if (!group.hasAlternation || i + 1 >= pattern.length() - || pattern.charAt(i + 1) != '*') { - continue; - } - - String body = pattern.substring(group.start, i + 1); - char delimiter = body.contains("[^\"") || body.contains("[^\\\"") ? '"' - : body.contains("[^'") || body.contains("[^\\'") ? '\'' : 0; - if (delimiter == 0) continue; - - int suffix = i + 2; - while (suffix < pattern.length() && pattern.charAt(suffix) == ')') suffix++; - if (suffix < pattern.length() && pattern.charAt(suffix) == delimiter) { - insertions.add(i + 2); - } - } - } - - if (insertions.isEmpty()) return pattern; - StringBuilder stackSafe = new StringBuilder(pattern); - for (int i = insertions.size() - 1; i >= 0; i--) { - stackSafe.insert(insertions.get(i).intValue(), '+'); - } - return stackSafe.toString(); - } - - private static final class DelimitedGroup { - final int start; - boolean hasAlternation; - - DelimitedGroup(int start) { - this.start = start; - } - } - private static RuntimeRegexState state() { return PerlRuntime.current().regexState; } @@ -175,35 +112,23 @@ static void updateControlVerbVariables(String mark, String error) { } } } - // Compiled regex pattern (for byte strings - ASCII-only \w, \d) - public Pattern pattern; - // Compiled regex pattern for Unicode strings (Unicode \w, \d) - public Pattern patternUnicode; - // Marker-free variants used for ordinary strings that cannot contain PerlOnJava's - // internal U+FFFD scalar markers. - Pattern patternNoInternalMarkers; - Pattern patternUnicodeNoInternalMarkers; - // "Notempty" variant patterns for zero-length match guard retry. - // In Perl, after a zero-length /gc match at position P, the next attempt - // stays at P but uses NOTEMPTY. Java lacks this option, so an opaque region - // starting at P plus a trailing one-character lookbehind requires the - // selected alternative to consume input. - Pattern notemptyPattern; - Pattern notemptyPatternUnicode; JoniRegexPattern recursivePattern; JoniRegexPattern recursivePatternUnicode; JoniRegexPattern recursivePatternBytes; private JoniRegexPattern.NamedCharacterCache namedCharacterCache; + private NamedCharacterExpansion.SourceMode namedCharacterSourceMode; + private RuntimeScalar namedCharacterTranslator; + private int trustedCalloutCount; + private String compiledRegexCacheKey; + // Bare Is*/In* callbacks resolve in the package where the regex was + // constructed, even when qr// is first matched later or in an ithread. + private String userPropertyPackage = "main"; List executableCallbacks = List.of(); private boolean executableCallbacksReleased; - int patternFlags; - int patternFlagsUnicode; public String patternString; // Source scalar provenance needed when a compiled qr// is reused under // lexical use bytes: byte-backed source characters are already octets. private boolean patternByteBacked; - String javaPatternString; // Preprocessed Java-compatible pattern for recompilation - private String requiredLiteral; boolean hasPreservesMatch = false; // True if /p was used (outer or inline (?p)) // Indicates if \G assertion is used (set from regexFlags during compilation) private boolean useGAssertion = false; @@ -227,39 +152,52 @@ static void updateControlVerbVariables(String mark, String error) { // 0 = off, 1 = debug, 2 = debugcolor. Captured at the regex call site. private int lexicalDebugMode; private boolean lexicalReStrict; - private static final String DYNAMIC_PATTERN_ERROR = - "\u0000(??{...}) recursive regex patterns not implemented (dynamic pattern)"; - public RuntimeRegex() { this.regexFlags = null; } /** * Creates a tracked copy of this RuntimeRegex for use as a qr// value. - * The copy shares compiled Pattern objects but has its own refCount = 0, + * The copy shares compiled native regex objects but has its own refCount = 0, * enabling proper reference counting when assigned to user variables. * This mirrors Perl 5 where qr// always creates a new SV wrapper around * the shared compiled regex. */ public RuntimeRegex cloneTracked() { + return cloneTrackedWithCallbacks(this.executableCallbacks); + } + + /** + * Clone a compiled qr// at an ithread graph boundary. + * + *

    The native patterns are immutable and remain shared, but executable + * callback CODE objects own Perl lexical pads. Route those CODE objects + * through the graph cloner so callbacks share the same child-side lexical + * identities as ordinary CODE references in the snapshot.

    + */ + public RuntimeRegex cloneTrackedForThread( + Function callbackCloner) { + List callbacks = new ArrayList<>(executableCallbacks.size()); + for (RuntimeRegexCallback callback : executableCallbacks) { + callbacks.add(callbackCloner.apply(callback)); + } + return cloneTrackedWithCallbacks(callbacks); + } + + private RuntimeRegex cloneTrackedWithCallbacks(List callbacks) { RuntimeRegex copy = new RuntimeRegex(); - copy.pattern = this.pattern; - copy.patternUnicode = this.patternUnicode; - copy.patternNoInternalMarkers = this.patternNoInternalMarkers; - copy.patternUnicodeNoInternalMarkers = this.patternUnicodeNoInternalMarkers; - copy.notemptyPattern = this.notemptyPattern; - copy.notemptyPatternUnicode = this.notemptyPatternUnicode; copy.recursivePattern = this.recursivePattern; copy.recursivePatternUnicode = this.recursivePatternUnicode; copy.recursivePatternBytes = this.recursivePatternBytes; copy.namedCharacterCache = this.namedCharacterCache; - copy.setExecutableCallbacks(this.executableCallbacks); - copy.patternFlags = this.patternFlags; - copy.patternFlagsUnicode = this.patternFlagsUnicode; + copy.namedCharacterSourceMode = this.namedCharacterSourceMode; + copy.namedCharacterTranslator = copyScalarOrNull(this.namedCharacterTranslator); + copy.trustedCalloutCount = this.trustedCalloutCount; + copy.compiledRegexCacheKey = this.compiledRegexCacheKey; + copy.userPropertyPackage = this.userPropertyPackage; + copy.setExecutableCallbacks(callbacks); copy.patternString = this.patternString; copy.patternByteBacked = this.patternByteBacked; - copy.javaPatternString = this.javaPatternString; - copy.requiredLiteral = this.requiredLiteral; copy.hasPreservesMatch = this.hasPreservesMatch; copy.useGAssertion = this.useGAssertion; copy.regexFlags = this.regexFlags; @@ -299,37 +237,18 @@ public void releaseExecutableCallbacks() { for (RuntimeRegexCallback callback : executableCallbacks) callback.releaseOwner(); } - /** Select the byte or Unicode compiled pattern for a particular target scalar. */ - public Pattern selectPattern(RuntimeScalar string) { - Pattern selected = this.pattern; - if (this.patternUnicode != null && this.patternUnicode != this.pattern) { - if (this.regexFlags != null && this.regexFlags.isAscii()) { - selected = this.pattern; - } else if (hasInlineAsciiModifier(this.patternString)) { - selected = this.pattern; - } else if (Utf8.isUtf8(string)) { - selected = this.patternUnicode; - } - } - return selected; - } - /** * Create a backend-neutral matcher for callers that implement Perl * operations around regex matches (for example {@code split}). */ public RegexMatcher matcher(RuntimeScalar string, String input) { - if (recursivePattern != null) { - return selectRecursivePattern(string).matcher(input, executableCallbacks, string); - } - Pattern selected = selectPattern(string, input); - return new JavaRegexMatcher(selected.matcher(new RegexTimeoutCharSequence(input))); + return selectRecursivePattern(string).matcher(input, executableCallbacks, string); } private JoniRegexPattern selectRecursivePattern(RuntimeScalar string) { boolean byteDefaultSemantics = patternByteBacked && regexFlags != null - && regexFlags.isCaseInsensitive() && !regexFlags.isUnicode() - && !regexFlags.isAscii(); + && !regexFlags.isUnicode() + && !regexFlags.isAscii() && !hasInlineUnicodeCaseFoldModifier(patternString); if ((bytesSubstitution || byteDefaultSemantics) && recursivePatternBytes != null && !Utf8.isUtf8(string)) { return recursivePatternBytes; @@ -346,115 +265,113 @@ public String sourcePattern() { return patternString; } - private Pattern selectPattern(RuntimeScalar string, String inputStr) { - Pattern selected = selectPattern(string); - if (!couldContainInternalScalarMarker(inputStr)) { - if (selected == this.patternUnicode && this.patternUnicodeNoInternalMarkers != null) { - return this.patternUnicodeNoInternalMarkers; - } - if (selected == this.pattern && this.patternNoInternalMarkers != null) { - return this.patternNoInternalMarkers; - } - } - return selected; - } - - private static boolean couldContainInternalScalarMarker(String inputStr) { - return inputStr != null && inputStr.indexOf('\uFFFD') >= 0; - } - - private static Pattern compileWithoutInternalMarkerAlternations(String javaPattern, int patternFlags) { - String stripped = stripInternalMarkerAlternations(javaPattern); - if (stripped.equals(javaPattern)) { - return null; - } - return Pattern.compile(stripped, patternFlags); - } - - private static final String INTERNAL_MARKER_ALTERNATION = "(?:\\x{FFFD}<[0-9A-F]+>|"; - - private static String stripInternalMarkerAlternations(String javaPattern) { - int markerStart = javaPattern.indexOf(INTERNAL_MARKER_ALTERNATION); - if (markerStart < 0) { - return javaPattern; - } - - StringBuilder stripped = new StringBuilder(javaPattern.length()); - int offset = 0; - while (markerStart >= 0) { - stripped.append(javaPattern, offset, markerStart); - int altStart = markerStart + INTERNAL_MARKER_ALTERNATION.length(); - int close = findInternalMarkerAlternationClose(javaPattern, altStart); - if (close < 0) { - stripped.append(javaPattern, markerStart, altStart); - offset = altStart; - } else { - stripped.append(javaPattern, altStart, close); - offset = close + 1; - } - markerStart = javaPattern.indexOf(INTERNAL_MARKER_ALTERNATION, offset); - } - stripped.append(javaPattern, offset, javaPattern.length()); - return stripped.toString(); - } - - private static int findInternalMarkerAlternationClose(String pattern, int altStart) { - boolean escaped = false; - boolean inCharacterClass = false; - int nestedGroups = 0; - - for (int i = altStart; i < pattern.length(); i++) { - char ch = pattern.charAt(i); - if (escaped) { - escaped = false; - continue; - } - if (ch == '\\') { - escaped = true; + private void emitWarningsOnUse() { + // These warnings belong to the regex use site, not the earlier qr// + // construction site. The active Perl code supplies the baseline lexical + // warning bits. Each retained diagnostic keeps its Perl warning + // category; WarnDie additionally applies a narrower runtime lexical + // scope at the individual match site. + String activeCodeBits = WarningBitsRegistry.getCurrent(); + String retainedRuntimeWarningBits = WarningBitsRegistry.getRuntimeWarningBits(); + String retainedCallSiteWarningBits = RegexQuoteMeta.getCallSiteWarningBits(); + boolean retainedWarnFlagSet = Warnings.isWarnFlagSet(); + for (String warning : warningsOnUse) { + String category = RegexQuoteMeta.warningCategory(warning); + if ("experimental::uniprop_wildcards".equals(category)) { + // The feature notice is default-on, while the positioned + // single-character diagnostic follows the lexical warning + // bits (or re strict). Snapshot those bits before warning + // callbacks can temporarily replace the active Perl scope. + boolean defaultOnFeatureNotice = warning.startsWith( + "The Unicode property wildcards feature is experimental"); + boolean categoryEnabled = retainedRuntimeWarningBits != null + && WarningFlags.isEnabledInBits( + retainedRuntimeWarningBits, category) + || retainedCallSiteWarningBits != null + && WarningFlags.isEnabledInBits( + retainedCallSiteWarningBits, category) + || activeCodeBits != null + && WarningFlags.isEnabledInBits(activeCodeBits, category); + boolean enabledAtCallSite = WarningFlags.areWarningsForcedOn() + || retainedWarnFlagSet || categoryEnabled; + if ((defaultOnFeatureNotice || lexicalReStrict || enabledAtCallSite) + && !WarningFlags.areWarningsForcedOff() + && !WarningFlags.isWarningSuppressedAtRuntime(category)) { + RuntimeScalar message = new RuntimeScalar(warning); + if (retainedRuntimeWarningBits != null + && WarningFlags.isFatalInBits( + retainedRuntimeWarningBits, category) + || retainedCallSiteWarningBits != null + && WarningFlags.isFatalInBits( + retainedCallSiteWarningBits, category) + || activeCodeBits != null + && WarningFlags.isFatalInBits(activeCodeBits, category)) { + WarnDie.die(message, RuntimeScalarCache.scalarEmptyString); + } else { + WarnDie.warn(message, RuntimeScalarCache.scalarEmptyString); + } + } continue; } - if (inCharacterClass) { - if (ch == ']') { - inCharacterClass = false; + if ("experimental::vlb".equals(category)) { + // Perl's experimental VLB warning is default-on, + // independent of both `use warnings` and `use re 'strict'`. + // The narrower lexical category can still suppress it + // explicitly. + if (!WarningFlags.areWarningsForcedOff() + && !WarningFlags.isWarningSuppressedAtRuntime(category)) { + String warningBits = RegexQuoteMeta.getCallSiteWarningBits(); + RuntimeScalar message = new RuntimeScalar(warning); + if (warningBits != null + && WarningFlags.isFatalInBits(warningBits, category)) { + WarnDie.die(message, RuntimeScalarCache.scalarEmptyString); + } else { + WarnDie.warn(message, RuntimeScalarCache.scalarEmptyString); + } } continue; } - if (ch == '[') { - inCharacterClass = true; + boolean defaultOnExtendedClassDeprecation = warning.startsWith( + "Use of unescaped '#' in [] is deprecated under /xx") + || warning.startsWith( + "Use of literal vertical space in [] is deprecated under /xx"); + if (defaultOnExtendedClassDeprecation + && !WarningFlags.areWarningsForcedOff() + && !WarningFlags.isWarningSuppressedAtRuntime("regexp") + && !WarningFlags.isWarningSuppressedAtRuntime("deprecated")) { + WarnDie.warn(new RuntimeScalar(warning), + RuntimeScalarCache.scalarEmptyString); continue; } - if (ch == '(') { - nestedGroups++; + if (lexicalReStrict + && !WarningFlags.areWarningsForcedOff() + && !WarningFlags.isWarningSuppressedAtRuntime(category) + && !WarningFlags.isWarningSuppressedAtRuntime("regexp") + && !WarningFlags.isWarningSuppressedAtRuntime("digit")) { + String warningBits = WarningBitsRegistry.getRuntimeWarningBits(); + if (warningBits == null) { + warningBits = activeCodeBits; + } + RuntimeScalar message = new RuntimeScalar(warning); + if (warningBits != null + && WarningFlags.isFatalInBits(warningBits, category)) { + WarnDie.die(message, RuntimeScalarCache.scalarEmptyString); + } else { + // `use re 'strict'` makes its retained regex diagnostics + // default-on. This is independent of $^W, including the + // deliberately localized unset value used by reg_mesg.t. + WarnDie.warn(message, RuntimeScalarCache.scalarEmptyString); + } continue; } - if (ch == ')') { - if (nestedGroups == 0) { - return i; - } - nestedGroups--; + if (!WarningFlags.areWarningsForcedOn() + && InterpreterState.current() == null + && activeCodeBits != null + && !WarningFlags.isEnabledInBits(activeCodeBits, category)) { + continue; } - } - return -1; - } - - private void emitWarningsOnUse() { - // These warnings belong to the regex use site, not the earlier qr// - // construction site. The active Perl code supplies the baseline lexical - // warning bits; WarnDie additionally applies a narrower runtime - // `no warnings 'regexp'` scope at the individual match site. - String activeCodeBits = WarningBitsRegistry.getCurrent(); - boolean activeCodeEnablesRegexp = activeCodeBits == null - || WarningFlags.isEnabledInBits(activeCodeBits, "regexp"); - if (!WarningFlags.areWarningsForcedOn() - && InterpreterState.current() == null - && !activeCodeEnablesRegexp) { - return; - } - if (warningsOnUse.contains(DYNAMIC_PATTERN_ERROR)) { - throw new PerlJavaUnimplementedException(DYNAMIC_PATTERN_ERROR.substring(1)); - } - for (String warning : warningsOnUse) { - WarnDie.warnWithCategory(new RuntimeScalar(warning), RuntimeScalarCache.scalarEmptyString, "regexp"); + WarnDie.warnWithCategory(new RuntimeScalar(warning), + RuntimeScalarCache.scalarEmptyString, category); } } @@ -531,8 +448,25 @@ private static RuntimeRegex compile(String patternString, String modifiers, int private static RuntimeRegex compile(String patternString, String modifiers, int lexicalDebugMode, int trustedCalloutCount, boolean patternByteBacked, boolean lexicalReStrict) { - RuntimeScalar namedCharacterTranslator = - org.perlonjava.runtime.HintHashRegistry.getCompileTimeHint("charnames"); + return compile(patternString, modifiers, lexicalDebugMode, trustedCalloutCount, + patternByteBacked, lexicalReStrict, null); + } + + private static RuntimeRegex compile(String patternString, String modifiers, int lexicalDebugMode, + int trustedCalloutCount, boolean patternByteBacked, + boolean lexicalReStrict, String sourceDiagnosticPattern) { + return compile(patternString, modifiers, lexicalDebugMode, trustedCalloutCount, + patternByteBacked, lexicalReStrict, sourceDiagnosticPattern, null); + } + + private static RuntimeRegex compile(String patternString, String modifiers, int lexicalDebugMode, + int trustedCalloutCount, boolean patternByteBacked, + boolean lexicalReStrict, String sourceDiagnosticPattern, + NamedCharacterExpansionMap preResolvedNamedCharacters) { + String userPropertyPackage = currentUserPropertyPackage(); + RuntimeScalar namedCharacterTranslator = preResolvedNamedCharacters == null + ? org.perlonjava.runtime.HintHashRegistry.getCompileTimeHint("charnames") + : null; modifiers = stripInternalMarkers(modifiers); // Dynamic/interpolated qr// compilation can begin during ordinary // execution, outside the Perl compiler lock. User-defined Unicode @@ -540,11 +474,26 @@ private static RuntimeRegex compile(String patternString, String modifiers, int // before entering the process-wide regex compiler monitor. Calls made // during source compilation remain deferred by UnicodeResolver. RegexFlags preloadFlags = fromModifiers(modifiers, patternString); - UnicodeResolver.preloadUserDefinedProperties( - patternString, preloadFlags.isCaseInsensitive()); - return compileSynchronized(patternString, modifiers, lexicalDebugMode, - trustedCalloutCount, false, patternByteBacked, lexicalReStrict, - namedCharacterTranslator); + String compileModifiers = modifiers; + return UnicodeResolver.withUserPropertyPackage(userPropertyPackage, () -> { + UnicodeResolver.preloadUserDefinedProperties( + patternString, preloadFlags.isCaseInsensitive(), + preloadFlags.isExtended()); + return compileSynchronized(patternString, compileModifiers, lexicalDebugMode, + trustedCalloutCount, false, patternByteBacked, lexicalReStrict, + namedCharacterTranslator, + preResolvedNamedCharacters == null ? null + : new JoniRegexPattern.NamedCharacterCache( + preResolvedNamedCharacters), + preResolvedNamedCharacters == null ? null + : preResolvedNamedCharacters.sourceMode(), + false, sourceDiagnosticPattern); + }); + } + + private static String currentUserPropertyPackage() { + String packageName = InterpreterState.currentPackage.get().toString(); + return packageName == null || packageName.isBlank() ? "main" : packageName; } /** User properties execute Perl code and therefore cannot be validated while compiling a CV. */ @@ -564,10 +513,36 @@ public static boolean requiresRuntimeUnicodePropertyResolution(String patternStr * JPERL_UNIMPLEMENTED policy for those patterns.

    */ public static void validateLiteralSyntax(String patternString, String modifiers) { + validateLiteralSyntax(patternString, modifiers, + org.perlonjava.runtime.HintHashRegistry + .getCompileTimeHint("charnames")); + } + + /** Validate literal syntax with the lexical charnames policy captured by its AST. */ + public static void validateLiteralSyntax( + String patternString, String modifiers, + RuntimeScalar namedCharacterTranslator) { + validateLiteralSyntax(patternString, modifiers, + namedCharacterTranslator, null); + } + + /** Validate literal syntax with its captured charnames source provenance. */ + public static void validateLiteralSyntax( + String patternString, String modifiers, + RuntimeScalar namedCharacterTranslator, + NamedCharacterExpansion.SourceMode namedCharacterSourceMode) { + validateLiteralSyntaxResult(patternString, modifiers, + namedCharacterTranslator, namedCharacterSourceMode); + } + + private static RuntimeRegex validateLiteralSyntaxResult( + String patternString, String modifiers, + RuntimeScalar namedCharacterTranslator, + NamedCharacterExpansion.SourceMode namedCharacterSourceMode) { try { - compileSynchronized(patternString, stripInternalMarkers(modifiers), + return compileSynchronized(patternString, stripInternalMarkers(modifiers), debugMode(modifiers), 0, true, false, reStrictMode(modifiers), - org.perlonjava.runtime.HintHashRegistry.getCompileTimeHint("charnames")); + namedCharacterTranslator, null, namedCharacterSourceMode, false, null); } catch (PerlJavaUnimplementedException unsupported) { String message = unsupported.getMessage(); if (message != null && (message.contains("premature end of char-class") @@ -581,38 +556,131 @@ public static void validateLiteralSyntax(String patternString, String modifiers) || message.contains("Illegal repetition"))) { throw new PerlCompilerException(message); } + return null; } } + /** + * Validate one lexical literal and retain the custom translator's immutable + * results for compiled-CV and ithread use. + */ + public static NamedCharacterExpansionMap validateLiteralSyntaxAndCapture( + String patternString, String modifiers, + RuntimeScalar namedCharacterTranslator, + NamedCharacterExpansion.SourceMode namedCharacterSourceMode, + NamedCharacterExpansionMap.LiteralIdentity literalIdentity, + NamedCharacterExpansionMap.CallableIdentity callableIdentity, + String diagnosticPatternString) { + try { + RuntimeRegex regex = validateLiteralSyntaxResult(patternString, modifiers, + namedCharacterTranslator, namedCharacterSourceMode); + return regex == null ? new NamedCharacterExpansionMap( + literalIdentity, callableIdentity, Map.of()) + : regex.namedCharacterCache.snapshot(literalIdentity, callableIdentity); + } catch (PerlCompilerException exception) { + throw new PerlCompilerException(remapLiteralDiagnosticSource( + exception.getMessage(), patternString, diagnosticPatternString)); + } + } + + /** Validate masked callback syntax while retaining its same-width source in diagnostics. */ + public static void validateLiteralSyntax( + String patternString, String modifiers, String diagnosticPatternString) { + validateLiteralSyntax(patternString, modifiers, + org.perlonjava.runtime.HintHashRegistry + .getCompileTimeHint("charnames"), + null, diagnosticPatternString); + } + + /** Validate masked callback syntax with the literal's lexical charname context. */ + public static void validateLiteralSyntax( + String patternString, String modifiers, + RuntimeScalar namedCharacterTranslator, + NamedCharacterExpansion.SourceMode namedCharacterSourceMode, + String diagnosticPatternString) { + try { + validateLiteralSyntax(patternString, modifiers, + namedCharacterTranslator, namedCharacterSourceMode); + } catch (PerlCompilerException exception) { + throw new PerlCompilerException(remapLiteralDiagnosticSource( + exception.getMessage(), patternString, diagnosticPatternString)); + } + } + + private static String remapLiteralDiagnosticSource( + String message, String compiledPattern, String diagnosticPattern) { + if (message == null || compiledPattern == null || diagnosticPattern == null + || compiledPattern.length() != diagnosticPattern.length() + || compiledPattern.equals(diagnosticPattern)) { + return message; + } + String prefix = " in regex; marked by <-- HERE in m/"; + String marker = " <-- HERE "; + int sourceStart = message.indexOf(prefix); + if (sourceStart < 0) return message; + sourceStart += prefix.length(); + int markerStart = message.indexOf(marker, sourceStart); + if (markerStart < sourceStart) return message; + int offset = markerStart - sourceStart; + if (offset > diagnosticPattern.length()) return message; + int sourceEnd = markerStart + marker.length() + + compiledPattern.length() - offset; + if (sourceEnd > message.length()) return message; + return message.substring(0, sourceStart) + + diagnosticPattern.substring(0, offset) + + marker + + diagnosticPattern.substring(offset) + + message.substring(sourceEnd); + } + private static synchronized RuntimeRegex compileSynchronized( String patternString, String modifiers, int lexicalDebugMode, int trustedCalloutCount, boolean literalSyntaxValidation, boolean patternByteBacked, boolean lexicalReStrict, RuntimeScalar namedCharacterTranslator) { + return compileSynchronized(patternString, modifiers, lexicalDebugMode, + trustedCalloutCount, literalSyntaxValidation, patternByteBacked, + lexicalReStrict, namedCharacterTranslator, null, null, false, null); + } + + private static synchronized RuntimeRegex compileSynchronized( + String patternString, String modifiers, int lexicalDebugMode, + int trustedCalloutCount, boolean literalSyntaxValidation, + boolean patternByteBacked, boolean lexicalReStrict, + RuntimeScalar namedCharacterTranslator, String sourceDiagnosticPattern) { + return compileSynchronized(patternString, modifiers, lexicalDebugMode, + trustedCalloutCount, literalSyntaxValidation, patternByteBacked, + lexicalReStrict, namedCharacterTranslator, null, null, false, + sourceDiagnosticPattern); + } + + private static synchronized RuntimeRegex compileSynchronized( + String patternString, String modifiers, int lexicalDebugMode, + int trustedCalloutCount, boolean literalSyntaxValidation, + boolean patternByteBacked, boolean lexicalReStrict, + RuntimeScalar namedCharacterTranslator, + JoniRegexPattern.NamedCharacterCache existingNamedCharacterCache, + NamedCharacterExpansion.SourceMode existingNamedCharacterSourceMode, + boolean forceRecompile, String sourceDiagnosticPattern) { // Debug logging if (DEBUG_REGEX) { System.err.println("RuntimeRegex.compile: pattern=" + patternString + " modifiers=" + modifiers); System.err.println(" caller stack: " + Thread.currentThread().getStackTrace()[2]); } - String originalPatternString = patternString; - String compilePatternString = patternString; - boolean hasDynamicPattern = compilePatternString != null - && compilePatternString.contains(RegexMarkers.RECURSIVE_PATTERN); - boolean warnOnUnimplemented = "warn".equals( - GlobalVariable.getGlobalHash("main::ENV") - .get("JPERL_UNIMPLEMENTED").toString()); - boolean hasDeferredDynamicPattern = hasDynamicPattern && !warnOnUnimplemented; - boolean hasWarnDynamicFallback = hasDynamicPattern && warnOnUnimplemented; - if (hasDeferredDynamicPattern || hasWarnDynamicFallback) { - // Perl permits qr// construction before the dynamic callback is needed. - // Default mode keeps a never-matching placeholder and reports the hard - // error on use. Warn mode retains the historical compatibility fallback - // that ignores the unsupported dynamic component after warning. - compilePatternString = compilePatternString.replace( - RegexMarkers.RECURSIVE_PATTERN, - hasWarnDynamicFallback ? "(?:)" : "(?!)"); + boolean literalUselessCaseEscape = patternString != null + && patternString.contains(RegexMarkers.LITERAL_USELESS_CASE_ESCAPE); + String literalFrontendDiagnostic = + RegexMarkers.firstLiteralDiagnostic(patternString); + String originalPatternString = RegexMarkers.stripLiteralDiagnostics(patternString); + if (literalUselessCaseEscape) { + originalPatternString = originalPatternString.replace( + RegexMarkers.LITERAL_USELESS_CASE_ESCAPE, ""); } + String compilePatternString = originalPatternString; + String displayDiagnosticPattern = sourceDiagnosticPattern == null + ? originalPatternString + : RegexMarkers.stripLiteralDiagnostics(sourceDiagnosticPattern); List quoteMetaWarningsOnUse = new ArrayList<>(); if (compilePatternString != null && compilePatternString.contains("\\Q")) { // Interpolated-pattern warnings are lexical diagnostics for each @@ -621,9 +689,7 @@ private static synchronized RuntimeRegex compileSynchronized( quoteMetaWarningsOnUse = RegexQuoteMeta.getWarningsOnUse(); } - // Dynamic patterns compile differently in normal and warn modes. Do not - // let a placeholder cached in one mode leak into the other. Lexical - // regex debugging also changes the compiled representation. + // Lexical regex debugging changes the compiled representation. // A lexical charname translator may return a different expansion for // each compilation of the same spelling. Literal syntax validation is // the first leg of one logical compilation: refresh the raw-source @@ -634,19 +700,20 @@ private static synchronized RuntimeRegex compileSynchronized( && patternString != null && patternString.contains("\\N{"); boolean effectivePatternByteBacked = patternByteBacked - && !hasUnicodePromotingPatternSyntax(patternString); + && !hasUnicodePromotingPatternSyntax(originalPatternString); String cacheKey = patternString + "/" + modifiers + "#debug=" + lexicalDebugMode + "#callouts=" + trustedCalloutCount - + "#backend=" + RegexBackendPolicy.cacheTag() + "#bytepattern=" + effectivePatternByteBacked + "#strict=" + lexicalReStrict + + (requiresRuntimeUnicodePropertyResolution(patternString) + ? "#propertyPackage=" + + UnicodeResolver.activeUserPropertyPackage() : "") + (namedCharacterTranslator == null ? "" : "#charnames=" - + namedCharacterTranslator.toString()) - + (hasDynamicPattern ? (warnOnUnimplemented ? "\0warn" : "\0defer") : ""); + + namedCharacterTranslator.toString()); // Check if the regex is already cached - RuntimeRegex regex = refreshLexicalNamedCharacter + RuntimeRegex regex = refreshLexicalNamedCharacter || forceRecompile ? null : state().compiledRegexCache.get(cacheKey); if (regex == null) { if (DEBUG_REGEX) { @@ -654,23 +721,34 @@ private static synchronized RuntimeRegex compileSynchronized( } regex = new RuntimeRegex(); regex.patternByteBacked = effectivePatternByteBacked; - regex.namedCharacterCache = - new JoniRegexPattern.NamedCharacterCache(namedCharacterTranslator); + regex.namedCharacterTranslator = copyScalarOrNull(namedCharacterTranslator); + regex.namedCharacterCache = existingNamedCharacterCache == null + ? new JoniRegexPattern.NamedCharacterCache(regex.namedCharacterTranslator) + : existingNamedCharacterCache; + regex.trustedCalloutCount = trustedCalloutCount; + regex.compiledRegexCacheKey = cacheKey; + regex.userPropertyPackage = UnicodeResolver.activeUserPropertyPackage(); regex.lexicalDebugMode = lexicalDebugMode; regex.lexicalReStrict = lexicalReStrict; // Note: flags /e /ee are processed at parse time, in parseRegexReplace() - validateModifiers(modifiers); - regex.regexFlags = fromModifiers(modifiers, compilePatternString); regex.useGAssertion = regex.regexFlags.useGAssertion(); - regex.patternFlags = regex.regexFlags.toPatternFlags(); + NamedCharacterExpansion.SourceMode namedCharacterSourceMode = + existingNamedCharacterSourceMode != null + ? existingNamedCharacterSourceMode + : patternByteBacked + ? NamedCharacterExpansion.SourceMode.BYTE + : NamedCharacterExpansion.SourceMode.UNICODE; + regex.namedCharacterSourceMode = namedCharacterSourceMode; LeftBraceIssue leftBraceIssue = unescapedLeftBraceIssue( originalPatternString); String sourcePolicyWarning = null; - String constructionPolicyWarning = null; + String constructionPolicyWarning = literalUselessCaseEscape + ? "Useless use of \\E" + : null; if (leftBraceIssue != null) { String message = leftBraceIssue.alwaysFatal || lexicalReStrict ? "Unescaped left brace in regex is illegal here" @@ -682,140 +760,76 @@ private static synchronized RuntimeRegex compileSynchronized( } sourcePolicyWarning = diagnostic; } - NonHexIssue nonHexIssue = nonHexEscapeIssue(originalPatternString); - if (nonHexIssue != null) { - if (lexicalReStrict) { - throw new PerlCompilerException(RegexDiagnosticFormatter.markedPerl( - originalPatternString, nonHexIssue.offset + 1, - "Non-hex character")); - } - if (!nonHexIssue.braced) { - char invalid = originalPatternString.charAt(nonHexIssue.offset); - char digit = originalPatternString.charAt(nonHexIssue.offset - 1); - String message = "Non-hex character '" + invalid - + "' terminates \\x early. Resolved as \"\\x0" - + digit + invalid + "\""; - constructionPolicyWarning = RegexDiagnosticFormatter.markedPerl( - originalPatternString, nonHexIssue.offset, message); - } - } - - // Always compute Unicode flags - we need the Unicode variant for when - // the input string contains non-ASCII characters (auto-Unicode detection) - // Only skip Unicode variant if /a flag is explicitly used - if (!regex.regexFlags.isAscii()) { - regex.patternFlagsUnicode = regex.patternFlags | Pattern.UNICODE_CHARACTER_CLASS; - } else { - regex.patternFlagsUnicode = regex.patternFlags; - } - String javaPattern = null; try { - boolean usesRecursiveBackend = org.perlonjava.runtime.NamedCharacterExpansion - .usesCustomTranslator(namedCharacterTranslator) - && JoniRegexPattern.containsNamedCharacterEscape(compilePatternString) - || RegexBackendPolicy.useJoni( - compilePatternString, regex.regexFlags); - if (usesRecursiveBackend - && compilePatternString.contains("(?&") - && (compilePatternString.contains("(?<=") - || compilePatternString.contains("(?(quoteMetaWarningsOnUse); if (sourcePolicyWarning != null) { regex.inlineModifierWarnings.add(sourcePolicyWarning); - regex.warningsOnUse.add(sourcePolicyWarning); } if (constructionPolicyWarning != null) { regex.inlineModifierWarnings.add(constructionPolicyWarning); } - if (hasDeferredDynamicPattern) { - regex.warningsOnUse.add(DYNAMIC_PATTERN_ERROR); - } else if (hasWarnDynamicFallback) { - regex.warningsOnUse.add( - "(??{...}) recursive/dynamic regex patterns not implemented\n"); - } - if (usesRecursiveBackend) { - regex.recursivePattern = new JoniRegexPattern(compilePatternString, + regex.recursivePattern = new JoniRegexPattern(compilePatternString, regex.regexFlags, trustedCalloutCount, !regex.regexFlags.isUnicode(), false, false, - regex.namedCharacterCache); + regex.namedCharacterCache, namedCharacterSourceMode, + lexicalReStrict); regex.recursivePatternUnicode = regex.regexFlags.isAscii() ? regex.recursivePattern : new JoniRegexPattern(compilePatternString, regex.regexFlags, trustedCalloutCount, false, - false, false, regex.namedCharacterCache); - if (effectivePatternByteBacked && regex.regexFlags.isCaseInsensitive() - && !regex.regexFlags.isUnicode() && !regex.regexFlags.isAscii()) { - regex.recursivePatternBytes = new JoniRegexPattern( - compilePatternString, regex.regexFlags, trustedCalloutCount, - true, true, true, regex.namedCharacterCache); - } + false, false, regex.namedCharacterCache, + namedCharacterSourceMode, lexicalReStrict); regex.deferredUserDefinedUnicodeProperties = regex.recursivePattern.hasDeferredUserDefinedUnicodeProperty() || regex.recursivePatternUnicode .hasDeferredUserDefinedUnicodeProperty(); - regex.inlineModifierWarnings.addAll(normalizeNonHexWarningCase( - regex.recursivePattern.compileWarnings(), - originalPatternString, nonHexIssue)); + if (effectivePatternByteBacked && !regex.regexFlags.isUnicode() + && !regex.regexFlags.isAscii() + && !regex.deferredUserDefinedUnicodeProperties + && !regex.recursivePattern.hasUserDefinedUnicodeProperty() + && !regex.recursivePatternUnicode + .hasUserDefinedUnicodeProperty()) { + try { + regex.recursivePatternBytes = new JoniRegexPattern( + compilePatternString, regex.regexFlags, + trustedCalloutCount, true, true, true, + regex.namedCharacterCache, + namedCharacterSourceMode, lexicalReStrict); + } catch (RuntimeException byteVariantFailure) { + // The Unicode variant above is authoritative. Some + // otherwise valid property/set programs cannot be + // represented by the ISO-8859-1 optimization; use + // the Unicode matcher instead of rejecting them. + regex.recursivePatternBytes = null; + } + } + regex.inlineModifierWarnings.addAll( + regex.recursivePattern.compileWarnings()); + if (lexicalReStrict) { + for (String warning : regex.inlineModifierWarnings) { + if (warning.startsWith("False [] range")) { + throw new PerlCompilerException(warning); + } + if (warning.startsWith("Unrecognized escape ") + && warning.contains( + " in character class passed through")) { + throw new PerlCompilerException(warning.replaceFirst( + " in character class passed through", + " in character class")); + } + } + } regex.warningsOnUse.addAll(regex.inlineModifierWarnings); - regex.hasPreservesMatch = regex.regexFlags.preservesMatch() - || RegexFlags.hasInlinePreserveModifier(compilePatternString); - } else { - regex.deferredUserDefinedUnicodeProperties = RegexPreprocessor.hadDeferredUnicodePropertyEncountered(); - regex.hasPreservesMatch = regex.regexFlags.preservesMatch() - || RegexFlags.hasInlinePreserveModifier(compilePatternString) - || RegexPreprocessor.hadInlinePFlag(); - regex.warningsOnUse.addAll(RegexPreprocessor.getWarningsOnUse()); - } - + regex.warningsOnUse.addAll( + unicodePropertyWildcardWarnings(originalPatternString)); + regex.hasPreservesMatch = regex.regexFlags.preservesMatch() + || RegexFlags.hasInlinePreserveModifier(compilePatternString); regex.patternString = originalPatternString; - regex.javaPatternString = javaPattern; - regex.requiredLiteral = usesRecursiveBackend - ? null - : findTopLevelRequiredLiteral(compilePatternString, regex.regexFlags); - - // Compile the regex pattern for byte strings (ASCII-only \w, \d, \s) - regex.pattern = Pattern.compile(javaPattern, regex.patternFlags); - regex.patternNoInternalMarkers = compileWithoutInternalMarkerAlternations(javaPattern, regex.patternFlags); - - // Compile the Unicode variant for Unicode strings - // Only compile separately if the flags differ (saves memory when /a or /u is used) - if (!usesRecursiveBackend && regex.patternFlagsUnicode != regex.patternFlags) { - String javaPatternUnicode = preProcessRegex(compilePatternString, regex.regexFlags.with("u", "a"), false); - // Fix POSIX [:punct:] for Unicode mode: Java's UNICODE_CHARACTER_CLASS flag - // changes \p{Punct} from ASCII punct+symbols to only \p{P} (Unicode Punctuation). - // Perl's [:punct:] should match both Punctuation and Symbols in Unicode mode. - javaPatternUnicode = javaPatternUnicode.replace("\\p{Punct}", "[\\p{P}\\p{S}]") - .replace("\\P{Punct}", "[^\\p{P}\\p{S}]"); - regex.patternUnicode = Pattern.compile(javaPatternUnicode, regex.patternFlagsUnicode); - regex.patternUnicodeNoInternalMarkers = - compileWithoutInternalMarkerAlternations(javaPatternUnicode, regex.patternFlagsUnicode); - } else { - regex.patternUnicode = regex.pattern; - regex.patternUnicodeNoInternalMarkers = regex.patternNoInternalMarkers; - } // Check if pattern has code block captures for $^R optimization // Code blocks are encoded as named captures like (?) - Map namedGroups = regex.pattern.namedGroups(); + Map namedGroups = regex.recursivePattern.namedGroups(); if (namedGroups != null) { for (String groupName : namedGroups.keySet()) { if (CaptureNameEncoder.isCodeBlockCapture(groupName)) { @@ -825,37 +839,47 @@ private static synchronized RuntimeRegex compileSynchronized( } } - // Compile a "notempty" variant for /g patterns. With an opaque - // region starting at the retry position, the trailing lookbehind - // succeeds only when the selected alternative consumed input. - if (!usesRecursiveBackend && regex.regexFlags.isGlobalMatch() && javaPattern != null) { - try { - String notemptyJava = "(?:" + javaPattern + ")(?<=[\\s\\S])"; - regex.notemptyPattern = Pattern.compile(notemptyJava, regex.patternFlags); - if (regex.patternFlagsUnicode != regex.patternFlags) { - String javaPatternUnicode = preProcessRegex(compilePatternString, regex.regexFlags.with("u", "a"), false); - String notemptyUnicode = javaPatternUnicode - .replace("\\p{Punct}", "[\\p{P}\\p{S}]") - .replace("\\P{Punct}", "[^\\p{P}\\p{S}]"); - notemptyUnicode = "(?:" + notemptyUnicode + ")(?<=[\\s\\S])"; - regex.notemptyPatternUnicode = Pattern.compile(notemptyUnicode, regex.patternFlagsUnicode); - } else { - regex.notemptyPatternUnicode = regex.notemptyPattern; - } - } catch (Exception ignore) { - // If notempty compilation fails, fall back to bumpalong - regex.notemptyPattern = null; - regex.notemptyPatternUnicode = null; + } catch (Exception e) { + if (literalFrontendDiagnostic != null) { + String backendDiagnostic = e.getMessage(); + if (backendDiagnostic != null + && backendDiagnostic.startsWith("Unknown charname '") + && literalFrontendDiagnostic.startsWith("Unknown charname '")) { + // Literal source validation and native compilation are + // two legs of one compile. Perl reports the lexical + // source diagnostic once, not again as a backend error. + throw new PerlCompilerException(literalFrontendDiagnostic + "\n"); } + if (backendDiagnostic != null + && backendDiagnostic.startsWith("Unknown charname '") + && !backendDiagnostic.endsWith(" in regex")) { + backendDiagnostic += " in regex"; + } + throw new PerlCompilerException(literalFrontendDiagnostic + + "\n" + backendDiagnostic); } - } catch (Exception e) { if (e instanceof PatternSyntaxException syntaxError && "Illegal character range".equals(syntaxError.getDescription())) { throw new PerlCompilerException("Invalid [] range"); } if ("invalid backref number/name".equals(e.getMessage()) || "invalid backref number".equals(e.getMessage())) { - throw new PerlCompilerException("Reference to nonexistent group"); + int offset = nonexistentNumericBackreferenceEnd(originalPatternString); + String message = "Reference to nonexistent group"; + throw new PerlCompilerException(offset >= 0 + ? RegexDiagnosticFormatter.markedPerl( + originalPatternString, offset, message) + : message + " in regex"); + } + if (e instanceof IllegalArgumentException + && e.getMessage() != null + && e.getMessage().startsWith("Unknown charname '") + && !e.getMessage().endsWith(" in regex")) { + throw new PerlCompilerException(e.getMessage() + " in regex"); + } + if (e instanceof IllegalArgumentException + && isNamedCharacterDiagnostic(e.getMessage())) { + throw new PerlCompilerException(e.getMessage()); } String invalidProperty = invalidUnicodePropertyName(e.getMessage()); if (invalidProperty != null) { @@ -863,8 +887,19 @@ private static synchronized RuntimeRegex compileSynchronized( throw new PerlCompilerException( "Illegal user-defined property name \"" + invalidProperty + "\""); } - throw new PerlCompilerException( - "Can't find Unicode property definition \"" + invalidProperty + "\""); + String diagnostic = failedUnicodePropertyDiagnostic( + displayDiagnosticPattern, invalidProperty); + throw new PerlCompilerException(diagnostic != null + ? diagnostic + : "Can't find Unicode property definition \"" + + invalidProperty.trim() + "\""); + } + if (isUnicodePropertyResolutionFailure(e.getMessage())) { + String diagnostic = failedUnicodePropertyDiagnostic( + displayDiagnosticPattern, null); + if (diagnostic != null) { + throw new PerlCompilerException(diagnostic); + } } // Joni reports malformed patterns with SyntaxException (including its // ValueException subclass). These are real compile errors, not missing @@ -873,7 +908,16 @@ private static synchronized RuntimeRegex compileSynchronized( && containsExecutableSource(originalPatternString, regex.regexFlags.isExtended()); if (e instanceof SyntaxException && !validatesExecutableSource) { - String message = e.getMessage(); + String message = ((SyntaxException) e).getDiagnosticMessage(); + if (message != null && message.startsWith("end pattern") + && originalPatternString != null + && originalPatternString.endsWith("\\")) { + throw new PerlCompilerException("Trailing \\ in regex m/" + + originalPatternString + "/"); + } + if ("unmatched close parenthesis".equals(message)) { + message = "Unmatched )"; + } if ("Empty \\N{}".equals(message)) { throw new PerlCompilerException("Unknown charname ''"); } @@ -886,11 +930,20 @@ && containsExecutableSource(originalPatternString, } throw new PerlCompilerException(diagnostic); } + if ("Lookbehind longer than 255 not implemented in regex".equals(message)) { + throw new PerlCompilerException(message + " m/" + + originalPatternString + "/"); + } int bytePosition = ((SyntaxException) e).getPatternPosition(); if (bytePosition != SyntaxException.UNKNOWN_PATTERN_POSITION) { int characterPosition = utf8ByteOffsetToCharacterOffset( - compilePatternString, bytePosition); - if ("undefined group option".equals(message) + displayDiagnosticPattern, bytePosition); + int unmatched = unmatchedOpeningParenthesis(originalPatternString); + if ("Reference to nonexistent named group".equals(message) + && unmatched >= 0) { + message = "Unmatched ("; + characterPosition = unmatched + 1; + } else if ("undefined group option".equals(message) && originalPatternString != null && characterPosition >= 3 && originalPatternString.regionMatches( @@ -899,15 +952,13 @@ && containsExecutableSource(originalPatternString, } else if ("too big number for repeat range".equals(message)) { message = "Quantifier in {,} bigger than 2147483646"; } else if ("end pattern with unmatched parenthesis".equals(message)) { - int unmatched = ordinaryUnmatchedOpeningParenthesis( - originalPatternString); if (unmatched >= 0) { message = "Unmatched ("; characterPosition = unmatched + 1; } } throw new PerlCompilerException(RegexDiagnosticFormatter.markedPerl( - originalPatternString, characterPosition, message)); + displayDiagnosticPattern, characterPosition, message)); } throw new PerlCompilerException(message); } @@ -934,16 +985,15 @@ && containsExecutableSource(originalPatternString, if (GlobalVariable.getGlobalHash("main::ENV").get("JPERL_UNIMPLEMENTED").toString().equals("warn")) { String base = unimplEx.getMessage(); // Include original and preprocessed patterns to aid debugging - String patternInfo = " [pattern='" + (originalPatternString == null ? "" : originalPatternString) + "'" + - (javaPattern != null ? ", java='" + javaPattern + "'" : "") + "]"; + String patternInfo = " [pattern='" + (originalPatternString == null ? "" : originalPatternString) + "']"; String errorMessage = base + patternInfo; // Ensure error message ends with newline to prevent running into test output if (!errorMessage.endsWith("\n")) { errorMessage += "\n"; } WarnDie.warn(new RuntimeScalar(errorMessage), new RuntimeScalar()); - regex.pattern = Pattern.compile(Character.toString(0) + "ERROR" + Character.toString(0), Pattern.DOTALL); - regex.patternUnicode = regex.pattern; // Error pattern - same for both + regex.recursivePattern = new JoniRegexPattern("(?!)", regex.regexFlags); + regex.recursivePatternUnicode = regex.recursivePattern; // Ensure patternString is set so downstream code doesn't NPE if (regex.patternString == null) { regex.patternString = originalPatternString != null ? originalPatternString : ""; @@ -953,6 +1003,13 @@ && containsExecutableSource(originalPatternString, } } + // Parse the complete alphanumeric modifier suffix before reporting + // it. Perl can diagnose a malformed pattern and an invalid numeric + // modifier from the same quote-like construct; compiling the + // pattern first preserves the more specific native syntax error. + // A valid pattern still reaches the ordinary modifier diagnostic. + validateModifiers(modifiers); + // Cache the result if the cache is not full if (state().compiledRegexCache.size() < MAX_REGEX_CACHE_SIZE || state().compiledRegexCache.containsKey(cacheKey)) { @@ -986,6 +1043,50 @@ private static String invalidUnicodePropertyName(String message) { return end < 0 ? null : message.substring(start, end); } + private static boolean isUnicodePropertyResolutionFailure(String message) { + if (message == null) return false; + return message.startsWith("Invalid or unsupported Unicode property:") + || message.startsWith("Unsupported General_Category value:") + || message.startsWith("Unsupported Numeric_Value value:") + || message.startsWith("Unsupported obsolete Unicode property:"); + } + + /** Preserve Perl's original spelling and point immediately after its closing brace. */ + private static String failedUnicodePropertyDiagnostic( + String pattern, String engineProperty) { + if (pattern == null) return null; + Matcher property = Pattern.compile("\\\\[pP]\\{([^}]*)}").matcher(pattern); + while (property.find()) { + String original = property.group(1).trim(); + if (engineProperty == null + || original.equals(engineProperty.trim()) + || looseUnicodePropertyDiagnosticName(original).equals( + looseUnicodePropertyDiagnosticName(engineProperty))) { + return RegexDiagnosticFormatter.markedPerl( + pattern, property.end(), + "Can't find Unicode property definition \"" + original + "\""); + } + } + return null; + } + + private static String looseUnicodePropertyDiagnosticName(String property) { + return property == null ? "" : property.replaceAll("[\\s_-]+", "") + .toLowerCase(java.util.Locale.ROOT); + } + + private static List unicodePropertyWildcardWarnings(String pattern) { + if (pattern == null || !pattern.contains("(?[")) return List.of(); + Matcher property = Pattern.compile( + "\\\\[pP]\\{\\s*(?:name|na)\\s*(?:=|:(?!:))\\s*/[^}]*/\\s*}", + Pattern.CASE_INSENSITIVE).matcher(pattern); + if (!property.find()) return List.of(); + return List.of( + "The Unicode property wildcards feature is experimental", + RegexDiagnosticFormatter.markedPerl(pattern, property.end(), + "Using just the single character results returned by \\p{} in (?[...])")); + } + private static int utf8ByteOffsetToCharacterOffset(String pattern, int byteOffset) { if (pattern == null || byteOffset <= 0) return 0; byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8); @@ -993,8 +1094,76 @@ private static int utf8ByteOffsetToCharacterOffset(String pattern, int byteOffse return new String(bytes, 0, boundedOffset, StandardCharsets.UTF_8).length(); } - /** Locate an unmatched ordinary group opener, excluding Perl's specialized {@code (?...} forms. */ - private static int ordinaryUnmatchedOpeningParenthesis(String pattern) { + /** Locate the end of the numeric escape responsible for an invalid-backref error. */ + private static int nonexistentNumericBackreferenceEnd(String pattern) { + if (pattern == null) return -1; + + int captureCount = 0; + boolean inClass = false; + for (int i = 0; i < pattern.length(); i++) { + char c = pattern.charAt(i); + if (c == '\\') { + i++; + continue; + } + if (c == '[') { + inClass = true; + continue; + } + if (c == ']' && inClass) { + inClass = false; + continue; + } + if (c != '(' || inClass) continue; + if (i + 1 >= pattern.length() || pattern.charAt(i + 1) != '?') { + captureCount++; + continue; + } + if (i + 2 >= pattern.length()) continue; + char kind = pattern.charAt(i + 2); + if (kind == '\'' + || (kind == '<' && i + 3 < pattern.length() + && pattern.charAt(i + 3) != '=' + && pattern.charAt(i + 3) != '!') + || (kind == 'P' && i + 3 < pattern.length() + && pattern.charAt(i + 3) == '<')) { + captureCount++; + } + } + + inClass = false; + for (int i = 0; i + 1 < pattern.length(); i++) { + char c = pattern.charAt(i); + if (c == '[') { + inClass = true; + continue; + } + if (c == ']' && inClass) { + inClass = false; + continue; + } + if (c != '\\') continue; + char first = pattern.charAt(i + 1); + if (inClass || first < '1' || first > '9') { + i++; + continue; + } + int end = i + 2; + long number = first - '0'; + while (end < pattern.length() + && pattern.charAt(end) >= '0' && pattern.charAt(end) <= '9') { + number = Math.min(Integer.MAX_VALUE, + number * 10 + pattern.charAt(end) - '0'); + end++; + } + if (number > captureCount) return end; + i = end - 1; + } + return -1; + } + + /** Locate the first unmatched group opener after otherwise balanced groups are removed. */ + private static int unmatchedOpeningParenthesis(String pattern) { if (pattern == null) return -1; Deque openings = new ArrayDeque<>(); boolean escaped = false; @@ -1024,13 +1193,7 @@ private static int ordinaryUnmatchedOpeningParenthesis(String pattern) { openings.pop(); } } - while (!openings.isEmpty()) { - int opening = openings.removeLast(); - if (opening + 1 >= pattern.length() || pattern.charAt(opening + 1) != '?') { - return opening; - } - } - return -1; + return openings.isEmpty() ? -1 : openings.getLast(); } private static LeftBraceIssue unescapedLeftBraceIssue(String pattern) { @@ -1137,93 +1300,6 @@ private static final class LeftBraceIssue { } } - private static NonHexIssue nonHexEscapeIssue(String pattern) { - if (pattern == null || pattern.contains("(?[")) return null; - for (int i = 0; i + 2 < pattern.length(); i++) { - if (pattern.charAt(i) != '\\' || pattern.charAt(i + 1) != 'x' - || (i > 0 && pattern.charAt(i - 1) == '\\')) { - continue; - } - int cursor = i + 2; - if (pattern.charAt(cursor) != '{') { - if (isHexDigit(pattern.charAt(cursor)) - && cursor + 1 < pattern.length() - && Character.isLetterOrDigit(pattern.charAt(cursor + 1)) - && !isHexDigit(pattern.charAt(cursor + 1))) { - return new NonHexIssue(cursor + 1, false); - } - continue; - } - int close = pattern.indexOf('}', cursor + 1); - if (close < 0) continue; - cursor++; - while (cursor < close && pattern.charAt(cursor) == ' ') cursor++; - int digits = cursor; - while (cursor < close) { - if (isHexDigit(pattern.charAt(cursor))) { - cursor++; - continue; - } - if (pattern.charAt(cursor) == '_' && cursor > digits - && cursor + 1 < close - && isHexDigit(pattern.charAt(cursor + 1))) { - cursor++; - continue; - } - break; - } - if (cursor == digits || cursor == close) { - i = close; - continue; - } - if (pattern.charAt(cursor) != ' ') return new NonHexIssue(cursor, true); - int whitespace = cursor; - while (cursor < close && pattern.charAt(cursor) == ' ') cursor++; - if (cursor < close) return new NonHexIssue(whitespace, true); - i = close; - } - return null; - } - - private static final class NonHexIssue { - final int offset; - final boolean braced; - - NonHexIssue(int offset, boolean braced) { - this.offset = offset; - this.braced = braced; - } - } - - private static List normalizeNonHexWarningCase( - List warnings, String pattern, NonHexIssue issue) { - if (issue == null || !issue.braced || warnings.isEmpty()) return warnings; - int opening = pattern.lastIndexOf('{', issue.offset); - if (opening < 0) return warnings; - String sourceDigits = pattern.substring(opening + 1, issue.offset).trim(); - if (sourceDigits.isEmpty()) return warnings; - List normalized = new ArrayList<>(warnings.size()); - String prefix = "Resolved as \"\\x{"; - for (String warning : warnings) { - int valueStart = warning.indexOf(prefix); - int valueEnd = valueStart < 0 ? -1 : warning.indexOf('}', valueStart + prefix.length()); - if (valueEnd >= 0) { - String resolved = warning.substring(valueStart + prefix.length(), valueEnd); - if (resolved.equalsIgnoreCase(sourceDigits)) { - warning = warning.substring(0, valueStart + prefix.length()) - + sourceDigits + warning.substring(valueEnd); - } - } - normalized.add(warning); - } - return normalized; - } - - private static boolean isHexDigit(char ch) { - return ch >= '0' && ch <= '9' || ch >= 'a' && ch <= 'f' - || ch >= 'A' && ch <= 'F'; - } - private static int debugMode(String modifiers) { if (modifiers == null) return 0; if (modifiers.indexOf(INTERNAL_DEBUGCOLOR_MARKER) >= 0) return 2; @@ -1245,10 +1321,14 @@ private void emitCompileDebugTrace() { if (lexicalDebugMode == 0) return; registerDebugLifecycle(); String patternDescription = patternString == null ? "" : patternString; + String optimizerDescription = recursivePattern == null + ? "" : recursivePattern.optimizerDebugDescription(); debugWrite("Compiling REx \"" + patternDescription + "\"\n" + "Final program:\n" - + " 1: JAVA_PATTERN <" + patternDescription + "> (2)\n" - + " 2: END (0)\n"); + + " 1: JONI_PATTERN <" + patternDescription + "> (2)\n" + + " 2: END (0)\n" + + (optimizerDescription.isEmpty() + ? "" : optimizerDescription + "\n")); } public void emitExecutionDebugTrace(String input) { @@ -1300,44 +1380,53 @@ private static RuntimeRegex ensureCompiledForRuntime(RuntimeRegex regex) { if (!regex.deferredUserDefinedUnicodeProperties) { return regex; } - - // Recompile once, now that runtime may have defined user properties. - // To avoid infinite loops if recompilation still can't resolve, clear the flag first. - regex.deferredUserDefinedUnicodeProperties = false; - - // Evict the old cached entry so compile() will actually recompile - // instead of returning the stale regex with deferred placeholders. - String cacheKey = regex.patternString + "/" + (regex.regexFlags == null ? "" : regex.regexFlags.toFlagString()); - // Deferred Unicode properties cannot contain executable callouts, so - // this is the same zero-callout key used by compile(). Keep the suffix - // in sync with compileSynchronized(): leaving the placeholder cached - // makes a later qr/\\p{Property}/ reuse its match-any stand-in. - state().compiledRegexCache.remove(cacheKey + "#debug=" + regex.lexicalDebugMode - + "#callouts=0#backend=" + RegexBackendPolicy.cacheTag() - + "#bytepattern=" + regex.patternByteBacked - + "#strict=" + regex.lexicalReStrict); + RegexFlags originalFlags = regex.regexFlags; // User property subs can execute arbitrary Perl and block. Resolve them // before compile() takes its process-wide monitor; only simultaneous // definitions of the same property coordinate in PerlThreadRegistry. - UnicodeResolver.preloadDeferredUserDefinedProperties(regex.patternString, - regex.regexFlags != null && regex.regexFlags.isCaseInsensitive()); - RuntimeRegex recompiled = compile(regex.patternString, - regex.regexFlags == null ? "" : regex.regexFlags.toFlagString(), - regex.lexicalDebugMode, 0, regex.patternByteBacked, - regex.lexicalReStrict); - regex.pattern = recompiled.pattern; - regex.patternUnicode = recompiled.patternUnicode; + RuntimeRegex recompiled = UnicodeResolver.withUserPropertyPackage( + regex.userPropertyPackage, () -> { + UnicodeResolver.preloadDeferredUserDefinedProperties( + regex.patternString, + regex.regexFlags != null + && regex.regexFlags.isCaseInsensitive(), + regex.regexFlags != null && regex.regexFlags.isExtended()); + + // The placeholder was cached under its original lexical + // compilation context. Package and lexical charnames + // provenance must both be reused for recompilation. + if (regex.compiledRegexCacheKey != null) { + state().compiledRegexCache.remove(regex.compiledRegexCacheKey); + } + return compileSynchronized(regex.patternString, + regex.regexFlags == null + ? "" : regex.regexFlags.toFlagString(), + regex.lexicalDebugMode, regex.trustedCalloutCount, false, + regex.patternByteBacked, regex.lexicalReStrict, + regex.namedCharacterTranslator, regex.namedCharacterCache, + regex.namedCharacterSourceMode, true, null); + }); + if (recompiled.deferredUserDefinedUnicodeProperties) { + throw new PerlCompilerException( + "Deferred user-defined Unicode property remained unresolved at runtime"); + } regex.recursivePattern = recompiled.recursivePattern; regex.recursivePatternUnicode = recompiled.recursivePatternUnicode; regex.recursivePatternBytes = recompiled.recursivePatternBytes; - regex.patternNoInternalMarkers = recompiled.patternNoInternalMarkers; - regex.patternUnicodeNoInternalMarkers = recompiled.patternUnicodeNoInternalMarkers; - regex.patternFlags = recompiled.patternFlags; - regex.regexFlags = recompiled.regexFlags; - regex.useGAssertion = recompiled.useGAssertion; + regex.namedCharacterCache = recompiled.namedCharacterCache; + regex.namedCharacterSourceMode = recompiled.namedCharacterSourceMode; + regex.namedCharacterTranslator = + copyScalarOrNull(recompiled.namedCharacterTranslator); + regex.trustedCalloutCount = recompiled.trustedCalloutCount; + regex.compiledRegexCacheKey = recompiled.compiledRegexCacheKey; + regex.userPropertyPackage = recompiled.userPropertyPackage; + // Compilation-only flag spelling omits operation state such as /c, + // /g, /o, and m?PAT?. Those flags belong to the original regex object + // and must survive the native-pattern refresh unchanged. + regex.regexFlags = originalFlags; + regex.useGAssertion = originalFlags != null && originalFlags.useGAssertion(); regex.deferredUserDefinedUnicodeProperties = recompiled.deferredUserDefinedUnicodeProperties; - regex.requiredLiteral = recompiled.requiredLiteral; regex.warningsOnUse = new ArrayList<>(recompiled.warningsOnUse); regex.inlineModifierWarnings = new ArrayList<>(recompiled.inlineModifierWarnings); regex.lexicalDebugMode = recompiled.lexicalDebugMode; @@ -1345,309 +1434,8 @@ private static RuntimeRegex ensureCompiledForRuntime(RuntimeRegex regex) { return regex; } - private static String findTopLevelRequiredLiteral(String pattern, RegexFlags flags) { - if (pattern == null || pattern.isEmpty() || flags == null || flags.isCaseInsensitive() - || pattern.contains("(?i") || pattern.contains("(?[") || hasTopLevelAlternation(pattern)) { - return null; - } - - int depth = 0; - boolean inCharClass = false; - boolean escaped = false; - for (int i = 0; i < pattern.length(); i++) { - char ch = pattern.charAt(i); - - if (escaped) { - if (depth == 0 && !inCharClass && isEscapedRequiredLiteral(ch) - && !isOptionalQuantifiedAt(pattern, i + 1)) { - return Character.toString(ch); - } - if (!isEscapedRequiredLiteral(ch)) { - i = skipEscapePayload(pattern, i); - } - escaped = false; - continue; - } - - if (ch == '\\') { - escaped = true; - continue; - } - - if (inCharClass) { - if (ch == '[' && i + 1 < pattern.length() && isPosixBracketStart(pattern.charAt(i + 1))) { - int posixEnd = findPosixBracketEnd(pattern, i); - if (posixEnd >= 0) { - i = posixEnd; - } - continue; - } - if (ch == ']') { - inCharClass = false; - } - continue; - } - - if (ch == '[') { - inCharClass = true; - continue; - } - - if (ch == '(') { - depth++; - continue; - } - - if (ch == ')' && depth > 0) { - depth--; - continue; - } - - if (depth != 0) { - continue; - } - - if (ch == '{') { - int quantifierEnd = findQuantifierEnd(pattern, i); - if (quantifierEnd >= 0) { - i = quantifierEnd; - continue; - } - } - - if ((flags.isExtended() || flags.isExtendedWhitespace()) && Character.isWhitespace(ch)) { - continue; - } - if ((flags.isExtended() || flags.isExtendedWhitespace()) && ch == '#') { - while (i < pattern.length() && pattern.charAt(i) != '\n') { - i++; - } - continue; - } - - if (!isTopLevelLiteralMetaCharacter(ch) && !isOptionalQuantifiedAt(pattern, i + 1)) { - return Character.toString(ch); - } - } - - return null; - } - - private static boolean isPosixBracketStart(char ch) { - return ch == ':' || ch == '=' || ch == '.'; - } - - private static int findPosixBracketEnd(String pattern, int bracketOffset) { - if (bracketOffset + 1 >= pattern.length()) { - return -1; - } - char delimiter = pattern.charAt(bracketOffset + 1); - if (!isPosixBracketStart(delimiter)) { - return -1; - } - for (int i = bracketOffset + 2; i + 1 < pattern.length(); i++) { - if (pattern.charAt(i) == delimiter && pattern.charAt(i + 1) == ']') { - return i + 1; - } - } - return -1; - } - - private static int findQuantifierEnd(String pattern, int offset) { - int close = pattern.indexOf('}', offset + 1); - if (close < 0) { - return -1; - } - - String body = pattern.substring(offset + 1, close).trim(); - if (body.isEmpty()) { - return -1; - } - - int comma = body.indexOf(','); - if (comma < 0) { - return isAsciiDigits(body) ? close : -1; - } - - if (body.indexOf(',', comma + 1) >= 0) { - return -1; - } - - String min = body.substring(0, comma).trim(); - String max = body.substring(comma + 1).trim(); - if (!min.isEmpty() && !isAsciiDigits(min)) { - return -1; - } - if (min.isEmpty() && max.isEmpty()) { - return -1; - } - return max.isEmpty() || isAsciiDigits(max) ? close : -1; - } - - private static boolean isAsciiDigits(String s) { - if (s.isEmpty()) { - return false; - } - for (int i = 0; i < s.length(); i++) { - char ch = s.charAt(i); - if (ch < '0' || ch > '9') { - return false; - } - } - return true; - } - - private static boolean hasTopLevelAlternation(String pattern) { - int depth = 0; - boolean inCharClass = false; - boolean escaped = false; - for (int i = 0; i < pattern.length(); i++) { - char ch = pattern.charAt(i); - if (escaped) { - escaped = false; - continue; - } - if (ch == '\\') { - escaped = true; - continue; - } - if (inCharClass) { - if (ch == '[' && i + 1 < pattern.length() && isPosixBracketStart(pattern.charAt(i + 1))) { - int posixEnd = findPosixBracketEnd(pattern, i); - if (posixEnd >= 0) { - i = posixEnd; - } - continue; - } - if (ch == ']') { - inCharClass = false; - } - continue; - } - if (ch == '[') { - inCharClass = true; - continue; - } - if (ch == '(') { - depth++; - continue; - } - if (ch == ')' && depth > 0) { - depth--; - continue; - } - if (ch == '|' && depth == 0) { - return true; - } - } - return false; - } - - private static boolean isEscapedRequiredLiteral(char ch) { - return switch (ch) { - case 'A', 'B', 'C', 'D', 'G', 'H', 'K', 'N', 'P', 'R', 'S', 'V', 'W', 'X', 'Z', - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'k', 'n', 'o', 'p', 'r', 's', 't', 'v', 'w', 'x', 'z', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' -> false; - default -> true; - }; - } - - private static int skipEscapePayload(String pattern, int escapeNameOffset) { - char ch = pattern.charAt(escapeNameOffset); - if ((ch == 'p' || ch == 'P' || ch == 'x' || ch == 'o' || ch == 'N' || ch == 'g') - && escapeNameOffset + 1 < pattern.length() - && pattern.charAt(escapeNameOffset + 1) == '{') { - int close = pattern.indexOf('}', escapeNameOffset + 2); - return close >= 0 ? close : escapeNameOffset; - } - if ((ch == 'b' || ch == 'B') - && escapeNameOffset + 1 < pattern.length() - && pattern.charAt(escapeNameOffset + 1) == '{') { - int close = pattern.indexOf('}', escapeNameOffset + 2); - return close >= 0 ? close : escapeNameOffset; - } - if (ch == 'c' && escapeNameOffset + 1 < pattern.length()) { - return escapeNameOffset + 1; - } - if (ch == 'x') { - int end = skipHexDigits(pattern, escapeNameOffset + 1, 2); - return end > escapeNameOffset + 1 ? end - 1 : escapeNameOffset; - } - if ((ch == 'p' || ch == 'P') - && escapeNameOffset + 1 < pattern.length() - && Character.isLetter(pattern.charAt(escapeNameOffset + 1))) { - return escapeNameOffset + 1; - } - if (ch == 'g' && escapeNameOffset + 1 < pattern.length()) { - int pos = escapeNameOffset + 1; - if (pattern.charAt(pos) == '-') { - pos++; - } - int end = skipAsciiDigits(pattern, pos); - return end > pos ? end - 1 : escapeNameOffset; - } - if (ch >= '0' && ch <= '9') { - int end = skipAsciiDigits(pattern, escapeNameOffset); - return end > escapeNameOffset ? end - 1 : escapeNameOffset; - } - if (ch == 'k' && escapeNameOffset + 1 < pattern.length()) { - char opener = pattern.charAt(escapeNameOffset + 1); - char closer = opener == '<' ? '>' : (opener == '\'' ? '\'' : 0); - if (closer != 0) { - int close = pattern.indexOf(closer, escapeNameOffset + 2); - return close >= 0 ? close : escapeNameOffset; - } - } - return escapeNameOffset; - } - - private static int skipAsciiDigits(String s, int offset) { - int pos = offset; - while (pos < s.length()) { - char ch = s.charAt(pos); - if (ch < '0' || ch > '9') { - break; - } - pos++; - } - return pos; - } - - private static int skipHexDigits(String s, int offset, int maxDigits) { - int pos = offset; - int digits = 0; - while (pos < s.length() && digits < maxDigits) { - if (Character.digit(s.charAt(pos), 16) < 0) { - break; - } - pos++; - digits++; - } - return pos; - } - - private static boolean isTopLevelLiteralMetaCharacter(char ch) { - return ch == '^' || ch == '$' || ch == '.' || ch == '*' || ch == '+' - || ch == '?' || ch == '{' || ch == '}'; - } - - private static boolean isOptionalQuantifiedAt(String pattern, int offset) { - if (offset >= pattern.length()) { - return false; - } - char ch = pattern.charAt(offset); - if (ch == '?' || ch == '*') { - return true; - } - if (ch != '{') { - return false; - } - int close = pattern.indexOf('}', offset + 1); - if (close < 0) { - return false; - } - String body = pattern.substring(offset + 1, close).trim(); - return body.equals("0") || body.startsWith("0,") || body.startsWith(","); + private static RuntimeScalar copyScalarOrNull(RuntimeScalar value) { + return value == null ? null : new RuntimeScalar(value); } /** @@ -1717,6 +1505,22 @@ public static RuntimeScalar applyUnicodeStringsFeatureToModifiers(RuntimeScalar } public static RuntimeScalar getQuotedRegex(RuntimeScalar patternString, RuntimeScalar modifiers) { + NamedCharacterExpansionMap metadata = + patternString instanceof RuntimeRegexLiteralScalar literal + ? literal.namedCharacterExpansions() : null; + return getQuotedRegex(patternString, modifiers, metadata); + } + + /** Attach CV-owned immutable charname results without changing pattern text. */ + public static RuntimeScalar attachNamedCharacterExpansions( + RuntimeScalar patternString, NamedCharacterExpansionMap metadata) { + return metadata == null ? patternString + : new RuntimeRegexLiteralScalar(patternString, metadata); + } + + public static RuntimeScalar getQuotedRegex( + RuntimeScalar patternString, RuntimeScalar modifiers, + NamedCharacterExpansionMap preResolvedNamedCharacters) { String rawModifierStr = modifiers.toString(); int callSiteDebugMode = debugMode(rawModifierStr); String modifierStr = stripInternalMarkers(rawModifierStr); @@ -1748,7 +1552,9 @@ && containsExecutableSource(patternString.toString(), modifierStr.indexOf('x') > if (patternString.value instanceof RuntimeRegexTemplate template) { RuntimeRegex regex = compile(template.pattern(), rawModifierStr, callSiteDebugMode, - template.callbacks().size(), template.byteBackedPattern()).cloneTracked(); + template.callbacks().size(), template.byteBackedPattern(), + reStrictMode(rawModifierStr), RuntimeRegexTemplate.displayPattern( + template.pattern(), template.callbacks())).cloneTracked(); regex.setExecutableCallbacks(template.callbacks()); return new RuntimeScalar(regex).propagateTaint(patternString); } @@ -1764,14 +1570,17 @@ && containsExecutableSource(patternString.toString(), modifierStr.indexOf('x') > // Create a new regex with merged flags RuntimeRegex regex = new RuntimeRegex(); - regex.pattern = originalRegex.pattern; - regex.patternUnicode = originalRegex.patternUnicode; regex.recursivePattern = originalRegex.recursivePattern; regex.recursivePatternUnicode = originalRegex.recursivePatternUnicode; regex.recursivePatternBytes = originalRegex.recursivePatternBytes; + regex.namedCharacterCache = originalRegex.namedCharacterCache; + regex.namedCharacterSourceMode = originalRegex.namedCharacterSourceMode; + regex.namedCharacterTranslator = + copyScalarOrNull(originalRegex.namedCharacterTranslator); + regex.trustedCalloutCount = originalRegex.trustedCalloutCount; + regex.compiledRegexCacheKey = originalRegex.compiledRegexCacheKey; + regex.userPropertyPackage = originalRegex.userPropertyPackage; regex.setExecutableCallbacks(originalRegex.executableCallbacks); - regex.patternNoInternalMarkers = originalRegex.patternNoInternalMarkers; - regex.patternUnicodeNoInternalMarkers = originalRegex.patternUnicodeNoInternalMarkers; regex.patternString = originalRegex.patternString; regex.patternByteBacked = originalRegex.patternByteBacked; regex.deferredUserDefinedUnicodeProperties = @@ -1786,7 +1595,6 @@ && containsExecutableSource(patternString.toString(), modifierStr.indexOf('x') > regex.regexFlags = mergeRegexFlags(originalRegex.regexFlags, modifierStr, originalRegex.patternString); regex.hasPreservesMatch = regex.hasPreservesMatch || regex.regexFlags.preservesMatch(); regex.useGAssertion = regex.regexFlags.useGAssertion(); - regex.patternFlags = regex.regexFlags.toPatternFlags(); regex.refCount = 0; // Track for proper weak ref handling return new RuntimeScalar(regex).propagateTaint(patternString); @@ -1809,14 +1617,17 @@ && containsExecutableSource(patternString.toString(), modifierStr.indexOf('x') > // Create a new regex with merged flags RuntimeRegex regex = new RuntimeRegex(); - regex.pattern = originalRegex.pattern; - regex.patternUnicode = originalRegex.patternUnicode; regex.recursivePattern = originalRegex.recursivePattern; regex.recursivePatternUnicode = originalRegex.recursivePatternUnicode; regex.recursivePatternBytes = originalRegex.recursivePatternBytes; + regex.namedCharacterCache = originalRegex.namedCharacterCache; + regex.namedCharacterSourceMode = originalRegex.namedCharacterSourceMode; + regex.namedCharacterTranslator = + copyScalarOrNull(originalRegex.namedCharacterTranslator); + regex.trustedCalloutCount = originalRegex.trustedCalloutCount; + regex.compiledRegexCacheKey = originalRegex.compiledRegexCacheKey; + regex.userPropertyPackage = originalRegex.userPropertyPackage; regex.setExecutableCallbacks(originalRegex.executableCallbacks); - regex.patternNoInternalMarkers = originalRegex.patternNoInternalMarkers; - regex.patternUnicodeNoInternalMarkers = originalRegex.patternUnicodeNoInternalMarkers; regex.patternString = originalRegex.patternString; regex.patternByteBacked = originalRegex.patternByteBacked; regex.deferredUserDefinedUnicodeProperties = @@ -1831,7 +1642,6 @@ && containsExecutableSource(patternString.toString(), modifierStr.indexOf('x') > regex.regexFlags = mergeRegexFlags(originalRegex.regexFlags, modifierStr, originalRegex.patternString); regex.hasPreservesMatch = regex.hasPreservesMatch || regex.regexFlags.preservesMatch(); regex.useGAssertion = regex.regexFlags.useGAssertion(); - regex.patternFlags = regex.regexFlags.toPatternFlags(); regex.refCount = 0; // Track for proper weak ref handling return new RuntimeScalar(regex).propagateTaint(patternString, overloadedResult); @@ -1854,7 +1664,9 @@ && containsExecutableSource(patternString.toString(), modifierStr.indexOf('x') > // so the cached RuntimeRegex is not corrupted by refCount changes) RuntimeRegex compiled = compile(patternString.toString(), rawModifierStr, callSiteDebugMode, 0, - patternString.type == RuntimeScalarType.BYTE_STRING).cloneTracked(); + patternString.type == RuntimeScalarType.BYTE_STRING, + reStrictMode(rawModifierStr), null, + preResolvedNamedCharacters).cloneTracked(); return new RuntimeScalar(compiled).propagateTaint(patternString); } @@ -1862,6 +1674,14 @@ static boolean containsExecutableSource(String pattern) { return containsExecutableSource(pattern, false); } + private static boolean isNamedCharacterDiagnostic(String message) { + return "Invalid character in \\N{...}".equals(message) + || "Zero length \\N{}".equals(message) + || "Invalid hexadecimal number in \\N{U+...}".equals(message) + || (message != null && message.startsWith( + "charnames alias definitions may not contain ")); + } + static boolean containsExecutableSource(String pattern, boolean extended) { if (pattern == null || pattern.isEmpty()) return false; boolean escaped = false; @@ -1943,7 +1763,7 @@ public static RuntimeScalar markSyntacticQuoteConstruction(RuntimeScalar quotedR RuntimeRegex regex = resolveRegex(quotedRegex); regex.quoteConstruction = true; for (String warning : regex.inlineModifierWarnings) { - RegexQuoteMeta.warnAtConstruction(warning); + RegexQuoteMeta.warnAtConstruction(warning, regex.lexicalReStrict); regex.warningsOnUse.remove(warning); } regex.inlineModifierWarnings.clear(); @@ -1967,7 +1787,7 @@ private static void validateTaintedPatternSecurity(RuntimeScalar patternString) } String property = matcher.group(2); - String qualified = property.contains("::") ? property : "main::" + property; + String qualified = UnicodeResolver.qualifyUserPropertyName(property); if (GlobalVariable.isGlobalCodeRefDefined(qualified)) { throw new PerlCompilerException( "Insecure user-defined property \"" + property + "\" in regex"); @@ -1987,6 +1807,15 @@ private static void validateTaintedPatternSecurity(RuntimeScalar patternString) * @return A RuntimeScalar representing the compiled regex. */ public static RuntimeScalar getQuotedRegex(RuntimeScalar patternString, RuntimeScalar modifiers, int callsiteId) { + NamedCharacterExpansionMap metadata = + patternString instanceof RuntimeRegexLiteralScalar literal + ? literal.namedCharacterExpansions() : null; + return getQuotedRegex(patternString, modifiers, callsiteId, metadata); + } + + public static RuntimeScalar getQuotedRegex( + RuntimeScalar patternString, RuntimeScalar modifiers, int callsiteId, + NamedCharacterExpansionMap preResolvedNamedCharacters) { String rawModifierStr = modifiers.toString(); String modifierStr = stripInternalMarkers(rawModifierStr); @@ -2001,13 +1830,14 @@ public static RuntimeScalar getQuotedRegex(RuntimeScalar patternString, RuntimeS } // Compile the regex and cache it - RuntimeScalar result = getQuotedRegex(patternString, modifiers); + RuntimeScalar result = getQuotedRegex( + patternString, modifiers, preResolvedNamedCharacters); state().optimizedRegexCache.put(callsiteId, result); return result; } // No /o or m?PAT? modifier, use normal compilation - return getQuotedRegex(patternString, modifiers); + return getQuotedRegex(patternString, modifiers, preResolvedNamedCharacters); } /** @@ -2031,14 +1861,17 @@ public static RuntimeScalar getReplacementRegex(RuntimeScalar patternString, Run RuntimeRegex regex = new RuntimeRegex(); // Always start with the resolved regex properties - regex.pattern = resolvedRegex.pattern; - regex.patternUnicode = resolvedRegex.patternUnicode; regex.recursivePattern = resolvedRegex.recursivePattern; regex.recursivePatternUnicode = resolvedRegex.recursivePatternUnicode; regex.recursivePatternBytes = resolvedRegex.recursivePatternBytes; + regex.namedCharacterCache = resolvedRegex.namedCharacterCache; + regex.namedCharacterSourceMode = resolvedRegex.namedCharacterSourceMode; + regex.namedCharacterTranslator = + copyScalarOrNull(resolvedRegex.namedCharacterTranslator); + regex.trustedCalloutCount = resolvedRegex.trustedCalloutCount; + regex.compiledRegexCacheKey = resolvedRegex.compiledRegexCacheKey; + regex.userPropertyPackage = resolvedRegex.userPropertyPackage; regex.executableCallbacks = resolvedRegex.executableCallbacks; - regex.patternNoInternalMarkers = resolvedRegex.patternNoInternalMarkers; - regex.patternUnicodeNoInternalMarkers = resolvedRegex.patternUnicodeNoInternalMarkers; regex.patternString = resolvedRegex.patternString; regex.patternByteBacked = resolvedRegex.patternByteBacked; regex.deferredUserDefinedUnicodeProperties = @@ -2047,7 +1880,6 @@ public static RuntimeScalar getReplacementRegex(RuntimeScalar patternString, Run regex.hasPreservesMatch = resolvedRegex.hasPreservesMatch; regex.quoteConstruction = resolvedRegex.quoteConstruction; regex.useGAssertion = resolvedRegex.useGAssertion; - regex.patternFlags = resolvedRegex.patternFlags; regex.hasCodeBlockCaptures = resolvedRegex.hasCodeBlockCaptures; regex.warningsOnUse = new ArrayList<>(resolvedRegex.warningsOnUse); regex.inlineModifierWarnings = new ArrayList<>(resolvedRegex.inlineModifierWarnings); @@ -2075,19 +1907,24 @@ public static RuntimeScalar getReplacementRegex(RuntimeScalar patternString, Run newFlags.toFlagString(), regex.lexicalDebugMode, resolvedRegex.executableCallbacks.size(), resolvedRegex.patternByteBacked, regex.lexicalReStrict); - regex.pattern = recompiledRegex.pattern; - regex.patternUnicode = recompiledRegex.patternUnicode; regex.recursivePattern = recompiledRegex.recursivePattern; regex.recursivePatternUnicode = recompiledRegex.recursivePatternUnicode; regex.recursivePatternBytes = recompiledRegex.recursivePatternBytes; + regex.namedCharacterCache = recompiledRegex.namedCharacterCache; + regex.namedCharacterSourceMode = recompiledRegex.namedCharacterSourceMode; + regex.namedCharacterTranslator = + copyScalarOrNull(recompiledRegex.namedCharacterTranslator); + regex.trustedCalloutCount = recompiledRegex.trustedCalloutCount; + regex.compiledRegexCacheKey = recompiledRegex.compiledRegexCacheKey; + regex.userPropertyPackage = recompiledRegex.userPropertyPackage; regex.executableCallbacks = resolvedRegex.executableCallbacks; - regex.patternNoInternalMarkers = recompiledRegex.patternNoInternalMarkers; - regex.patternUnicodeNoInternalMarkers = recompiledRegex.patternUnicodeNoInternalMarkers; regex.patternString = recompiledRegex.patternString; + regex.patternByteBacked = recompiledRegex.patternByteBacked; regex.regexFlags = recompiledRegex.regexFlags; + regex.deferredUserDefinedUnicodeProperties = + recompiledRegex.deferredUserDefinedUnicodeProperties; regex.hasPreservesMatch = recompiledRegex.hasPreservesMatch; regex.useGAssertion = recompiledRegex.useGAssertion; - regex.patternFlags = recompiledRegex.patternFlags; regex.hasCodeBlockCaptures = recompiledRegex.hasCodeBlockCaptures; regex.warningsOnUse = new ArrayList<>(recompiledRegex.warningsOnUse); regex.inlineModifierWarnings = new ArrayList<>( @@ -2099,7 +1936,6 @@ public static RuntimeScalar getReplacementRegex(RuntimeScalar patternString, Run regex.regexFlags = newFlags; regex.hasPreservesMatch = regex.hasPreservesMatch || newFlags.preservesMatch(); regex.useGAssertion = newFlags.useGAssertion(); - regex.patternFlags = newFlags.toPatternFlags(); } } @@ -2140,7 +1976,8 @@ public static RuntimeScalar getBytesReplacementRegex(RuntimeScalar patternString : patternString.type == RuntimeScalarType.BYTE_STRING; regex.recursivePatternBytes = new JoniRegexPattern(sourcePattern, regex.regexFlags, regex.executableCallbacks.size(), true, - true, byteBackedPattern, regex.namedCharacterCache); + true, byteBackedPattern, regex.namedCharacterCache, + regex.lexicalReStrict); } return result; } @@ -2152,13 +1989,39 @@ private static boolean containsNonAscii(String value) { return false; } - /** Perl named characters and wide numeric escapes make an ASCII source Unicode. */ + /** Syntax with intrinsic Unicode semantics makes an ASCII source Unicode. */ private static boolean hasUnicodePromotingPatternSyntax(String pattern) { if (pattern == null) return false; boolean quoted = false; + int characterClassDepth = 0; + boolean[] classAtStart = new boolean[pattern.length() + 1]; for (int i = 0; i < pattern.length(); i++) { char ch = pattern.charAt(i); if (ch > 0xff) return true; + if (!quoted && ch == '[') { + if (characterClassDepth > 0) { + // A nested opener (including the '[' in a POSIX class) + // consumes the parent class's first member position. + classAtStart[characterClassDepth - 1] = false; + } + classAtStart[characterClassDepth] = true; + characterClassDepth++; + continue; + } + if (!quoted && ch == ']' && characterClassDepth > 0) { + if (classAtStart[characterClassDepth - 1]) { + // A close bracket immediately after '[' or '[^' is a + // literal member, not the end of the character class. + classAtStart[characterClassDepth - 1] = false; + continue; + } + characterClassDepth--; + continue; + } + if (!quoted && characterClassDepth > 0 + && classAtStart[characterClassDepth - 1]) { + if (ch != '^') classAtStart[characterClassDepth - 1] = false; + } if (ch != '\\' || i + 1 >= pattern.length()) continue; char escape = pattern.charAt(++i); @@ -2171,6 +2034,9 @@ private static boolean hasUnicodePromotingPatternSyntax(String pattern) { continue; } if (quoted || escape == '\\') continue; + if ((escape == 'p' || escape == 'P') && characterClassDepth == 0) { + return true; + } if (escape == 'N' && i + 1 < pattern.length() && pattern.charAt(i + 1) == '{') { return true; @@ -2340,6 +2206,39 @@ private static void updateNumberedCaptureGroups(RegexMatcher matcher) { /** * Direct regex matching without timeout wrapper (fast path). */ + /** + * Resolve Perl's empty-pattern reuse without retaining Java matcher state. + * A changed modifier set needs a complete native recompilation; otherwise a + * tracked wrapper around the last native compiled form is sufficient. + */ + private static RuntimeRegex emptyPatternReuse(RuntimeRegex previous, + RegexFlags flags, + int lexicalDebugMode, + boolean lexicalReStrict, + RuntimeScalar replacement) { + RuntimeRegex reused; + if (previous != null && (flags == null || flags.equals(previous.regexFlags))) { + reused = previous.cloneTracked(); + } else { + String source = previous == null ? "" : previous.patternString; + String modifiers = flags == null ? "" : flags.toFlagString(); + int debugMode = lexicalDebugMode != 0 + ? lexicalDebugMode + : (previous == null ? 0 : previous.lexicalDebugMode); + reused = compile(source, modifiers, debugMode, 0, + previous != null && previous.patternByteBacked, + lexicalReStrict || (previous != null && previous.lexicalReStrict)); + } + reused.regexFlags = flags == null ? reused.regexFlags : flags; + reused.hasPreservesMatch = reused.hasPreservesMatch + || (flags != null && flags.preservesMatch()); + reused.lexicalDebugMode = lexicalDebugMode != 0 ? lexicalDebugMode : reused.lexicalDebugMode; + reused.lexicalReStrict = lexicalReStrict || reused.lexicalReStrict; + reused.useGAssertion = flags != null && flags.useGAssertion(); + reused.replacement = replacement; + return reused; + } + private static RuntimeBase matchRegexDirect(RuntimeScalar quotedRegex, RuntimeScalar string, int ctx) { RuntimeRegexState regexState = state(); RuntimeRegex regex = resolveRegex(quotedRegex); @@ -2354,51 +2253,19 @@ private static RuntimeBase matchRegexDirect(RuntimeScalar quotedRegex, RuntimeSc if (regexState.lastSuccessfulPattern != null) { // Use the pattern from last successful match // But keep the current flags (especially /g and /i) - Pattern pattern = regexState.lastSuccessfulPattern.pattern; - // Re-apply current flags if they differ - if (originalFlags != null && !originalFlags.equals(regexState.lastSuccessfulPattern.regexFlags)) { - // Need to recompile with current flags using preprocessed pattern - int newFlags = originalFlags.toPatternFlags(); - String recompilePattern = regexState.lastSuccessfulPattern.javaPatternString != null - ? regexState.lastSuccessfulPattern.javaPatternString : regexState.lastSuccessfulPattern.patternString; - pattern = Pattern.compile(recompilePattern, newFlags); - } - // Create a temporary regex with the right pattern and current flags - RuntimeRegex tempRegex = new RuntimeRegex(); - tempRegex.pattern = pattern; - tempRegex.patternUnicode = regexState.lastSuccessfulPattern.patternUnicode; - tempRegex.recursivePattern = regexState.lastSuccessfulPattern.recursivePattern; - tempRegex.recursivePatternUnicode = - regexState.lastSuccessfulPattern.recursivePatternUnicode; - tempRegex.executableCallbacks = regexState.lastSuccessfulPattern.executableCallbacks; - tempRegex.patternNoInternalMarkers = regexState.lastSuccessfulPattern.patternNoInternalMarkers; - tempRegex.patternUnicodeNoInternalMarkers = regexState.lastSuccessfulPattern.patternUnicodeNoInternalMarkers; - tempRegex.patternString = regexState.lastSuccessfulPattern.patternString; - tempRegex.javaPatternString = regexState.lastSuccessfulPattern.javaPatternString; - tempRegex.requiredLiteral = regexState.lastSuccessfulPattern.requiredLiteral; - tempRegex.hasPreservesMatch = regexState.lastSuccessfulPattern.hasPreservesMatch || (originalFlags != null && originalFlags.preservesMatch()); - tempRegex.warningsOnUse = new ArrayList<>(regexState.lastSuccessfulPattern.warningsOnUse); - tempRegex.inlineModifierWarnings = new ArrayList<>( - regexState.lastSuccessfulPattern.inlineModifierWarnings); - tempRegex.lexicalDebugMode = regex.lexicalDebugMode != 0 - ? regex.lexicalDebugMode - : regexState.lastSuccessfulPattern.lexicalDebugMode; - tempRegex.lexicalReStrict = regex.lexicalReStrict - || regexState.lastSuccessfulPattern.lexicalReStrict; - tempRegex.regexFlags = originalFlags; - tempRegex.useGAssertion = originalFlags != null && originalFlags.useGAssertion(); - regex = tempRegex; + regex = emptyPatternReuse(regexState.lastSuccessfulPattern, originalFlags, + regex.lexicalDebugMode, regex.lexicalReStrict, null); + } else { + regex = emptyPatternReuse(null, originalFlags, + regex.lexicalDebugMode, regex.lexicalReStrict, null); } - // If no previous pattern, the empty pattern matches empty string at start (default behavior) } regex.emitWarningsOnUse(); // Debug logging if (DEBUG_REGEX) { - String description = regex.recursivePattern != null - ? regex.recursivePattern.patternDescription() - : regex.pattern.pattern(); + String description = regex.recursivePattern.patternDescription(); System.err.println("matchRegexDirect: pattern=" + description + " input=" + string.toString() + " ctx=" + ctx); } @@ -2417,23 +2284,8 @@ private static RuntimeBase matchRegexDirect(RuntimeScalar quotedRegex, RuntimeSc String inputStr = string.toString(); regex.emitNonUnicodePropertyWarning(string, inputStr); regex.emitExecutionDebugTrace(inputStr); - CharSequence matchInput = new RegexTimeoutCharSequence(inputStr); - RegexMatcher matcher; - if (regex.recursivePattern != null) { - matcher = regex.selectRecursivePattern(string) - .matcher(inputStr, regex.executableCallbacks, string); - } else { - Pattern pattern = regex.selectPattern(string, inputStr); - - // Workaround for Java MULTILINE quirk: Java's Pattern.MULTILINE changes ^ to only - // match after line terminators, so "^" fails on empty strings. In Perl, /m makes ^ - // and $ match at line boundaries AND at start/end of string. Since empty strings have - // no line breaks, MULTILINE is irrelevant and we can safely strip it. - if (inputStr.isEmpty() && (pattern.flags() & Pattern.MULTILINE) != 0) { - pattern = Pattern.compile(pattern.pattern(), pattern.flags() & ~Pattern.MULTILINE); - } - matcher = new JavaRegexMatcher(pattern.matcher(matchInput)); - } + RegexMatcher matcher = regex.selectRecursivePattern(string) + .matcher(inputStr, regex.executableCallbacks, string); // hexPrinter(inputStr); @@ -2476,7 +2328,7 @@ private static RuntimeBase matchRegexDirect(RuntimeScalar quotedRegex, RuntimeSc string, posScalar.getInt(), patternKey)) { // First, try the notempty variant at the SAME position (Perl behavior) RegexMatcher notemptyMatcher = findNonEmptyGlobalRetry( - regex, string, inputStr, matchInput, startPos); + regex, string, inputStr, startPos); boolean notemptySucceeded = notemptyMatcher != null; if (notemptySucceeded) { matcher = notemptyMatcher; @@ -2507,26 +2359,6 @@ private static RuntimeBase matchRegexDirect(RuntimeScalar quotedRegex, RuntimeSc nativeGlobalPosition = matcher.setGlobalPosition(startPos); } - if (regex.requiredLiteral != null && !inputStr.contains(regex.requiredLiteral)) { - if (DEBUG_REGEX) { - System.err.println(" required literal prefilter failed: " + regex.requiredLiteral); - } - if (regex.regexFlags.isGlobalMatch() && !regex.regexFlags.keepCurrentPosition() && posScalar != null) { - posScalar.set(scalarUndef); - } - regexState.globalMatchString = null; - regexState.lastMatchedString = null; - regexState.lastMatchStart = -1; - regexState.lastMatchEnd = -1; - if (ctx == RuntimeContextType.LIST) { - return new RuntimeList(); - } else if (ctx == RuntimeContextType.SCALAR) { - return RuntimeScalarCache.scalarFalse; - } else { - return scalarUndef; - } - } - // Start matching from the current position if defined // (skip if notempty variant already found a match - region() would reset the matcher) if (isPosDefined && !skipFirstFind) { @@ -2660,7 +2492,7 @@ private static RuntimeBase matchRegexDirect(RuntimeScalar quotedRegex, RuntimeSc } if (zeroLengthMatch) { RegexMatcher notemptyMatcher = findNonEmptyGlobalRetry( - regex, string, inputStr, matchInput, startPos); + regex, string, inputStr, startPos); if (notemptyMatcher != null) { matcher = notemptyMatcher; skipFirstFind = true; @@ -2679,8 +2511,8 @@ private static RuntimeBase matchRegexDirect(RuntimeScalar quotedRegex, RuntimeSc WarnDie.warn(new RuntimeScalar(e.getMessage() + "\n"), RuntimeScalarCache.scalarEmptyString); found = false; } catch (StackOverflowError e) { - // Java's backtracking engine uses the native stack for some nested - // quantifiers. Perl reports an unsuccessful match when its own + // Joni uses the native stack for some nested quantifiers. Perl + // reports an unsuccessful match when its own // recursion ceiling is reached; do not let the JVM error abort the // whole program for the equivalent pathological failure case. found = false; @@ -2753,13 +2585,13 @@ private static RuntimeBase matchRegexDirect(RuntimeScalar quotedRegex, RuntimeSc } /** - * Avoid Java Pattern recursion for ExifTool's XMP element scan: + * Avoid deep matcher recursion for ExifTool's XMP element scan: * {@code <(/?)x:xmpmeta([-\w:.\x80-\xff]*)(.*?(/?))>}. * - *

    On Google extended-XMP payloads, Java's backtracking engine can - * recurse deeply enough to throw {@link StackOverflowError}, while Perl - * handles the scan iteratively. This narrow path preserves the captures - * ExifTool uses while keeping other regexes on the normal engine.

    + *

    On Google extended-XMP payloads, a generic backtracking scan can + * recurse deeply enough to throw {@link StackOverflowError}. This narrow + * path preserves the captures ExifTool uses while keeping other regexes on + * the normal Joni engine.

    */ private static RuntimeBase tryFastXmpMetaElementScan(RuntimeRegex regex, RuntimeScalar string, @@ -2856,14 +2688,11 @@ private static RuntimeBase tryFastXmpMetaElementScan(RuntimeRegex regex, private static boolean isXmpMetaElementScanPattern(RuntimeRegex regex) { String perlPattern = "<(/?)x:xmpmeta([-\\w:.\\x80-\\xff]*)(.*?(/?))>"; - if (perlPattern.equals(regex.patternString)) { - return true; - } - return regex.pattern != null && perlPattern.equals(regex.pattern.pattern()); + return perlPattern.equals(regex.patternString); } /** - * Avoid Java Pattern recursion for ExifTool's generic XML element scan: + * Avoid deep matcher recursion for ExifTool's generic XML element scan: * {@code <([?/]?)([-\w:.\x80-\xff]+|!--)([^>]*)>}. */ private static RuntimeBase tryFastXmlElementScan(RuntimeRegex regex, @@ -2929,10 +2758,7 @@ private static RuntimeBase tryFastXmlElementScan(RuntimeRegex regex, private static boolean isXmlElementScanPattern(RuntimeRegex regex) { String perlPattern = "<([?/]?)([-\\w:.\\x80-\\xff]+|!--)([^>]*)>"; - if (perlPattern.equals(regex.patternString)) { - return true; - } - return regex.pattern != null && perlPattern.equals(regex.pattern.pattern()); + return perlPattern.equals(regex.patternString); } private static XmlElementMatch findXmlElement(String inputStr, int startPos) { @@ -3117,14 +2943,6 @@ private static RuntimeBase matchRegexWithTimeout(RuntimeScalar quotedRegex, Runt * @param ctx The context LIST, SCALAR, VOID. * @return A RuntimeScalar or RuntimeList. */ - private static Pattern compileNonEmptySubstitutionPattern(Pattern pattern) { - try { - return Pattern.compile("(?:" + pattern.pattern() + ")(?<=[\\s\\S])", pattern.flags()); - } catch (RuntimeException e) { - return null; - } - } - private static int bumpGlobalMatchPosition(String inputStr, int offset) { if (offset >= inputStr.length()) { return inputStr.length() + 1; @@ -3135,45 +2953,16 @@ private static int bumpGlobalMatchPosition(String inputStr, int offset) { private static RegexMatcher findNonEmptyGlobalRetry(RuntimeRegex regex, RuntimeScalar string, String inputStr, - CharSequence matchInput, int startPos) { - RegexMatcher retryMatcher; - boolean nativeNotEmpty; - if (regex.recursivePattern != null) { - retryMatcher = regex.selectRecursivePattern(string) - .matcher(inputStr, regex.executableCallbacks, string); - nativeNotEmpty = true; - } else { - Pattern notemptyPattern = regex.notemptyPattern; - if (regex.notemptyPatternUnicode != null - && regex.notemptyPatternUnicode != regex.notemptyPattern - && !(regex.regexFlags != null && regex.regexFlags.isAscii()) - && !hasInlineAsciiModifier(regex.patternString) - && Utf8.isUtf8(string)) { - notemptyPattern = regex.notemptyPatternUnicode; - } - if (notemptyPattern == null) { - // A compiled qr// can be created without /g and interpolated - // later into a global match. Build its retry form lazily from - // the selected byte/Unicode Java pattern. - notemptyPattern = compileNonEmptySubstitutionPattern( - regex.selectPattern(string, inputStr)); - if (notemptyPattern == null) { - return null; - } - } - retryMatcher = new JavaRegexMatcher(notemptyPattern.matcher(matchInput)); - nativeNotEmpty = false; - } + RegexMatcher retryMatcher = regex.selectRecursivePattern(string) + .matcher(inputStr, regex.executableCallbacks, string); retryMatcher.region(startPos, inputStr.length()); retryMatcher.useAnchoringBounds(false); if (regex.useGAssertion) { retryMatcher.setGlobalPosition(startPos); } - boolean found = nativeNotEmpty - ? retryMatcher.findNotEmpty() - : retryMatcher.find(); + boolean found = retryMatcher.findNotEmpty(); return found && retryMatcher.consumedStart() == startPos && retryMatcher.end() > startPos @@ -3262,69 +3051,20 @@ public static RuntimeBase replaceRegex(RuntimeScalar quotedRegex, RuntimeScalar if (state().lastSuccessfulPattern != null) { // Use the pattern from last successful match // But keep the current replacement and flags (especially /g and /i) - Pattern pattern = state().lastSuccessfulPattern.pattern; - // Re-apply current flags if they differ - if (originalFlags != null && !originalFlags.equals(state().lastSuccessfulPattern.regexFlags)) { - // Need to recompile with current flags using preprocessed pattern - int newFlags = originalFlags.toPatternFlags(); - String recompilePattern = state().lastSuccessfulPattern.javaPatternString != null - ? state().lastSuccessfulPattern.javaPatternString : state().lastSuccessfulPattern.patternString; - pattern = Pattern.compile(recompilePattern, newFlags); - } - // Create a temporary regex with the right pattern and current flags - RuntimeRegex tempRegex = new RuntimeRegex(); - tempRegex.pattern = pattern; - tempRegex.patternUnicode = state().lastSuccessfulPattern.patternUnicode; - tempRegex.recursivePattern = state().lastSuccessfulPattern.recursivePattern; - tempRegex.recursivePatternUnicode = - state().lastSuccessfulPattern.recursivePatternUnicode; - tempRegex.executableCallbacks = state().lastSuccessfulPattern.executableCallbacks; - tempRegex.patternNoInternalMarkers = state().lastSuccessfulPattern.patternNoInternalMarkers; - tempRegex.patternUnicodeNoInternalMarkers = state().lastSuccessfulPattern.patternUnicodeNoInternalMarkers; - tempRegex.patternString = state().lastSuccessfulPattern.patternString; - tempRegex.javaPatternString = state().lastSuccessfulPattern.javaPatternString; - tempRegex.hasPreservesMatch = state().lastSuccessfulPattern.hasPreservesMatch || (originalFlags != null && originalFlags.preservesMatch()); - tempRegex.warningsOnUse = new ArrayList<>(state().lastSuccessfulPattern.warningsOnUse); - tempRegex.inlineModifierWarnings = new ArrayList<>( - state().lastSuccessfulPattern.inlineModifierWarnings); - tempRegex.regexFlags = originalFlags; - tempRegex.useGAssertion = originalFlags != null && originalFlags.useGAssertion(); - tempRegex.replacement = replacement; - regex = tempRegex; + regex = emptyPatternReuse(state().lastSuccessfulPattern, originalFlags, + regex.lexicalDebugMode, regex.lexicalReStrict, replacement); } else { // No previous regex - use empty pattern (matches empty string at start) // This matches Perl's behavior: s//x/ inserts 'x' at the beginning - RuntimeRegex tempRegex = new RuntimeRegex(); - int flags = originalFlags != null ? originalFlags.toPatternFlags() : 0; - tempRegex.pattern = Pattern.compile("", flags); - tempRegex.patternUnicode = tempRegex.pattern; // Empty pattern - same for both - tempRegex.patternString = ""; - tempRegex.regexFlags = originalFlags; - tempRegex.useGAssertion = originalFlags != null && originalFlags.useGAssertion(); - tempRegex.replacement = replacement; - regex = tempRegex; + regex = emptyPatternReuse(null, originalFlags, + regex.lexicalDebugMode, regex.lexicalReStrict, replacement); } } regex.emitWarningsOnUse(); - CharSequence matchInput = new RegexTimeoutCharSequence(inputStr); - Pattern pattern = null; - RegexMatcher matcher; - if (regex.recursivePattern != null) { - matcher = regex.selectRecursivePattern(inputValue) - .matcher(inputStr, regex.executableCallbacks, inputValue); - } else { - pattern = regex.selectPattern(inputValue, inputStr); - if (inputStr.isEmpty() && (pattern.flags() & Pattern.MULTILINE) != 0) { - pattern = Pattern.compile(pattern.pattern(), pattern.flags() & ~Pattern.MULTILINE); - } - matcher = new JavaRegexMatcher(pattern.matcher(matchInput)); - } - Pattern nonEmptySubstitutionPattern = pattern != null - && regex.regexFlags != null && regex.regexFlags.isGlobalMatch() - ? compileNonEmptySubstitutionPattern(pattern) - : null; + RegexMatcher matcher = regex.selectRecursivePattern(inputValue) + .matcher(inputStr, regex.executableCallbacks, inputValue); int searchStart = 0; int globalPosition = 0; boolean nativeGlobalPosition = false; @@ -3439,18 +3179,14 @@ public static RuntimeBase replaceRegex(RuntimeScalar quotedRegex, RuntimeScalar int zeroLengthOffset = matcher.end(); boolean consumedNonEmptyRetry = false; - if ((nonEmptySubstitutionPattern != null || regex.recursivePattern != null) - && zeroLengthOffset <= inputStr.length()) { - RegexMatcher retryMatcher = nonEmptySubstitutionPattern != null - ? new JavaRegexMatcher(nonEmptySubstitutionPattern.matcher(matchInput)) - : regex.selectRecursivePattern(inputValue) - .matcher(inputStr, regex.executableCallbacks, inputValue); + if (zeroLengthOffset <= inputStr.length()) { + RegexMatcher retryMatcher = regex.selectRecursivePattern(inputValue) + .matcher(inputStr, regex.executableCallbacks, inputValue); // The synthetic (?<=[\s\S]) suffix relies on opaque bounds // so a zero-length match at the region start is rejected. setSubstitutionRegion(retryMatcher, zeroLengthOffset, inputStr.length(), false); if (nativeGlobalPosition) retryMatcher.setGlobalPosition(zeroLengthOffset); - boolean retryFound = nonEmptySubstitutionPattern != null - ? retryMatcher.find() : retryMatcher.findNotEmpty(); + boolean retryFound = retryMatcher.findNotEmpty(); if (retryFound && retryMatcher.start() == zeroLengthOffset && retryMatcher.end() > zeroLengthOffset) { @@ -3781,31 +3517,48 @@ private static boolean hasUnicodeChars(String s) { } /** - * Check if a pattern contains inline ASCII modifier (?a...). - * When present, we should use ASCII matching even for UTF-8 strings with non-ASCII content. - * - * @param pattern The pattern string to check - * @return true if the pattern contains inline (?a...) modifier + * A scoped {@code /u}, {@code /a}, or {@code /aa} group must use the UTF-8 + * Joni variant even when its containing qr// originated in a byte scalar. + * The byte variant carries {@code PERL_BYTE_PATTERN}, whose global + * case-fold policy deliberately excludes Latin-1 folds; that policy cannot + * be relaxed by a nested charset group. */ - private static boolean hasInlineAsciiModifier(String pattern) { - if (pattern == null) { - return false; - } - // Check for (?a...) inline modifier - matches (?a, (?a:, (?ai, (?ia, etc. - // The 'a' must appear in the modifier position after (? - int idx = 0; - while ((idx = pattern.indexOf("(?", idx)) >= 0) { - idx += 2; - // Scan modifier characters until we hit : or ) - while (idx < pattern.length()) { - char c = pattern.charAt(idx); - if (c == 'a') { - return true; // Found inline ASCII modifier - } - if (c == ':' || c == ')' || c == '-' || c == '<' || c == '=' || c == '!' || c == '{' || c == '#') { - break; // End of modifier section + private static boolean hasInlineUnicodeCaseFoldModifier(String pattern) { + if (pattern == null) return false; + + boolean escaped = false; + boolean inClass = false; + for (int i = 0; i + 2 < pattern.length(); i++) { + char current = pattern.charAt(i); + if (escaped) { + escaped = false; + continue; + } + if (current == '\\') { + escaped = true; + continue; + } + if (current == '[') { + inClass = true; + continue; + } + if (current == ']' && inClass) { + inClass = false; + continue; + } + if (inClass || current != '(' || pattern.charAt(i + 1) != '?') continue; + + boolean negated = false; + for (int j = i + 2; j < pattern.length(); j++) { + char modifier = pattern.charAt(j); + if (modifier == ':' || modifier == ')') break; + if (modifier == '-') { + negated = true; + continue; } - idx++; + if (modifier == '^') continue; + if (modifier < 'a' || modifier > 'z') break; + if ((modifier == 'u' || modifier == 'a') && !negated) return true; } } return false; diff --git a/src/main/java/org/perlonjava/runtime/regex/RuntimeRegexCallback.java b/src/main/java/org/perlonjava/runtime/regex/RuntimeRegexCallback.java index feb45966c5..4547dfefcf 100644 --- a/src/main/java/org/perlonjava/runtime/regex/RuntimeRegexCallback.java +++ b/src/main/java/org/perlonjava/runtime/regex/RuntimeRegexCallback.java @@ -4,6 +4,8 @@ import org.perlonjava.runtime.runtimetypes.RuntimeScalar; import org.perlonjava.runtime.operators.WarnDie; +import java.util.function.Function; + /** A parser-created executable segment in a regex template. */ public final class RuntimeRegexCallback { public enum Kind { BLOCK, CONDITION, DYNAMIC } @@ -13,16 +15,18 @@ public enum Kind { BLOCK, CONDITION, DYNAMIC } final String sourceLocation; final String lexicalPackage; final String source; + final boolean uninitializedWarningsEnabled; private int ownerCount; private RuntimeRegexCallback( RuntimeCode code, Kind kind, String sourceLocation, String lexicalPackage, - String source) { + String source, boolean uninitializedWarningsEnabled) { this.code = code; this.kind = kind; this.sourceLocation = sourceLocation; this.lexicalPackage = lexicalPackage; this.source = source; + this.uninitializedWarningsEnabled = uninitializedWarningsEnabled; } synchronized void retainOwner() { @@ -43,6 +47,14 @@ synchronized void releaseOwner() { } } + /** Exact metadata copy for an ithread graph clone with a child-owned CODE pad. */ + public RuntimeRegexCallback cloneForThread( + Function codeCloner) { + return new RuntimeRegexCallback( + codeCloner.apply(code), kind, sourceLocation, lexicalPackage, + source, uninitializedWarningsEnabled); + } + public static RuntimeScalar wrap(RuntimeScalar codeRef, String kindName) { return wrap(codeRef, kindName, null); } @@ -54,6 +66,12 @@ public static RuntimeScalar wrap( public static RuntimeScalar wrap( RuntimeScalar codeRef, String kindName, String lexicalPackage, String source) { + return wrap(codeRef, kindName, lexicalPackage, source, true); + } + + public static RuntimeScalar wrap( + RuntimeScalar codeRef, String kindName, String lexicalPackage, String source, + boolean uninitializedWarningsEnabled) { if (!(codeRef.value instanceof RuntimeCode code)) { throw new IllegalArgumentException("regex callback is not a code reference"); } @@ -68,6 +86,6 @@ public static RuntimeScalar wrap( return new RuntimeScalar(new RuntimeRegexCallback( code, Kind.valueOf(kindName), sourceLocation, lexicalPackage != null ? lexicalPackage : code.packageName, - source)); + source, uninitializedWarningsEnabled)); } } diff --git a/src/main/java/org/perlonjava/runtime/regex/RuntimeRegexLiteralScalar.java b/src/main/java/org/perlonjava/runtime/regex/RuntimeRegexLiteralScalar.java new file mode 100644 index 0000000000..6e7bdb1c07 --- /dev/null +++ b/src/main/java/org/perlonjava/runtime/regex/RuntimeRegexLiteralScalar.java @@ -0,0 +1,19 @@ +package org.perlonjava.runtime.regex; + +import org.perlonjava.runtime.NamedCharacterExpansionMap; +import org.perlonjava.runtime.runtimetypes.RuntimeScalar; + +/** A pattern scalar carrying immutable lexical regex metadata from its CV. */ +public final class RuntimeRegexLiteralScalar extends RuntimeScalar { + private final NamedCharacterExpansionMap namedCharacterExpansions; + + RuntimeRegexLiteralScalar( + RuntimeScalar pattern, NamedCharacterExpansionMap namedCharacterExpansions) { + super(pattern); + this.namedCharacterExpansions = namedCharacterExpansions; + } + + public NamedCharacterExpansionMap namedCharacterExpansions() { + return namedCharacterExpansions; + } +} diff --git a/src/main/java/org/perlonjava/runtime/regex/RuntimeRegexSourceCompiler.java b/src/main/java/org/perlonjava/runtime/regex/RuntimeRegexSourceCompiler.java index 50b3b0851b..f6992a83ae 100644 --- a/src/main/java/org/perlonjava/runtime/regex/RuntimeRegexSourceCompiler.java +++ b/src/main/java/org/perlonjava/runtime/regex/RuntimeRegexSourceCompiler.java @@ -37,8 +37,28 @@ private RuntimeRegexSourceCompiler() {} static RuntimeScalar compile(RuntimeScalar pattern, String modifiers) { RuntimeCode owner = RuntimeCode.getActiveCodeAt(0); - Map cells = owner == null - ? Map.of() : RuntimeCode.snapshotActiveLexicals(owner); + Map cells = new LinkedHashMap<>(); + if (owner != null) { + cells.putAll(RuntimeCode.snapshotActiveLexicals(owner)); + } + // Eval STRING code enters with its outer lexical cells preloaded in + // captured registers. Those registers have no declaration opcode in + // the eval body, so they are not added to the active-frame map. Merge + // them explicitly before strict-vars validation and callback capture; + // a live active binding wins whenever both routes provide a cell. + if (owner instanceof InterpretedCode interpreted + && interpreted.capturedVars != null) { + for (Map.Entry entry + : interpreted.variableRegistry.entrySet()) { + int capturedIndex = entry.getValue() - 3; + if (capturedIndex >= 0 + && capturedIndex < interpreted.capturedVars.length + && interpreted.capturedVars[capturedIndex] != null) { + cells.putIfAbsent( + entry.getKey(), interpreted.capturedVars[capturedIndex]); + } + } + } Map orderedCells = new LinkedHashMap<>(); for (Map.Entry entry : cells.entrySet()) { String name = entry.getKey(); @@ -52,12 +72,13 @@ static RuntimeScalar compile(RuntimeScalar pattern, String modifiers) { String publicModifiers = modifiers.replace("E", "").replace("T", "") .replace(String.valueOf(RuntimeRegex.INTERNAL_DEBUG_MARKER), "") - .replace(String.valueOf(RuntimeRegex.INTERNAL_DEBUGCOLOR_MARKER), ""); + .replace(String.valueOf(RuntimeRegex.INTERNAL_DEBUGCOLOR_MARKER), "") + .replace(String.valueOf(RuntimeRegex.INTERNAL_RE_STRICT_MARKER), ""); // qr// accepts pattern modifiers, not operation modifiers such as the // trailing marker used for m?PAT?. Reapply the complete operation flag // set to the compiled qr object below. String sourceModifiers = publicModifiers.replaceAll("[gcr?op]", ""); - String source = "qr~" + pattern.toString().replace("~", "\\~") + String source = "qr~" + escapeDelimiter(pattern.toString(), '~') + "~" + sourceModifiers; // Perl compiles each executable runtime pattern as a distinct eval, // so diagnostics and warnings use an independent (eval N) filename. @@ -74,7 +95,13 @@ static RuntimeScalar compile(RuntimeScalar pattern, String modifiers) { symbolTable.addVariable("this", "", null); symbolTable.addVariable("@_", "our", null); symbolTable.addVariable("wantarray", "", null); - symbolTable.enableStrictOption(HINT_RE_EVAL); + // Runtime callback source is an eval at the regex construction + // site. Preserve that site's complete $^H state so strict subs, + // vars, refs, bytes, and related lexical policy validate the + // callback while it is compiled, rather than deferring malformed + // code until the first match executes. + symbolTable.setStrictOptions( + WarningBitsRegistry.getCallSiteHints() | HINT_RE_EVAL); symbolTable.enableLexicalRegexModifiers( publicModifiers.replaceAll("[^imsx]", "")); String warningBits = RegexQuoteMeta.getCallSiteWarningBits(); @@ -117,17 +144,36 @@ static RuntimeScalar compile(RuntimeScalar pattern, String modifiers) { Node ast = new Parser(context, tokens).parse(); InterpretedCode code = new BytecodeCompiler( sourceName, sourceLine, errors, registry).compile(ast, context); - code = code.withCapturedVars(orderedCells.values().toArray(new RuntimeBase[0])); + int highestCapturedRegister = 2; + for (int compiledRegister : code.variableRegistry.values()) { + highestCapturedRegister = Math.max( + highestCapturedRegister, compiledRegister); + } + RuntimeBase[] capturedCells = + new RuntimeBase[highestCapturedRegister - 2]; + for (Map.Entry entry : orderedCells.entrySet()) { + Integer compiledRegister = code.variableRegistry.get(entry.getKey()); + if (compiledRegister != null && compiledRegister >= 3) { + capturedCells[compiledRegister - 3] = entry.getValue(); + } + } + code = code.withCapturedVars(capturedCells); if (owner != null) { code.__SUB__ = owner.__SUB__ != null ? owner.__SUB__ : new RuntimeScalar(owner); } RuntimeList result = code.apply(new RuntimeArray(), RuntimeContextType.SCALAR); RuntimeScalar compiled = result.scalar().propagateTaint(pattern); - if (compiled.value instanceof RuntimeRegex && !modifiers.isEmpty()) { + // Pattern modifiers were already parsed by the synthetic qr// source + // above. Reapplying them through getQuotedRegex() merges flags again; + // that loses the second 'a' of /aa because ordinary flag merging + // deduplicates modifier characters. Only operation modifiers belong + // to the outer runtime regexp operation. + String operationModifiers = publicModifiers.replaceAll("[nimsxpadeul]", ""); + if (compiled.value instanceof RuntimeRegex && !operationModifiers.isEmpty()) { RuntimeScalar unmodified = compiled; compiled = RuntimeRegex.getQuotedRegex( - unmodified, new RuntimeScalar(modifiers)).propagateTaint(pattern); + unmodified, new RuntimeScalar(operationModifiers)).propagateTaint(pattern); if (compiled.value != unmodified.value && unmodified.value instanceof RuntimeRegex temporary) { temporary.releaseExecutableCallbacks(); @@ -139,6 +185,22 @@ static RuntimeScalar compile(RuntimeScalar pattern, String modifiers) { } } + /** Quote a non-paired qr delimiter without changing regex backslash parity. */ + private static String escapeDelimiter(String pattern, char delimiter) { + StringBuilder escaped = new StringBuilder(pattern.length()); + int precedingBackslashes = 0; + for (int i = 0; i < pattern.length(); i++) { + char current = pattern.charAt(i); + if (current == delimiter && (precedingBackslashes & 1) == 0) { + escaped.append('\\'); + } + escaped.append(current); + precedingBackslashes = current == '\\' + ? precedingBackslashes + 1 : 0; + } + return escaped.toString(); + } + static RuntimeScalar compileTemplate(RuntimeScalar original, RuntimeRegexTemplate template, String modifiers) { diff --git a/src/main/java/org/perlonjava/runtime/regex/RuntimeRegexTemplate.java b/src/main/java/org/perlonjava/runtime/regex/RuntimeRegexTemplate.java index 3b5c6978a0..4a9d11604a 100644 --- a/src/main/java/org/perlonjava/runtime/regex/RuntimeRegexTemplate.java +++ b/src/main/java/org/perlonjava/runtime/regex/RuntimeRegexTemplate.java @@ -14,19 +14,18 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - import static org.perlonjava.runtime.runtimetypes.RuntimeScalarCache.scalarUndef; /** Runtime interpolation result that keeps executable regex callbacks out of strings. */ public final class RuntimeRegexTemplate { - private static final Pattern CALLOUT_ID = Pattern.compile( - "\\(\\?\\{=(CALL|DYNAMIC):(\\d+)\\}\\)"); + private static final char SLOT_START = '\u001e'; + private static final char SLOT_END = '\u001f'; private final String pattern; private final List callbacks; private final boolean byteBackedPattern; + private record CalloutSlot(int start, int end, char kind, int id) {} + /** * Deferred array interpolation. Keeping the joined operands separate until * the enclosing regex template is assembled lets a blessed element's dot @@ -99,23 +98,25 @@ public static RuntimeScalar build(RuntimeList parts) { int id = callbacks.size(); callbacks.add(callback); if (callback.kind == RuntimeRegexCallback.Kind.CONDITION) { - pattern.append("?{=CALL:").append(id).append("})"); + appendSlot(pattern, 'C', id); } else if (callback.kind == RuntimeRegexCallback.Kind.DYNAMIC) { - pattern.append("(?{=DYNAMIC:").append(id).append("})"); + appendSlot(pattern, 'D', id); } else { - pattern.append("(?{=CALL:").append(id).append("})"); + appendSlot(pattern, 'B', id); } } else if (scalar.value instanceof RuntimeRegex regex && !regex.executableCallbacks.isEmpty()) { - appendEmbeddedRegex(pattern, callbacks, regex.toExecutableString(), regex.executableCallbacks); + appendEmbeddedRegex(pattern, callbacks, + regex.toExecutableString(), regex.executableCallbacks); } else if (scalar.value instanceof RuntimeRegexTemplate template) { - appendEmbeddedRegex(pattern, callbacks, template.pattern, template.callbacks); + appendEmbeddedRegex(pattern, callbacks, + template.pattern, template.callbacks); } else { - pattern.append(scalar); + appendUntrusted(pattern, scalar.toString()); } } RuntimeScalar result = callbacks.isEmpty() - ? patternScalar(pattern.toString(), byteBackedPattern) + ? patternScalar(collapseSlotEscapes(pattern.toString()), byteBackedPattern) : new RuntimeScalar(new RuntimeRegexTemplate( pattern.toString(), callbacks, byteBackedPattern)); result.tainted = tainted; @@ -282,22 +283,71 @@ private static void appendEmbeddedRegex(StringBuilder pattern, String embeddedPattern, List embeddedCallbacks) { int offset = callbacks.size(); - Matcher matcher = CALLOUT_ID.matcher(embeddedPattern); - StringBuilder remapped = new StringBuilder(); - while (matcher.find()) { - String kind = matcher.group(1); - int oldId = Integer.parseInt(matcher.group(2)); + int cursor = 0; + for (CalloutSlot slot : calloutSlots(embeddedPattern)) { + pattern.append(embeddedPattern, cursor, slot.start()); + int oldId = slot.id(); if (oldId < 0 || oldId >= embeddedCallbacks.size()) { throw new IllegalArgumentException("Invalid embedded regex callout ID " + oldId); } - matcher.appendReplacement(remapped, - "(?{=" + kind + ":" + (offset + oldId) + "})"); + appendSlot(pattern, slot.kind(), offset + oldId); + cursor = slot.end(); } - matcher.appendTail(remapped); - pattern.append(remapped); + pattern.append(embeddedPattern, cursor, embeddedPattern.length()); callbacks.addAll(embeddedCallbacks); } + private static void appendSlot(StringBuilder pattern, char kind, int id) { + pattern.append(SLOT_START).append(kind).append(id).append(SLOT_END); + } + + private static void appendUntrusted(StringBuilder pattern, String text) { + for (int i = 0; i < text.length(); i++) { + char ch = text.charAt(i); + pattern.append(ch); + if (ch == SLOT_START) pattern.append(ch); + } + } + + private static List calloutSlots(String executablePattern) { + List slots = new ArrayList<>(); + for (int i = 0; i < executablePattern.length(); i++) { + if (executablePattern.charAt(i) != SLOT_START) continue; + if (i + 1 < executablePattern.length() + && executablePattern.charAt(i + 1) == SLOT_START) { + i++; + continue; + } + int start = i; + if (++i >= executablePattern.length()) { + throw malformedCalloutSlot(); + } + char kind = executablePattern.charAt(i); + if (kind != 'B' && kind != 'C' && kind != 'D') { + throw malformedCalloutSlot(); + } + int digitStart = ++i; + while (i < executablePattern.length() + && executablePattern.charAt(i) >= '0' + && executablePattern.charAt(i) <= '9') i++; + if (i == digitStart || i >= executablePattern.length() + || executablePattern.charAt(i) != SLOT_END) { + throw malformedCalloutSlot(); + } + try { + slots.add(new CalloutSlot(start, i + 1, kind, + Integer.parseInt(executablePattern.substring(digitStart, i)))); + } catch (NumberFormatException ignored) { + throw malformedCalloutSlot(); + } + } + return slots; + } + + private static IllegalArgumentException malformedCalloutSlot() { + return new IllegalArgumentException("Malformed internal regex callout slot"); + } + String pattern() { return pattern; } @@ -317,21 +367,24 @@ boolean byteBackedPattern() { * Perl expressions. */ MaskedCallouts maskCallouts() { - Matcher matcher = CALLOUT_ID.matcher(pattern); StringBuilder masked = new StringBuilder(); StringBuilder syntheticPrefix = new StringBuilder(); List placeholders = new ArrayList<>(); List markers = new ArrayList<>(); + int cursor = 0; int id = 0; - while (matcher.find()) { + for (CalloutSlot slot : calloutSlots(pattern)) { + int maskStart = slot.kind() == 'C' && slot.start() > 0 + && pattern.charAt(slot.start() - 1) == '(' + ? slot.start() - 1 : slot.start(); + masked.append(pattern, cursor, maskStart); String token = "POJ_INTERNAL_CALLOUT_PLACEHOLDER_" + id++ + "_END"; while (pattern.contains(token)) token += "_"; // In (?(?{...})yes|no), the marker itself is the condition. Use a // temporary named-capture condition so the runtime regex parser // preserves the branches without interpreting the trusted marker // as Perl source. The empty capture is removed by restore(). - boolean callbackCondition = matcher.start() >= 2 - && pattern.startsWith("(?", matcher.start() - 2); + boolean callbackCondition = slot.kind() == 'C'; String placeholder = token; if (callbackCondition) { String name = "POJ_INTERNAL_CALLOUT_CONDITION_" + id; @@ -340,10 +393,11 @@ MaskedCallouts maskCallouts() { placeholder = "(<" + name + ">)"; } placeholders.add(placeholder); - markers.add(matcher.group()); - matcher.appendReplacement(masked, Matcher.quoteReplacement(placeholder)); + markers.add(pattern.substring(maskStart, slot.end())); + masked.append(placeholder); + cursor = slot.end(); } - matcher.appendTail(masked); + masked.append(pattern, cursor, pattern.length()); return new MaskedCallouts(syntheticPrefix + masked.toString(), syntheticPrefix.toString(), placeholders, markers); } @@ -355,42 +409,90 @@ boolean containsRuntimeExecutableSource(String modifiers) { static String offsetCalloutIds(String executablePattern, int offset, int callbackCount) { - if (offset == 0 || callbackCount == 0) return executablePattern; - Matcher matcher = CALLOUT_ID.matcher(executablePattern); StringBuilder remapped = new StringBuilder(); - while (matcher.find()) { - int oldId = Integer.parseInt(matcher.group(2)); + int cursor = 0; + for (CalloutSlot slot : calloutSlots(executablePattern)) { + remapped.append(executablePattern, cursor, slot.start()); + int oldId = slot.id(); if (oldId < 0 || oldId >= callbackCount) { throw new IllegalArgumentException("Invalid runtime regex callout ID " + oldId); } - matcher.appendReplacement(remapped, Matcher.quoteReplacement( - "(?{=" + matcher.group(1) + ":" + (offset + oldId) + "})")); + appendSlot(remapped, slot.kind(), offset + oldId); + cursor = slot.end(); } - matcher.appendTail(remapped); + remapped.append(executablePattern, cursor, executablePattern.length()); return remapped.toString(); } + static String materializeTrustedCallouts(String executablePattern, int callbackCount) { + if (callbackCount == 0 || executablePattern.indexOf(SLOT_START) < 0) { + return executablePattern; + } + StringBuilder materialized = new StringBuilder(executablePattern.length() + 16); + int cursor = 0; + for (CalloutSlot slot : calloutSlots(executablePattern)) { + appendCollapsedSlotEscapes(materialized, + executablePattern.substring(cursor, slot.start())); + if (slot.id() < 0 || slot.id() >= callbackCount) { + throw new IllegalArgumentException( + "Invalid runtime regex callout ID " + slot.id()); + } + if (slot.kind() == 'C') { + materialized.append("?{=CALL:").append(slot.id()).append("})"); + } else { + materialized.append("(?{=") + .append(slot.kind() == 'D' ? "DYNAMIC:" : "CALL:") + .append(slot.id()).append("})"); + } + cursor = slot.end(); + } + appendCollapsedSlotEscapes(materialized, + executablePattern.substring(cursor)); + return materialized.toString(); + } + + private static void appendCollapsedSlotEscapes(StringBuilder target, String text) { + for (int i = 0; i < text.length(); i++) { + char ch = text.charAt(i); + target.append(ch); + if (ch == SLOT_START && i + 1 < text.length() + && text.charAt(i + 1) == SLOT_START) i++; + } + } + + private static String collapseSlotEscapes(String text) { + StringBuilder collapsed = new StringBuilder(text.length()); + appendCollapsedSlotEscapes(collapsed, text); + return collapsed.toString(); + } + static String displayPattern(String executablePattern, List callbacks) { if (executablePattern == null || executablePattern.isEmpty()) { return executablePattern; } - Matcher matcher = CALLOUT_ID.matcher(executablePattern); StringBuilder display = new StringBuilder(); - while (matcher.find()) { - int callbackId = Integer.parseInt(matcher.group(2)); + int cursor = 0; + for (CalloutSlot slot : calloutSlots(executablePattern)) { + int textEnd = slot.kind() == 'C' && slot.start() > cursor + && executablePattern.charAt(slot.start() - 1) == '(' + ? slot.start() - 1 : slot.start(); + appendCollapsedSlotEscapes(display, + executablePattern.substring(cursor, textEnd)); + int callbackId = slot.id(); String replacement = callbackId >= 0 && callbackId < callbacks.size() && callbacks.get(callbackId).source != null ? callbacks.get(callbackId).source - : "DYNAMIC".equals(matcher.group(1)) ? "(??{})" : "(?{})"; - matcher.appendReplacement(display, Matcher.quoteReplacement(replacement)); + : slot.kind() == 'D' ? "(??{})" : "(?{})"; + display.append(replacement); + cursor = slot.end(); } - matcher.appendTail(display); + appendCollapsedSlotEscapes(display, executablePattern.substring(cursor)); return display.toString(); } @Override public String toString() { - return pattern; + return displayPattern(pattern, callbacks); } } diff --git a/src/main/java/org/perlonjava/runtime/regex/UnicodeResolver.java b/src/main/java/org/perlonjava/runtime/regex/UnicodeResolver.java index 039f614db6..8ab6b5da41 100644 --- a/src/main/java/org/perlonjava/runtime/regex/UnicodeResolver.java +++ b/src/main/java/org/perlonjava/runtime/regex/UnicodeResolver.java @@ -4,26 +4,33 @@ import com.ibm.icu.lang.UProperty; import com.ibm.icu.text.UnicodeSet; import com.ibm.icu.util.ValueIterator; +import org.jcodings.Encoding; import org.joni.CharacterPropertyResolver; import org.joni.PerlPropertyValueMatcher; +import org.joni.WideScalarCodec; import org.perlonjava.app.scriptengine.PerlLanguageProvider; import org.perlonjava.runtime.runtimetypes.*; import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; +import java.util.ArrayDeque; import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.function.Supplier; import java.util.regex.Pattern; public class UnicodeResolver { + private record PropertyScanState(boolean caseInsensitive, boolean extended) {} private static final String USER_PROPERTY_RANGE_ENCODING = "\u0000POJ_USER_RANGES_V1:"; + private static final ThreadLocal USER_PROPERTY_PACKAGE = + ThreadLocal.withInitial(() -> "main"); private static final Pattern USER_DEFINED_PROPERTY_NAME = Pattern.compile( - "^(?:[A-Za-z_][A-Za-z0-9_]*::)*(?:Is|In)[A-Za-z_][A-Za-z0-9_]*$"); + "^(?:[A-Za-z_][A-Za-z0-9_]*::)*(?:Is|In)[A-Za-z0-9_]+$"); private static final UnicodeSet[] PERL_DECOMPOSITION_TYPE_SETS = buildPerlDecompositionTypeSets(); private static final UnicodeSet PERL_UNICODE_BASE_SET = @@ -96,6 +103,96 @@ public class UnicodeResolver { private static final UnicodeSet PERL_COMPOSITION_EXCLUSION_SET = buildPerlCompositionExclusionSet(); + /** + * Perl's native (*script_run:...) predicate, evaluated against the pinned + * Script and Script_Extensions data used by ordinary property matching. + */ + static boolean isPerlScriptRun(byte[] bytes, int start, int end, Encoding encoding, + WideScalarCodec wideScalarCodec) { + String[] scripts = PerlUnicodeScriptData.canonicalValues(); + boolean[] possibleScripts = null; + boolean japanesePossible = true; + int unknownCount = 0; + int characterCount = 0; + int digitSet = -1; + + for (int p = start; p < end;) { + int codePoint; + int next; + WideScalarCodec.Decoded wide = wideScalarCodec == null + ? null : wideScalarCodec.decode(bytes, p, end, encoding); + if (wide != null) { + if (wide.value() > Character.MAX_CODE_POINT || wide.end() <= p || wide.end() > end) { + return false; + } + codePoint = (int) wide.value(); + next = wide.end(); + } else { + int length = encoding.length(bytes, p, end); + if (length <= 0 || p + length > end) return false; + codePoint = encoding.mbcToCode(bytes, p, end); + next = p + length; + } + p = next; + characterCount++; + + if (PerlUnicodeScriptData.scriptSet("Unknown").contains(codePoint)) { + unknownCount++; + if (unknownCount > 1 || characterCount > 1) return false; + continue; + } + if (unknownCount != 0) return false; + + if (Character.getType(codePoint) == Character.DECIMAL_DIGIT_NUMBER) { + int digit = Character.digit(codePoint, 10); + int thisDigitSet = digit < 0 ? codePoint : codePoint - digit; + if (digitSet >= 0 && digitSet != thisDigitSet) return false; + digitSet = thisDigitSet; + } + + boolean[] forCharacter = new boolean[scripts.length]; + boolean hasScript = false; + for (int i = 0; i < scripts.length; i++) { + String script = scripts[i]; + if (script.equals("Common") || script.equals("Inherited") + || script.equals("Unknown")) continue; + if (PerlUnicodeScriptData.scriptExtensionsSet(script).contains(codePoint)) { + forCharacter[i] = true; + hasScript = true; + } + } + // Plain Common/Inherited characters do not constrain the run; + // Common characters with Script_Extensions (for example certain + // punctuation) do constrain it through the generated sets above. + if (!hasScript && (PerlUnicodeScriptData.scriptSet("Common").contains(codePoint) + || PerlUnicodeScriptData.scriptSet("Inherited").contains(codePoint))) { + continue; + } + if (!hasScript) return false; + boolean characterJapanese = forCharacter[scriptIndex(scripts, "Han")] + || forCharacter[scriptIndex(scripts, "Hiragana")] + || forCharacter[scriptIndex(scripts, "Katakana")]; + japanesePossible &= characterJapanese; + if (possibleScripts == null) { + possibleScripts = forCharacter; + } else { + for (int i = 0; i < possibleScripts.length; i++) { + possibleScripts[i] &= forCharacter[i]; + } + } + } + if (possibleScripts == null) return true; + for (boolean possible : possibleScripts) if (possible) return true; + // UTS #39's Highly Restrictive profile treats the Japanese script + // combination (Han, Hiragana, Katakana) as one permitted run. + return japanesePossible; + } + + private static int scriptIndex(String[] scripts, String name) { + for (int i = 0; i < scripts.length; i++) if (scripts[i].equals(name)) return i; + return -1; + } + /** * Cache for user-defined property subroutine results. * Perl only calls user-defined property subs once per unique name and caches the result. @@ -114,6 +211,31 @@ private static String userPropertyCacheKey(String subName, boolean caseInsensiti return subName + (caseInsensitive ? "\u0000i" : "\u0000s"); } + private static String userPropertyAttemptKey(String subName, boolean caseInsensitive) { + return userPropertyCacheKey(subName, caseInsensitive) + "\u0000checked"; + } + + static String activeUserPropertyPackage() { + String packageName = USER_PROPERTY_PACKAGE.get(); + return packageName == null || packageName.isBlank() ? "main" : packageName; + } + + static T withUserPropertyPackage(String packageName, Supplier action) { + String previous = USER_PROPERTY_PACKAGE.get(); + USER_PROPERTY_PACKAGE.set( + packageName == null || packageName.isBlank() ? "main" : packageName); + try { + return action.get(); + } finally { + USER_PROPERTY_PACKAGE.set(previous); + } + } + + static String qualifyUserPropertyName(String property) { + return property.contains("::") + ? property : activeUserPropertyPackage() + "::" + property; + } + /** * Retrieves the Unicode code point for a given character name. * Supports: @@ -126,6 +248,10 @@ private static String userPropertyCacheKey(String subName, boolean caseInsensiti * @throws IllegalArgumentException If the name is invalid, not found, or is a named sequence. */ public static int getCodePointFromName(String name) { + String trimmed = name.strip(); + if (trimmed.regionMatches(true, 0, "U+", 0, 2)) { + name = trimmed; + } int codePoint; if (name.startsWith("U+")) { try { @@ -134,59 +260,13 @@ public static int getCodePointFromName(String name) { throw new IllegalArgumentException("Invalid Unicode code point: " + name); } } else { - // First try common Perl charnames module aliases - // These are short names that Perl's charnames module provides - // for commonly used control characters and spaces - codePoint = switch (name) { - // C0 control character abbreviations (Unicode name aliases) - case "NUL", "NULL" -> 0x0000; - case "SOH", "START OF HEADING" -> 0x0001; - case "STX", "START OF TEXT" -> 0x0002; - case "ETX", "END OF TEXT" -> 0x0003; - case "EOT", "END OF TRANSMISSION" -> 0x0004; - case "ENQ", "ENQUIRY" -> 0x0005; - case "ACK", "ACKNOWLEDGE" -> 0x0006; - case "BEL", "ALERT" -> 0x0007; - case "BS", "BACKSPACE" -> 0x0008; - case "HT", "TAB", "CHARACTER TABULATION", "HORIZONTAL TABULATION" -> 0x0009; - case "LF", "LINE FEED", "LINE FEED (LF)" -> 0x000A; - case "VT", "LINE TABULATION", "VERTICAL TABULATION" -> 0x000B; - case "FF", "FORM FEED", "FORM FEED (FF)" -> 0x000C; - case "CR", "CARRIAGE RETURN", "CARRIAGE RETURN (CR)" -> 0x000D; - case "SO", "SHIFT OUT" -> 0x000E; - case "SI", "SHIFT IN" -> 0x000F; - case "DLE", "DATA LINK ESCAPE" -> 0x0010; - case "DC1", "DEVICE CONTROL ONE" -> 0x0011; - case "DC2", "DEVICE CONTROL TWO" -> 0x0012; - case "DC3", "DEVICE CONTROL THREE" -> 0x0013; - case "DC4", "DEVICE CONTROL FOUR" -> 0x0014; - case "NAK", "NEGATIVE ACKNOWLEDGE" -> 0x0015; - case "SYN", "SYNCHRONOUS IDLE" -> 0x0016; - case "ETB", "END OF TRANSMISSION BLOCK" -> 0x0017; - case "CAN", "CANCEL" -> 0x0018; - case "EOM", "END OF MEDIUM" -> 0x0019; - case "SUB", "SUBSTITUTE" -> 0x001A; - case "ESC", "ESCAPE" -> 0x001B; - case "FS", "INFORMATION SEPARATOR FOUR", "FILE SEPARATOR" -> 0x001C; - case "GS", "INFORMATION SEPARATOR THREE", "GROUP SEPARATOR" -> 0x001D; - case "RS", "INFORMATION SEPARATOR TWO", "RECORD SEPARATOR" -> 0x001E; - case "US", "INFORMATION SEPARATOR ONE", "UNIT SEPARATOR" -> 0x001F; - case "SP", "SPACE" -> 0x0020; - case "DEL", "DELETE" -> 0x007F; - - // Other control characters and special characters - case "NEL", "NEXT LINE", "NEXT LINE (NEL)" -> 0x0085; - case "BOM", "BYTE ORDER MARK" -> 0xFEFF; - - // Spaces (Perl allows both hyphenated and non-hyphenated forms) - case "NBSP", "NO-BREAK SPACE" -> 0x00A0; - case "ZWSP", "ZERO WIDTH SPACE" -> 0x200B; - case "ZWNJ", "ZERO WIDTH NON-JOINER" -> 0x200C; - case "ZWJ", "ZERO WIDTH JOINER" -> 0x200D; - - // Try ICU4J's official Unicode name lookup - default -> UCharacter.getCharFromName(name); - }; + // Perl's generated table is authoritative for canonical scalar + // names and all aliases represented by duplicate code-point rows. + codePoint = PerlUnicodeScalarNameData.codePoint(name); + if (codePoint == -1) { + // Preserve ICU's algorithmic CJK/Hangul and loose-name fallback. + codePoint = UCharacter.getCharFromName(name); + } if (codePoint == -1) { // Check if this is a named sequence (multi-character sequence) @@ -746,11 +826,7 @@ private static String tryUserDefinedProperty( String property, Set recursionSet, boolean caseInsensitive, boolean qualifyBareDiagnosticName) { // Build the full subroutine name - String subName = property; - if (!subName.contains("::")) { - // Try in main package - subName = "main::" + subName; - } + String subName = qualifyUserPropertyName(property); // The runtime-family coordinator also keys properties by their fully // qualified sub name. Keep recursion tracking in that same canonical @@ -867,29 +943,116 @@ private static IllegalArgumentException propertyDefinitionDie( * regex compiler. Property subs are arbitrary Perl and may block; keeping * them outside that compiler monitor lets unrelated property names proceed. */ - static void preloadUserDefinedProperties(String pattern, boolean caseInsensitive) { - preloadUserDefinedProperties(pattern, caseInsensitive, false); + static void preloadUserDefinedProperties( + String pattern, boolean caseInsensitive, boolean extended) { + preloadUserDefinedProperties(pattern, caseInsensitive, extended, false); } static void preloadDeferredUserDefinedProperties( - String pattern, boolean caseInsensitive) { - preloadUserDefinedProperties(pattern, caseInsensitive, true); + String pattern, boolean caseInsensitive, boolean extended) { + preloadUserDefinedProperties(pattern, caseInsensitive, extended, true); } private static void preloadUserDefinedProperties( - String pattern, boolean caseInsensitive, + String pattern, boolean caseInsensitive, boolean extended, boolean qualifyBareDiagnosticName) { if (pattern == null || pattern.isEmpty()) return; - for (int slash = pattern.indexOf('\\'); slash >= 0; - slash = pattern.indexOf('\\', slash + 1)) { - int precedingSlashes = 0; - for (int cursor = slash - 1; cursor >= 0 && pattern.charAt(cursor) == '\\'; cursor--) { - precedingSlashes++; + boolean quoted = false; + int characterClassDepth = 0; + PropertyScanState scanState = new PropertyScanState(caseInsensitive, extended); + ArrayDeque groupStates = new ArrayDeque<>(); + for (int slash = 0; slash < pattern.length(); slash++) { + char current = pattern.charAt(slash); + if (!quoted && current == '[') { + characterClassDepth++; + continue; + } + if (!quoted && current == ']' && characterClassDepth > 0) { + characterClassDepth--; + continue; } - if ((precedingSlashes & 1) != 0 || slash + 3 >= pattern.length()) continue; + if (!quoted && characterClassDepth == 0 && current == '(' + && slash + 2 < pattern.length() + && pattern.charAt(slash + 1) == '?' + && pattern.charAt(slash + 2) == '#') { + slash += 3; + while (slash < pattern.length() && pattern.charAt(slash) != ')') { + if (pattern.charAt(slash) == '\\' && slash + 1 < pattern.length()) { + slash++; + } + slash++; + } + continue; + } + if (!quoted && characterClassDepth == 0 && current == '(') { + PropertyScanState previousState = scanState; + int optionEnd = slash + 2; + boolean negative = false; + boolean sawOption = false; + boolean localCaseInsensitive = scanState.caseInsensitive(); + boolean localExtended = scanState.extended(); + while (optionEnd < pattern.length()) { + char option = pattern.charAt(optionEnd); + if (option == '-') { + if (negative) break; + negative = true; + optionEnd++; + continue; + } + if (option == ':' || option == ')') break; + if ("adgilimnopsux".indexOf(option) < 0) break; + sawOption = true; + if (option == 'i') localCaseInsensitive = !negative; + if (option == 'x') localExtended = !negative; + optionEnd++; + } + if (sawOption && optionEnd < pattern.length() + && (pattern.charAt(optionEnd) == ':' + || pattern.charAt(optionEnd) == ')')) { + scanState = new PropertyScanState( + localCaseInsensitive, localExtended); + if (pattern.charAt(optionEnd) == ':') { + groupStates.push(previousState); + } + slash = optionEnd; + continue; + } + groupStates.push(scanState); + continue; + } + if (!quoted && characterClassDepth == 0 && current == ')') { + if (!groupStates.isEmpty()) scanState = groupStates.pop(); + continue; + } + if (!quoted && scanState.extended() + && characterClassDepth == 0 && current == '#') { + while (slash < pattern.length() && pattern.charAt(slash) != '\n') slash++; + continue; + } + if (current != '\\' || slash + 1 >= pattern.length()) continue; char marker = pattern.charAt(slash + 1); + if (marker == 'Q' && !quoted) { + quoted = true; + slash++; + continue; + } + if (marker == 'E' && quoted) { + quoted = false; + slash++; + continue; + } + if (quoted) { + slash++; + continue; + } + if (marker == '\\') { + slash++; + continue; + } + if (slash + 3 >= pattern.length()) continue; + if ((marker != 'p' && marker != 'P') || pattern.charAt(slash + 2) != '{') continue; int end = pattern.indexOf('}', slash + 3); if (end < 0) return; @@ -897,18 +1060,30 @@ private static void preloadUserDefinedProperties( String property = pattern.substring(slash + 3, end).trim(); if (property.startsWith("^")) property = property.substring(1).trim(); if (isUserDefinedPropertyName(property)) { - if (qualifyBareDiagnosticName && !property.contains("::")) { - deferredUserProperties().add("main::" + property); + String subName = qualifyUserPropertyName(property); + if (qualifyBareDiagnosticName) { + deferredUserProperties().add(subName); } // Preloading is an optimization for callbacks that are already // available. Perl permits qr// to contain a forward reference - // to a user property; RegexPreprocessor represents that with a - // placeholder and recompiles on first use. Calling the complete - // translator here would turn that intentional forward reference - // into an early "unsupported property" fatal before the - // placeholder path can run. - tryUserDefinedProperty(property, new LinkedHashSet<>(), caseInsensitive, + // to a user property; RuntimeRegex retains that deferred marker + // and ensureCompiledForRuntime() recompiles on first use. Calling + // the complete translator here would turn that intentional + // forward reference into an early "unsupported property" fatal + // before the deferred runtime path can run. + String resolved = tryUserDefinedProperty( + property, new LinkedHashSet<>(), scanState.caseInsensitive(), qualifyBareDiagnosticName); + if (qualifyBareDiagnosticName && resolved == null + && !PerlLanguageProvider.COMPILE_LOCK.isHeldByCurrentThread()) { + // Record a completed negative lookup separately for each + // fold mode. A later /i compile must still defer if only + // the case-sensitive callback result (or absence) has + // previously been observed. + deferredUserProperties().add( + userPropertyAttemptKey( + subName, scanState.caseInsensitive())); + } } slash = end; } @@ -1020,6 +1195,23 @@ && isPerlAllProperty(property, looseIsValue)) { UserUnicodePropertyResult.decode(userProp).unicodePattern(), negated); } + if (mustDeferPotentialUserDefinedProperty( + property, caseInsensitive)) { + // A forward In*/Is* callback must outrank a same-spelled + // built-in property once runtime compilation can see the + // subroutine. Signal the Joni adapter to retain its + // deferred match-any placeholder instead of falling + // through to Block/Script/binary lookup under the compile + // lock. + throw new IllegalArgumentException( + "Deferred user-defined Unicode property " + property); + } + if (isRepeatedUserDefinedPropertyPrefix(property)) { + String qualified = qualifyUserPropertyName(property); + throw new PerlCompilerException( + "Unknown user-defined property name \\p{" + + qualified + "}"); + } String looseUserProperty = loosePropertyName(property); if (looseUserProperty.startsWith("isxposix") || looseUserProperty.startsWith("isposix")) { @@ -1252,20 +1444,22 @@ static boolean isUserDefinedPropertyName(String property) { return property != null && USER_DEFINED_PROPERTY_NAME.matcher(property).matches(); } - static boolean mustPreserveUserDefinedProperty( - String property, boolean caseInsensitive) { - if (!isUserDefinedPropertyName(property)) return false; - String subName = property.contains("::") ? property : "main::" + property; - if (PerlLanguageProvider.COMPILE_LOCK.isHeldByCurrentThread()) return true; - PerlRuntime runtime = PerlRuntime.currentOrNull(); - return runtime != null - && (runtime.regexState().deferredUserUnicodeProperties.contains(subName) - || runtime.regexState().userUnicodePropertyCache.containsKey( - userPropertyCacheKey(subName, caseInsensitive))); + private static boolean isRepeatedUserDefinedPropertyPrefix(String property) { + int separator = property.lastIndexOf("::"); + String localName = separator < 0 ? property : property.substring(separator + 2); + return localName.startsWith("Is_Is_") || localName.startsWith("In_In_"); } static boolean isPerlBuiltInPropertyAlias(String property) { if (property == null) return false; + if (isUserDefinedPropertyName(property) + && (mustDeferPotentialUserDefinedProperty(property, false) + || mustDeferPotentialUserDefinedProperty(property, true))) { + // A colliding In*/Is* callback inside a standard or extended + // character class must take the ordinary deferred-user-property + // path, not the built-in class shortcut. + return false; + } property = canonicalPerlPosixPropertyAlias(property); return isPerlSpecialPropertyAlias(property.trim()) || !normalizePerlIsPropertyAssignment(property).equals(property) @@ -1284,8 +1478,34 @@ static CharacterPropertyResolver.Result resolveJoniProperty( String property, boolean inCharacterClass, boolean caseInsensitive) { if (property == null) return null; property = property.trim(); - if (isUserDefinedPropertyName(property) - && PerlRuntime.currentOrNull() != null) { + if (PERL_REJECTED_OBSOLETE_BINARY_ALIASES.contains( + loosePropertyName(property))) { + throw new IllegalArgumentException( + "Unsupported obsolete Unicode property: " + property); + } + if (property.matches( + "(?i)(?:sc|script|scx|script[-_ ]?extensions)\\s*(?:=|:)\\s*")) { + throw new IllegalArgumentException( + "Unicode property wildcard not terminated"); + } + if (isPerlIsPrefixedNumericWildcard(property)) { + throw new IllegalArgumentException( + "Is-prefixed Numeric_Value properties do not accept wildcard values"); + } + if (isPerlIsPrefixedJoiningGroupWildcard(property)) { + throw new IllegalArgumentException( + "Can't find Unicode property definition for Is-prefixed Joining_Group wildcard"); + } + if (isPerlIsPrefixedBlockWildcard(property)) { + throw new IllegalArgumentException( + "Can't find Unicode property definition for Is-prefixed Block wildcard"); + } + if (isPerlIsPrefixedScriptWildcard(property)) { + throw new IllegalArgumentException( + "Can't find Unicode property definition for Is-prefixed Script wildcard"); + } + boolean userDefined = isUserDefinedPropertyName(property); + if (userDefined && PerlRuntime.currentOrNull() != null) { String encoded = tryUserDefinedProperty( property, new LinkedHashSet<>(), caseInsensitive); if (encoded != null) { @@ -1297,6 +1517,15 @@ static CharacterPropertyResolver.Result resolveJoniProperty( false); } } + if (userDefined && mustDeferPotentialUserDefinedProperty( + property, caseInsensitive)) { + return null; + } + if (userDefined && isRepeatedUserDefinedPropertyPrefix(property)) { + String qualified = qualifyUserPropertyName(property); + throw new PerlCompilerException( + "Unknown user-defined property name \\p{" + qualified + "}"); + } property = canonicalPerlPosixPropertyAlias(property); property = normalizePerlIsPropertyAssignment(property); int assignment = propertyValueDelimiter(property); @@ -1341,10 +1570,6 @@ static CharacterPropertyResolver.Result resolveJoniProperty( return bareSet == null ? null : joniPropertyResult( bareSet, perlUnicodeOnlyWideRanges(property, null), true); } - if (PerlUnicodeScriptData.canonicalValue(looseIsValue) != null - || PerlUnicodeBlockData.set(looseIsValue) != null) { - return null; - } UnicodeSet bareSet = resolvePerlBuiltInPropertyAlias(property); return bareSet == null ? null : joniPropertyResult( bareSet, perlUnicodeOnlyWideRanges(property, looseIsValue), true); @@ -1354,29 +1579,43 @@ static CharacterPropertyResolver.Result resolveJoniProperty( PerlUnicodePropertyWildcard propertyWildcard = resolvePerlUnicodePropertyWildcard(property); if (propertyWildcard != null) { - if (!propertyWildcard.caseFold && inCharacterClass) return null; return joniPropertyResult( propertyWildcard.set, propertyWildcard.wideRanges, propertyWildcard.caseFold); } + if (perlNumericWildcardBody(value) != null) { + UnicodeSet wildcardSet; + try { + wildcardSet = resolvePerlBuiltInPropertyAlias(property); + } catch (IllegalArgumentException pinnedUnsupported) { + wildcardSet = resolveIcuEnumeratedPropertyWildcard(name, value); + if (wildcardSet == null) throw pinnedUnsupported; + } + if (wildcardSet == null) { + wildcardSet = resolveIcuEnumeratedPropertyWildcard(name, value); + } + if (wildcardSet != null) { + return joniPropertyResult( + wildcardSet, isGeneralCategoryProperty(name)); + } + } boolean caseFold; PerlBinaryBooleanAssignment binaryAssignment = perlBinaryBooleanAssignment(property); + UnicodeSet genericAssignment = binaryAssignment == null + ? resolveIcuPropertyAssignment(property) : null; if (binaryAssignment != null) { - // False remains a semantic negation and is translated by the - // frontend so outer \P, /i folding, and signed-wide membership stay - // symmetric. True can use the native positive range result here. - if (!binaryAssignment.value) return null; - caseFold = true; + // A false assignment is a complement after applying /i to the + // positive property. Folding the complement itself would add the + // excluded positive members back into the native class. + caseFold = binaryAssignment.value; } else if (isGeneralCategoryProperty(name)) { caseFold = true; } else if (PerlUnicodeBlockData.isPropertyAlias(name)) { - if (perlBlockWildcardBody(value) != null) return null; caseFold = false; } else if (PerlUnicodeScriptData.isScriptPropertyAlias(name) || PerlUnicodeScriptData.isScriptExtensionsPropertyAlias(name)) { - if (perlNumericWildcardBody(value) != null) return null; caseFold = false; } else if (isCanonicalCombiningClassProperty(name) || PerlUnicodeBidiClassData.isPropertyAlias(name) @@ -1385,7 +1624,6 @@ static CharacterPropertyResolver.Result resolveJoniProperty( caseFold = false; } else if (PerlUnicodeNumericValueData.isPropertyAlias(name) || PerlUnicodeJoiningGroupData.isPropertyAlias(name)) { - if (perlNumericWildcardBody(value) != null) return null; caseFold = false; } else if (isPerlWordBreakProperty(name)) { if (resolvePerlWordBreakProperty(property) == null) return null; @@ -1393,35 +1631,111 @@ static CharacterPropertyResolver.Result resolveJoniProperty( } else if (isPerlSentenceBreakProperty(name)) { if (resolvePerlSentenceBreakProperty(property) == null) return null; caseFold = false; + } else if (isPerlLineBreakProperty(name)) { + if (resolvePerlLineBreakProperty(property) == null) return null; + caseFold = false; } else if (isPerlVerticalOrientationProperty(name)) { if (resolvePerlVerticalOrientationProperty(property) == null) return null; caseFold = false; } else if (isPerlAgeProperty(name)) { - if (isPerlAgeWildcard(value)) return null; + caseFold = false; + } else if (genericAssignment != null) { caseFold = false; } else { return null; } - // Joni currently folds a complete bracket expression as one class. - // Keep no-fold families translated by the adapter inside brackets until - // the AST can retain per-property fold policy through class composition. - if (!caseFold && inCharacterClass) return null; - - UnicodeSet set = binaryAssignment == null - ? resolvePerlBuiltInPropertyAlias(property) - : resolveStandardPropertyAsSet( - binaryAssignment.propertyName, new LinkedHashSet<>()); + UnicodeSet set; + if (binaryAssignment != null) { + set = resolveStandardPropertyAsSet( + binaryAssignment.propertyName, new LinkedHashSet<>()); + if (!binaryAssignment.value) { + set = new UnicodeSet(set); + if (caseInsensitive) { + set.closeOver(UnicodeSet.CASE_INSENSITIVE); + } + set.complement(); + } + } else if (isPerlLineBreakProperty(name)) { + set = resolvePerlLineBreakProperty(property); + } else { + set = resolvePerlBuiltInPropertyAlias(property); + if (set == null) set = genericAssignment; + } if (set == null) return null; - long[] wideRanges = isPerlVerticalOrientationDefault(property) + long[] wideRanges = binaryAssignment != null && !binaryAssignment.value + ? new long[] {1, 0x110000L, Long.MAX_VALUE} + : isPerlVerticalOrientationDefault(property) ? new long[] {1, 0x110000L, Long.MAX_VALUE} : null; return joniPropertyResult(set, wideRanges, caseFold); } + /** Resolves runtime-neutral ICU property/value pairs not needing Perl policy. */ + private static UnicodeSet resolveIcuPropertyAssignment(String property) { + int assignment = propertyValueDelimiter(property); + if (assignment <= 0 || assignment == property.length() - 1) return null; + String name = property.substring(0, assignment).trim(); + String value = property.substring(assignment + 1).trim(); + try { + return new UnicodeSet().applyPropertyAlias(name, value); + } catch (IllegalArgumentException unsupported) { + return null; + } + } + + /** Resolves an anchored Perl wildcard across an ICU enumerated property. */ + private static UnicodeSet resolveIcuEnumeratedPropertyWildcard( + String propertyName, String wildcardValue) { + PerlPropertyValueMatcher wildcard = + compilePerlUnicodePropertyWildcard(wildcardValue); + if (wildcard == null) return null; + final int property; + try { + property = UCharacter.getPropertyEnum(propertyName.trim()); + } catch (IllegalArgumentException unsupported) { + return null; + } + + UnicodeSet result = new UnicodeSet(); + int minimum = UCharacter.getIntPropertyMinValue(property); + int maximum = UCharacter.getIntPropertyMaxValue(property); + for (int value = minimum; value <= maximum; value++) { + boolean matches = false; + for (int nameChoice = UProperty.NameChoice.SHORT; + !matches && nameChoice <= UProperty.NameChoice.LONG; + nameChoice++) { + String alias = UCharacter.getPropertyValueName( + property, value, nameChoice); + matches = alias != null + && (wildcard.matchesPropertyValue(alias) + || wildcard.matchesPropertyValue( + loosePropertyName(alias))); + } + if (matches) result.addAll( + new UnicodeSet().applyIntPropertyValue(property, value)); + } + if (result.isEmpty()) { + throw new IllegalArgumentException( + "No Unicode property value wildcard matches " + + propertyName.trim()); + } + return result.freeze(); + } + private static UnicodeSet resolvePerlCaseFoldableBareProperty( String property, boolean caseInsensitive) { + try { + int propertyEnum = UCharacter.getPropertyEnum(property); + if (propertyEnum == UProperty.UPPERCASE + || propertyEnum == UProperty.LOWERCASE) { + return resolveStandardPropertyAsSet( + property, new LinkedHashSet<>()); + } + } catch (IllegalArgumentException unsupportedAlias) { + // Perl-only compatibility aliases are handled below. + } return switch (property) { case "Uppercase", "XPosixLower", "XPosixUpper" -> resolveStandardPropertyAsSet( @@ -1471,6 +1785,38 @@ private static CharacterPropertyResolver.Result joniPropertyResult( return new CharacterPropertyResolver.Result(ranges, wideRanges, caseFold); } + static boolean mustDeferPotentialUserDefinedProperty( + String property, boolean caseInsensitive) { + if (!PerlLanguageProvider.COMPILE_LOCK.isHeldByCurrentThread()) { + return false; + } + PerlRuntime runtime = PerlRuntime.currentOrNull(); + if (runtime == null) return false; + String subName = qualifyUserPropertyName(property); + if (runtime.regexState().userUnicodePropertyCache.containsKey( + userPropertyCacheKey(subName, caseInsensitive))) { + return false; + } + return !runtime.regexState().deferredUserUnicodeProperties.contains( + userPropertyAttemptKey(subName, caseInsensitive)); + } + + static boolean hasCachedUserDefinedProperty(String property) { + PerlRuntime runtime = PerlRuntime.currentOrNull(); + if (runtime == null) return false; + String subName = qualifyUserPropertyName(property); + return runtime.regexState().userUnicodePropertyCache.containsKey( + userPropertyCacheKey(subName, false)) + || runtime.regexState().userUnicodePropertyCache.containsKey( + userPropertyCacheKey(subName, true)); + } + + static boolean hasDefinedUserPropertySub(String property) { + if (PerlRuntime.currentOrNull() == null) return false; + String subName = qualifyUserPropertyName(property); + return GlobalVariable.isGlobalCodeRefDefined(subName); + } + private static boolean isPerlSpecialPropertyAlias(String property) { return switch (property) { case "lb=cr", "lb=CR", @@ -1861,6 +2207,32 @@ private static boolean isPerlSentenceBreakProperty(String property) { }; } + private static UnicodeSet resolvePerlLineBreakProperty(String property) { + int assignment = propertyValueDelimiter(property); + if (assignment <= 0 || assignment == property.length() - 1 + || !isPerlLineBreakProperty(property.substring(0, assignment))) { + return null; + } + String value = property.substring(assignment + 1); + // ICU exposes Line_Break's data for matching but not through its + // property-value enum lookup. Preserve the canonical CR value aliases + // that Perl accepts, matching the existing frontend property adapter. + if (switch (loosePropertyName(value)) { + case "cr", "carriagereturn" -> true; + default -> false; + }) { + return new UnicodeSet('\r', '\r'); + } + return unicodePropertyValueSet(UProperty.LINE_BREAK, value); + } + + private static boolean isPerlLineBreakProperty(String property) { + return switch (loosePropertyName(property)) { + case "lb", "linebreak" -> true; + default -> false; + }; + } + private static UnicodeSet resolvePerlVerticalOrientationProperty(String property) { int assignment = propertyValueDelimiter(property); if (assignment <= 0 || assignment == property.length() - 1 @@ -1917,6 +2289,9 @@ private static PerlUnicodePropertyWildcard resolvePerlUnicodePropertyWildcard( if (isIcuBinaryPropertyAlias(name)) { return resolvePerlBinaryPropertyWildcard(name, wildcard); } + if (resolvePerlMissingBaseAlias(name) != null) { + return resolvePerlBinaryPropertyWildcard(name, wildcard); + } if (isPerlWordBreakProperty(name)) { return resolvePerlEnumeratedPropertyWildcard( UProperty.WORD_BREAK, wildcard, "Word_Break", @@ -2003,10 +2378,7 @@ private static PerlPropertyValueMatcher compilePerlUnicodePropertyWildcard( String value) { String body = perlNumericWildcardBody(value); if (body == null) return null; - if (body.indexOf('*') >= 0) { - throw new IllegalArgumentException( - "quantifier '*' is not allowed in Unicode property value wildcard"); - } + rejectForbiddenPerlUnicodePropertyWildcardSyntax(body); try { return PerlPropertyValueMatcher.compile(body); } catch (RuntimeException invalidPattern) { @@ -2031,14 +2403,19 @@ private static boolean isPerlNameProperty(String name) { return trimmed.equals("name") || trimmed.equals("na"); } + static boolean isPerlStringProperty(String property) { + if (property == null) return false; + int assignment = propertyValueDelimiter(property); + return assignment > 0 && assignment < property.length() - 1 + && isPerlNameProperty(property.substring(0, assignment)) + && perlSlashWildcardBody(property.substring(assignment + 1)) == null; + } + private static PerlUnicodePropertyWildcard resolvePerlNamePropertyWildcard( String propertyName, String value) { String body = perlSlashWildcardBody(value); if (body == null) return null; - if (body.indexOf('*') >= 0) { - throw new IllegalArgumentException( - "quantifier '*' is not allowed in Unicode property value wildcard"); - } + rejectForbiddenPerlUnicodePropertyWildcardSyntax(body); final PerlPropertyValueMatcher wildcard; try { @@ -2095,7 +2472,8 @@ private static PerlBinaryBooleanAssignment perlBinaryBooleanAssignment( String name = normalized.substring(0, assignment); Boolean value = perlBooleanPropertyValue( normalized.substring(assignment + 1)); - if (value == null || !isIcuBinaryPropertyAlias(name)) return null; + if (value == null || !isIcuBinaryPropertyAlias(name) + && resolvePerlMissingBaseAlias(name) == null) return null; return new PerlBinaryBooleanAssignment(name, value); } @@ -2119,6 +2497,8 @@ private static UnicodeSet resolvePerlMissingBaseAlias(String alias) { case "horizspace" -> PERL_HORIZONTAL_SPACE_SET; case "kehnomirror" -> PerlUnicodeUnikemetData.noMirror(); case "kehnorotate" -> PerlUnicodeUnikemetData.noRotate(); + case "perlidstart" -> perlIdStartSet(); + case "perlidcont" -> perlIdContinueSet(); default -> null; }; } @@ -2163,16 +2543,58 @@ private static PerlBarePropertyAlias resolvePerlPosixCompatibilityAlias( PERL_ASCII_SPACE_SET, false); case "perlword" -> new PerlBarePropertyAlias( PERL_ASCII_WORD_SET, false); - case "xperlspace", "spaceperl" -> new PerlBarePropertyAlias( + case "xperlspace", "spaceperl", "xposixspace" -> new PerlBarePropertyAlias( PERL_UNICODE_SPACE_SET, false); case "whitespace" -> new PerlBarePropertyAlias( PERL_UNICODE_SPACE_SET, false); + case "xposixalnum" -> new PerlBarePropertyAlias( + new UnicodeSet().applyPropertyAlias("Alphabetic", "True") + .addAll(PerlUnicodeGeneralCategoryData.resolve("Nd")) + .freeze(), false); + case "xposixalpha" -> new PerlBarePropertyAlias( + new UnicodeSet().applyPropertyAlias("Alphabetic", "True") + .freeze(), false); + case "xposixblank" -> new PerlBarePropertyAlias( + PERL_UNICODE_SPACE_SET, false); + case "xposixcntrl" -> new PerlBarePropertyAlias( + PerlUnicodeGeneralCategoryData.resolve("Cc"), false); + case "xposixdigit" -> new PerlBarePropertyAlias( + PerlUnicodeGeneralCategoryData.resolve("Nd"), false); case "xposixgraph" -> new PerlBarePropertyAlias( PERL_POSIX_GRAPH_SET, false); case "xposixprint", "print" -> new PerlBarePropertyAlias( PERL_POSIX_PRINT_SET, false); + case "xposixpunct" -> new PerlBarePropertyAlias( + PerlUnicodeGeneralCategoryData.resolve("P"), false); + case "xposixword" -> new PerlBarePropertyAlias( + PERL_WORD_SET, false); case "xposixxdigit", "xdigit" -> new PerlBarePropertyAlias( PERL_POSIX_XDIGIT_SET, false); + case "posixalnum" -> new PerlBarePropertyAlias( + new UnicodeSet().add('0', '9').add('A', 'Z').add('a', 'z') + .freeze(), false); + case "posixalpha" -> new PerlBarePropertyAlias( + new UnicodeSet().add('A', 'Z').add('a', 'z').freeze(), false); + case "posixblank" -> new PerlBarePropertyAlias( + new UnicodeSet().add('\t').add(' ').freeze(), false); + case "posixcntrl" -> new PerlBarePropertyAlias( + new UnicodeSet().add(0, 0x1f).add(0x7f).freeze(), false); + case "posixdigit" -> new PerlBarePropertyAlias( + new UnicodeSet().add('0', '9').freeze(), false); + case "posixgraph" -> new PerlBarePropertyAlias( + new UnicodeSet().add('!', '~').freeze(), false); + case "posixprint" -> new PerlBarePropertyAlias( + new UnicodeSet().add(' ', '~').freeze(), false); + case "posixpunct" -> new PerlBarePropertyAlias( + new UnicodeSet().add('!', '/').add(':', '@') + .add('[', '`').add('{', '~').freeze(), false); + case "posixspace" -> new PerlBarePropertyAlias( + PERL_ASCII_SPACE_SET, false); + case "posixword" -> new PerlBarePropertyAlias( + PERL_ASCII_WORD_SET, false); + case "posixxdigit" -> new PerlBarePropertyAlias( + new UnicodeSet().add('0', '9').add('A', 'F').add('a', 'f') + .freeze(), false); default -> null; }; } @@ -2223,6 +2645,24 @@ private static UnicodeSet buildPerlHorizontalSpaceSet() { .freeze(); } + private static UnicodeSet perlIdStartSet() { + return new UnicodeSet() + .applyPropertyAlias("XID_Start", "True") + .add('_') + .freeze(); + } + + private static UnicodeSet perlIdContinueSet() { + return new UnicodeSet() + .addAll(PerlUnicodeGeneralCategoryData.resolve("L")) + .addAll(PerlUnicodeGeneralCategoryData.resolve("Nl")) + .addAll(PerlUnicodeGeneralCategoryData.resolve("Nd")) + .addAll(PerlUnicodeGeneralCategoryData.resolve("Mn")) + .addAll(PerlUnicodeGeneralCategoryData.resolve("Mc")) + .addAll(PerlUnicodeGeneralCategoryData.resolve("Pc")) + .freeze(); + } + private static UnicodeSet buildPerlUnicodeSpaceSet() { return new UnicodeSet() .add(0x0009, 0x000D).add(0x0020).add(0x0085).add(0x00A0) @@ -2636,6 +3076,10 @@ private static UnicodeSet resolvePerlNumericValue(String value) { private static String perlNumericWildcardBody(String value) { String trimmed = value.trim(); + if (trimmed.length() > 2 && trimmed.startsWith(":") + && trimmed.endsWith(":")) { + return trimmed.substring(1, trimmed.length() - 1); + } if (trimmed.startsWith("/\\A") && trimmed.endsWith("\\z/") && trimmed.length() > 6) { return "\\A" + trimmed.substring(3, trimmed.length() - 3) + "\\z"; @@ -2647,6 +3091,63 @@ private static String perlNumericWildcardBody(String value) { return null; } + /** + * Perl deliberately permits only a restricted regex dialect inside a + * Unicode property-value wildcard. Diagnose forbidden constructs against + * the wildcard body itself, matching the source Perl uses for its marker. + */ + private static void rejectForbiddenPerlUnicodePropertyWildcardSyntax( + String body) { + int offset = body.indexOf('*'); + if (offset >= 0) { + throw propertyWildcardSyntaxError(body, offset + 1, + "Use of quantifier '*' is not allowed in Unicode property wildcard subpatterns"); + } + offset = body.indexOf("\\G"); + if (offset >= 0) { + throw propertyWildcardSyntaxError(body, offset + 2, + "Use of '\\G' is not allowed in Unicode property wildcard subpatterns"); + } + for (String escape : new String[] {"\\pS", "\\PS"}) { + offset = body.indexOf(escape); + if (offset >= 0) { + throw propertyWildcardSyntaxError(body, offset + escape.length(), + "Use of '" + escape + + "' is not allowed in Unicode property wildcard subpatterns"); + } + } + java.util.regex.Matcher modifier = Pattern.compile( + "\\(\\?(-?[A-Za-z]+)\\)").matcher(body); + while (modifier.find()) { + String modifiers = modifier.group(1); + String prohibited = null; + int marker = modifier.end(); + if (modifiers.startsWith("-m")) { + prohibited = "-m"; + marker = modifier.end() - 1; + } else { + for (char candidate : new char[] {'g', 'a', 'u', 'd', 'l'}) { + if (modifiers.indexOf(candidate) >= 0) { + prohibited = String.valueOf(candidate); + if (candidate == 'g') marker = modifier.end() - 1; + break; + } + } + } + if (prohibited != null) { + throw propertyWildcardSyntaxError(body, marker, + "Use of modifier '" + prohibited + + "' is not allowed in Unicode property wildcard subpatterns"); + } + } + } + + private static PerlCompilerException propertyWildcardSyntaxError( + String body, int offset, String message) { + return new PerlCompilerException( + RegexDiagnosticFormatter.markedPerl(body, offset, message)); + } + private static short perlNumericValueIndex(String value) { try { if (value.indexOf('/') >= 0) { diff --git a/src/main/java/org/perlonjava/runtime/runtimetypes/DestroyDispatch.java b/src/main/java/org/perlonjava/runtime/runtimetypes/DestroyDispatch.java index a57cca866c..4865f8695d 100644 --- a/src/main/java/org/perlonjava/runtime/runtimetypes/DestroyDispatch.java +++ b/src/main/java/org/perlonjava/runtime/runtimetypes/DestroyDispatch.java @@ -149,10 +149,13 @@ public static boolean classNeedsWalkerGate(int blessId) { public static boolean classHasDestroy(int blessId, String className) { LifecycleRuntimeState state = state(); int idx = Math.abs(blessId); - if (state.destroyClasses.get(idx)) return true; + if (state.destroyClassesChecked.get(idx)) { + return state.destroyClasses.get(idx); + } // First time for this class — check hierarchy. // findMethodInHierarchy already falls through to AUTOLOAD if no explicit DESTROY exists. RuntimeScalar m = InheritanceResolver.findMethodInHierarchy("DESTROY", className, null, 0); + state.destroyClassesChecked.set(idx); if (m != null) { state.destroyClasses.set(idx); // Activate the mortal mechanism now that we know DESTROY classes exist @@ -168,6 +171,7 @@ public static boolean classHasDestroy(int blessId, String className) { */ public static void invalidateCache() { state().destroyClasses.clear(); + state().destroyClassesChecked.clear(); state().destroyMethodCache.clear(); } @@ -270,6 +274,15 @@ public static void callDestroy(RuntimeBase referent) { } } else if (referent instanceof org.perlonjava.runtime.regex.RuntimeRegex regex) { regex.releaseExecutableCallbacks(); + if (referent.blessId == 0) { + int regexpBlessId = NameNormalizer.getBlessId("Regexp"); + if (classHasDestroy(regexpBlessId, "Regexp")) { + // qr// is implicitly in class Regexp. Keep live wrappers + // unblessed for selective-lifetime compatibility, and + // expose the implicit class only at final destruction. + referent.blessId = regexpBlessId; + } + } } String className = NameNormalizer.getBlessStr(referent.blessId); diff --git a/src/main/java/org/perlonjava/runtime/runtimetypes/ErrorMessageUtil.java b/src/main/java/org/perlonjava/runtime/runtimetypes/ErrorMessageUtil.java index 377b44115e..7f1206c0ac 100644 --- a/src/main/java/org/perlonjava/runtime/runtimetypes/ErrorMessageUtil.java +++ b/src/main/java/org/perlonjava/runtime/runtimetypes/ErrorMessageUtil.java @@ -18,6 +18,7 @@ public class ErrorMessageUtil { private int tokenIndex; private int lastLineNumber; private volatile int[] physicalLineNumbers; + private volatile SourceDirectiveIndex sourceDirectiveIndex; /** * Constructs an ErrorMessageUtil with the specified file name and list of tokens. @@ -42,6 +43,7 @@ public ErrorMessageUtil(String fileName, List tokens) { public void updateTokens(List newTokens) { this.tokens = newTokens; this.physicalLineNumbers = null; + this.sourceDirectiveIndex = null; } /** @@ -518,91 +520,165 @@ private int[] buildPhysicalLineNumbers() { } public SourceLocation getSourceLocationAccurate(int index) { - String currentFileName = originalFileName; - int lineNumber = 1; + if (index < 0 || tokens == null || tokens.isEmpty()) { + return new SourceLocation(originalFileName, 1); + } - boolean atBeginningOfLine = true; - int i = 0; - while (i <= index && i < tokens.size()) { - LexerToken tok = tokens.get(i); - if (tok.type == LexerTokenType.EOF) { - break; + int boundedIndex = Math.min(index, tokens.size() - 1); + int physicalLine = getLineNumberAccurate(boundedIndex); + SourceDirectiveIndex directives = sourceDirectiveIndex(); + int directive = directives.floor(boundedIndex); + if (directive < 0) { + return new SourceLocation(originalFileName, physicalLine); + } + int logicalLine = directives.logicalLines[directive] + + physicalLine - directives.physicalLines[directive]; + return new SourceLocation(directives.fileNames[directive], logicalLine); + } + + private SourceDirectiveIndex sourceDirectiveIndex() { + SourceDirectiveIndex result = sourceDirectiveIndex; + if (result == null) { + synchronized (this) { + result = sourceDirectiveIndex; + if (result == null) { + result = buildSourceDirectiveIndex(); + sourceDirectiveIndex = result; + } } + } + return result; + } - if (tok.type == LexerTokenType.NEWLINE) { - lineNumber++; + private SourceDirectiveIndex buildSourceDirectiveIndex() { + ArrayList tokenIndexes = new ArrayList<>(); + ArrayList physicalLines = new ArrayList<>(); + ArrayList logicalLines = new ArrayList<>(); + ArrayList fileNames = new ArrayList<>(); + String currentFileName = originalFileName; + int physicalLine = 1; + boolean atBeginningOfLine = true; + + for (int i = 0; i < tokens.size(); i++) { + LexerToken token = tokens.get(i); + if (token.type == LexerTokenType.EOF) break; + if (token.type == LexerTokenType.NEWLINE) { + physicalLine++; atBeginningOfLine = true; - i++; continue; } - - if (atBeginningOfLine && tok.type == LexerTokenType.OPERATOR && tok.text.equals("#")) { - int j = i + 1; - while (j < tokens.size() && tokens.get(j).type == LexerTokenType.WHITESPACE) { - j++; - } - if (j < tokens.size() && tokens.get(j).type == LexerTokenType.IDENTIFIER && tokens.get(j).text.equals("line")) { - j++; - while (j < tokens.size() && tokens.get(j).type == LexerTokenType.WHITESPACE) { - j++; - } - if (j < tokens.size() && tokens.get(j).type == LexerTokenType.NUMBER) { - int directiveLine = -1; - try { - directiveLine = Integer.parseInt(tokens.get(j).text); - } catch (NumberFormatException e) { - directiveLine = -1; - } - j++; - while (j < tokens.size() && tokens.get(j).type == LexerTokenType.WHITESPACE) { - j++; - } - if (j < tokens.size() && tokens.get(j).type == LexerTokenType.OPERATOR && tokens.get(j).text.equals("\"")) { - // Quoted filename: #line N "filename" - j++; - StringBuilder filenameBuilder = new StringBuilder(); - while (j < tokens.size() && !(tokens.get(j).type == LexerTokenType.OPERATOR && tokens.get(j).text.equals("\""))) { - filenameBuilder.append(tokens.get(j).text); - j++; - } - if (j < tokens.size() && tokens.get(j).type == LexerTokenType.OPERATOR && tokens.get(j).text.equals("\"")) { - String directiveFile = filenameBuilder.toString(); - if (!directiveFile.isEmpty()) { - currentFileName = directiveFile; - } - } - } else if (j < tokens.size() && isUnquotedLineFilenameToken(tokens.get(j))) { - // Unquoted filename: #line N filename - // Perl allows unquoted filenames such as lib/Foo/Bar.pm. - StringBuilder filenameBuilder = new StringBuilder(); - while (j < tokens.size() && isUnquotedLineFilenameToken(tokens.get(j))) { - filenameBuilder.append(tokens.get(j).text); - j++; - } - String directiveFile = filenameBuilder.toString(); - if (!directiveFile.isEmpty()) { - currentFileName = directiveFile; - } - } - - if (directiveLine >= 0) { - // The directive applies to the following line. - // Perl allows `#line 0` (the next line becomes line 0); - // -M/-m import injection relies on this to make caller() - // report line 0, matching real Perl behavior. - lineNumber = directiveLine - 1; - } + if (atBeginningOfLine && token.type == LexerTokenType.OPERATOR + && token.text.equals("#")) { + ParsedLineDirective directive = parseLineDirective(i); + if (directive != null) { + if (directive.fileName != null) { + currentFileName = directive.fileName; } + tokenIndexes.add(i); + physicalLines.add(physicalLine); + // A directive applies to the following source line. The + // tokens on the directive line itself retain the legacy + // mapping to one less than the requested logical line. + logicalLines.add(directive.lineNumber - 1); + fileNames.add(currentFileName); } } - - if (tok.type != LexerTokenType.WHITESPACE) { + if (token.type != LexerTokenType.WHITESPACE) { atBeginningOfLine = false; } - i++; } + return new SourceDirectiveIndex( + tokenIndexes.stream().mapToInt(Integer::intValue).toArray(), + physicalLines.stream().mapToInt(Integer::intValue).toArray(), + logicalLines.stream().mapToInt(Integer::intValue).toArray(), + fileNames.toArray(String[]::new)); + } - return new SourceLocation(currentFileName, lineNumber); + private ParsedLineDirective parseLineDirective(int hashIndex) { + int index = hashIndex + 1; + while (index < tokens.size() + && tokens.get(index).type == LexerTokenType.WHITESPACE) { + index++; + } + if (index >= tokens.size() + || tokens.get(index).type != LexerTokenType.IDENTIFIER + || !tokens.get(index).text.equals("line")) { + return null; + } + index++; + while (index < tokens.size() + && tokens.get(index).type == LexerTokenType.WHITESPACE) { + index++; + } + if (index >= tokens.size() + || tokens.get(index).type != LexerTokenType.NUMBER) { + return null; + } + final int lineNumber; + try { + lineNumber = Integer.parseInt(tokens.get(index).text); + } catch (NumberFormatException invalidLine) { + return null; + } + if (lineNumber < 0) return null; + + index++; + while (index < tokens.size() + && tokens.get(index).type == LexerTokenType.WHITESPACE) { + index++; + } + String directiveFile = null; + if (index < tokens.size() + && tokens.get(index).type == LexerTokenType.OPERATOR + && tokens.get(index).text.equals("\"")) { + index++; + StringBuilder filename = new StringBuilder(); + while (index < tokens.size() + && !(tokens.get(index).type == LexerTokenType.OPERATOR + && tokens.get(index).text.equals("\""))) { + filename.append(tokens.get(index).text); + index++; + } + if (index < tokens.size() + && tokens.get(index).type == LexerTokenType.OPERATOR + && tokens.get(index).text.equals("\"") + && !filename.isEmpty()) { + directiveFile = filename.toString(); + } + } else if (index < tokens.size() + && isUnquotedLineFilenameToken(tokens.get(index))) { + StringBuilder filename = new StringBuilder(); + while (index < tokens.size() + && isUnquotedLineFilenameToken(tokens.get(index))) { + filename.append(tokens.get(index).text); + index++; + } + if (!filename.isEmpty()) directiveFile = filename.toString(); + } + return new ParsedLineDirective(lineNumber, directiveFile); + } + + private record ParsedLineDirective(int lineNumber, String fileName) { + } + + private record SourceDirectiveIndex( + int[] tokenIndexes, + int[] physicalLines, + int[] logicalLines, + String[] fileNames) { + private int floor(int tokenIndex) { + int low = 0; + int high = tokenIndexes.length - 1; + while (low <= high) { + int middle = (low + high) >>> 1; + if (tokenIndexes[middle] <= tokenIndex) { + low = middle + 1; + } else { + high = middle - 1; + } + } + return high; + } } public int getSourceOffset(int index) { diff --git a/src/main/java/org/perlonjava/runtime/runtimetypes/GlobalContext.java b/src/main/java/org/perlonjava/runtime/runtimetypes/GlobalContext.java index 1f1a1a74f5..02e2e3ed4d 100644 --- a/src/main/java/org/perlonjava/runtime/runtimetypes/GlobalContext.java +++ b/src/main/java/org/perlonjava/runtime/runtimetypes/GlobalContext.java @@ -331,6 +331,7 @@ public static void initializeGlobals(CompilerOptions compilerOptions) { Parent.initialize(); Lib.initialize(); Re.initialize(); + TieHashNamedCapture.initialize(); // Cwd.initialize(); // Use Perl Cwd.pm instead (has pure Perl fallbacks) FileSpec.initialize(); // Deferred to XSLoader::load() for faster startup - only loaded when actually used: diff --git a/src/main/java/org/perlonjava/runtime/runtimetypes/GlobalVariable.java b/src/main/java/org/perlonjava/runtime/runtimetypes/GlobalVariable.java index 16392005f1..20b2f1148b 100644 --- a/src/main/java/org/perlonjava/runtime/runtimetypes/GlobalVariable.java +++ b/src/main/java/org/perlonjava/runtime/runtimetypes/GlobalVariable.java @@ -1442,8 +1442,10 @@ private static RuntimeHash createNamedGlobalHash(java.util.List names) { // accessed. A glob alias of %! must materialize the same magic. hash.elements = new ErrnoHash(); } else if (names.contains("main::+")) { + hash.type = RuntimeHash.READONLY_HASH; hash.elements = new HashSpecialVariable(HashSpecialVariable.Id.CAPTURE); } else if (names.contains("main::-")) { + hash.type = RuntimeHash.READONLY_HASH; hash.elements = new HashSpecialVariable(HashSpecialVariable.Id.CAPTURE_ALL); } return hash; diff --git a/src/main/java/org/perlonjava/runtime/runtimetypes/HashSpecialVariable.java b/src/main/java/org/perlonjava/runtime/runtimetypes/HashSpecialVariable.java index 3f214250d8..7598ae3aec 100644 --- a/src/main/java/org/perlonjava/runtime/runtimetypes/HashSpecialVariable.java +++ b/src/main/java/org/perlonjava/runtime/runtimetypes/HashSpecialVariable.java @@ -301,12 +301,17 @@ private static RuntimeScalar captureAllArrayRef(List captures) { private static RuntimeScalar firstDefinedCapture(List captures) { for (String v : captures) { if (v != null) { - return new RuntimeScalar(v); + return new RuntimeScalarReadOnly(v); } } return scalarUndef; } + /** Return the named-capture view represented by this magic hash. */ + public Id captureMode() { + return mode == Id.CAPTURE || mode == Id.CAPTURE_ALL ? mode : null; + } + @Override public RuntimeScalar put(String key, RuntimeScalar value) { if (this.mode == Id.STASH) { diff --git a/src/main/java/org/perlonjava/runtime/runtimetypes/LifecycleRuntimeState.java b/src/main/java/org/perlonjava/runtime/runtimetypes/LifecycleRuntimeState.java index 429b8a7a06..580c46b670 100644 --- a/src/main/java/org/perlonjava/runtime/runtimetypes/LifecycleRuntimeState.java +++ b/src/main/java/org/perlonjava/runtime/runtimetypes/LifecycleRuntimeState.java @@ -40,6 +40,7 @@ final class LifecycleRuntimeState { volatile boolean weakRefsExist; final BitSet destroyClasses = new BitSet(); + final BitSet destroyClassesChecked = new BitSet(); final ConcurrentHashMap destroyMethodCache = new ConcurrentHashMap<>(); final Set destroyableObjects = Collections.synchronizedSet(Collections.newSetFromMap(new IdentityHashMap<>())); @@ -80,6 +81,7 @@ void clear() { referentToWeakRefs.clear(); weakRefsExist = false; destroyClasses.clear(); + destroyClassesChecked.clear(); destroyMethodCache.clear(); destroyableObjects.clear(); currentDestroyTarget = null; diff --git a/src/main/java/org/perlonjava/runtime/runtimetypes/PerlCompilerException.java b/src/main/java/org/perlonjava/runtime/runtimetypes/PerlCompilerException.java index cd17d16c97..6c0c4991bc 100644 --- a/src/main/java/org/perlonjava/runtime/runtimetypes/PerlCompilerException.java +++ b/src/main/java/org/perlonjava/runtime/runtimetypes/PerlCompilerException.java @@ -65,6 +65,12 @@ public PerlCompilerException(String message) { /** Attach the compiler's exact source location without a parser "near" clause. */ public static PerlCompilerException withSourceLocation( int tokenIndex, String message, ErrorMessageUtil errorMessageUtil) { + if (message != null && message.endsWith(", within pattern\n")) { + // Some lexical regex diagnostics already carry Perl's exact + // source location. Reattaching the token location would produce + // "within pattern at ... line ..." a second time. + return new PerlCompilerException(message); + } ErrorMessageUtil.SourceLocation location = errorMessageUtil.getSourceLocationAccurate(tokenIndex); String coreMessage = message != null && message.endsWith("\n") diff --git a/src/main/java/org/perlonjava/runtime/runtimetypes/PerlJavaUnimplementedException.java b/src/main/java/org/perlonjava/runtime/runtimetypes/PerlJavaUnimplementedException.java index cc4401570f..748457ee94 100644 --- a/src/main/java/org/perlonjava/runtime/runtimetypes/PerlJavaUnimplementedException.java +++ b/src/main/java/org/perlonjava/runtime/runtimetypes/PerlJavaUnimplementedException.java @@ -2,7 +2,7 @@ /** * Exception thrown when PerlOnJava encounters a Perl feature that is not yet implemented - * in the Java regex engine or other Java components. This is distinct from PerlCompilerException + * in the regex engine or other Java components. This is distinct from PerlCompilerException * which represents actual Perl syntax errors. *

    * This exception is used to distinguish between: diff --git a/src/main/java/org/perlonjava/runtime/runtimetypes/PerlRuntime.java b/src/main/java/org/perlonjava/runtime/runtimetypes/PerlRuntime.java index ef00524eb7..f66fc0790c 100644 --- a/src/main/java/org/perlonjava/runtime/runtimetypes/PerlRuntime.java +++ b/src/main/java/org/perlonjava/runtime/runtimetypes/PerlRuntime.java @@ -460,6 +460,7 @@ private RootSnapshot snapshotCloneInternal( RuntimeGraphCloner cloner = new RuntimeGraphCloner(this, child, skipped); try (Binding ignored = bind()) { globalState.snapshotInto(child.globalState, cloner); + cloner.cloneCompilationHints(compilationState, child.compilationState); runtimeCodeState.snapshotCompiledMetadataInto(child.runtimeCodeState); regexState.snapshotInto(child.regexState); } diff --git a/src/main/java/org/perlonjava/runtime/runtimetypes/RegexCallbackMutationSnapshot.java b/src/main/java/org/perlonjava/runtime/runtimetypes/RegexCallbackMutationSnapshot.java new file mode 100644 index 0000000000..c674cc99fa --- /dev/null +++ b/src/main/java/org/perlonjava/runtime/runtimetypes/RegexCallbackMutationSnapshot.java @@ -0,0 +1,89 @@ +package org.perlonjava.runtime.runtimetypes; + +import java.util.ArrayDeque; +import java.util.IdentityHashMap; +import java.util.Map; + +/** Backtracking savepoint for mutations made by a plain {@code (?{...})} block. */ +public final class RegexCallbackMutationSnapshot { + private final IdentityHashMap scalars = new IdentityHashMap<>(); + private final IdentityHashMap arrays = new IdentityHashMap<>(); + private final IdentityHashMap hashes = new IdentityHashMap<>(); + private final IdentityHashMap seen = new IdentityHashMap<>(); + + private RegexCallbackMutationSnapshot(RuntimeCode callback) { + ArrayDeque work = new ArrayDeque<>(); + if (callback.closedOverVariables != null) { + addAll(work, callback.closedOverVariables.values()); + } + addAll(work, callback.capturedScalars); + addAll(work, callback.capturedAggregates); + if (callback.ourVariableRegistry != null) { + for (Map.Entry entry : callback.ourVariableRegistry.entrySet()) { + String name = entry.getKey(); + String packageName = entry.getValue(); + if (name == null || name.length() < 2 || packageName == null) continue; + String fullName = packageName + "::" + name.substring(1); + RuntimeBase cell = switch (name.charAt(0)) { + case '@' -> GlobalVariable.getGlobalArray(fullName); + case '%' -> GlobalVariable.getGlobalHash(fullName); + default -> GlobalVariable.getGlobalVariable(fullName); + }; + work.add(cell); + } + } + capture(work); + } + + public static RegexCallbackMutationSnapshot capture(RuntimeCode callback) { + return new RegexCallbackMutationSnapshot(callback); + } + + private void capture(ArrayDeque work) { + while (!work.isEmpty()) { + RuntimeBase value = work.removeLast(); + if (value == null || seen.put(value, Boolean.TRUE) != null) continue; + if (value instanceof RuntimeScalar scalar) { + Object state = scalar.snapshotRegexMutationState(); + if (state != null) scalars.put(scalar, state); + if (scalar.value instanceof RuntimeArray array) work.add(array); + else if (scalar.value instanceof RuntimeHash hash) work.add(hash); + else if (scalar.value instanceof RuntimeScalar nested) work.add(nested); + } else if (value instanceof RuntimeArray array) { + Object state = array.snapshotRegexMutationState(); + if (state == null) continue; + arrays.put(array, state); + addAll(work, array.elements); + } else if (value instanceof RuntimeHash hash) { + Object state = hash.snapshotRegexMutationState(); + if (state == null) continue; + hashes.put(hash, state); + addAll(work, hash.elements.values()); + } + } + } + + public void restore() { + for (Map.Entry entry : arrays.entrySet()) { + entry.getKey().restoreRegexMutationState(entry.getValue()); + } + for (Map.Entry entry : hashes.entrySet()) { + entry.getKey().restoreRegexMutationState(entry.getValue()); + } + for (Map.Entry entry : scalars.entrySet()) { + entry.getKey().restoreRegexMutationState(entry.getValue()); + } + MortalList.flush(); + } + + private static void addAll(ArrayDeque work, + Iterable values) { + if (values == null) return; + for (RuntimeBase value : values) if (value != null) work.add(value); + } + + private static void addAll(ArrayDeque work, RuntimeBase[] values) { + if (values == null) return; + for (RuntimeBase value : values) if (value != null) work.add(value); + } +} diff --git a/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeArray.java b/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeArray.java index 2fb46e5534..8a60151c7d 100644 --- a/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeArray.java +++ b/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeArray.java @@ -1708,6 +1708,14 @@ public Iterator iterator() { return new RuntimeArrayIterator(); } + @Override + public Iterator foreachAliasIterator() { + // Plain Perl arrays are live during foreach: structural changes alter + // the remaining membership. Tied arrays retain FETCH-based snapshot + // behavior because their backing TieArray is not directly iterable. + return type == TIED_ARRAY ? getArrayOfAlias().iterator() : iterator(); + } + /** * Returns a string representation of the array reference. * diff --git a/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeBase.java b/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeBase.java index 8e2c058aa5..135e5be019 100644 --- a/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeBase.java +++ b/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeBase.java @@ -491,6 +491,14 @@ public RuntimeArray getArrayOfAlias() { return arr; } + /** + * Returns the iterator used by an implicit-topic foreach loop. + * Non-array list expressions retain their evaluated membership snapshot. + */ + public Iterator foreachAliasIterator() { + return getArrayOfAlias().iterator(); + } + /** * Retrieves the argument array for {@code goto &sub}. Most values use * ordinary aliasing, but RuntimeArray overrides this to transfer ownership diff --git a/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeCode.java b/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeCode.java index fe422a748f..2230341947 100644 --- a/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeCode.java +++ b/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeCode.java @@ -21,6 +21,7 @@ import org.perlonjava.runtime.ForkOpenCompleteException; import org.perlonjava.runtime.HintHashRegistry; import org.perlonjava.runtime.WarningBitsRegistry; +import org.perlonjava.runtime.regex.RegexQuoteMeta; import org.perlonjava.runtime.mro.InheritanceResolver; import org.perlonjava.runtime.debugger.DebugHooks; import org.perlonjava.runtime.debugger.DebugState; @@ -279,7 +280,8 @@ public static void pushActiveCode(RuntimeCode code) { PerlRuntime runtime = PerlRuntime.current(); ExecutionRuntimeState executionState = runtime.executionState(); activeCodeStack(executionState).push(code); - if (runtime.runtimeCodeState().lexicalAliasSupportEnabled) { + if (runtime.runtimeCodeState().lexicalAliasSupportEnabled + || code.tracksRuntimeRegexLexicals) { activeLexicalFrames(executionState).push( new ActiveLexicalFrame(code, new HashMap<>())); } @@ -288,7 +290,8 @@ public static void pushActiveCode(RuntimeCode code) { public static void popActiveCode(RuntimeCode code) { PerlRuntime runtime = PerlRuntime.current(); ExecutionRuntimeState executionState = runtime.executionState(); - if (runtime.runtimeCodeState().lexicalAliasSupportEnabled) { + if (runtime.runtimeCodeState().lexicalAliasSupportEnabled + || code.tracksRuntimeRegexLexicals) { Deque frames = activeLexicalFrames(executionState); if (!frames.isEmpty() && frames.peek().code() == code) { frames.pop(); @@ -351,7 +354,8 @@ private static boolean sameLogicalCode(RuntimeCode left, RuntimeCode right) { private static void registerActiveLexical( RuntimeCode code, String variableName, RuntimeBase cell) { PerlRuntime runtime = PerlRuntime.current(); - if (!runtime.runtimeCodeState().lexicalAliasSupportEnabled) return; + if (!runtime.runtimeCodeState().lexicalAliasSupportEnabled + && (code == null || !code.tracksRuntimeRegexLexicals)) return; Deque frames = activeLexicalFrames(runtime.executionState()); for (ActiveLexicalFrame frame : frames) { if (sameLogicalCode(frame.code(), code)) { @@ -399,7 +403,8 @@ public static String findActiveLexicalName(RuntimeBase cell) { public static Map snapshotActiveLexicals(RuntimeCode code) { if (code == null) return Collections.emptyMap(); PerlRuntime runtime = PerlRuntime.current(); - if (!runtime.runtimeCodeState().lexicalAliasSupportEnabled) { + if (!runtime.runtimeCodeState().lexicalAliasSupportEnabled + && !code.tracksRuntimeRegexLexicals) { return Collections.emptyMap(); } for (ActiveLexicalFrame frame : activeLexicalFrames(runtime.executionState())) { @@ -985,6 +990,10 @@ public static void registerPadConstants(String className, RuntimeBase[] constant // A callback compiled as part of qr// contributes Perl's anonymous-regex // frame to caller(), unlike an inline m// callback pseudo-block. public boolean isQuotedRegexCallback = false; + // Executable regex interpolation may stringify an overloaded value into + // source that references any lexical in the containing CV. Track live pad + // cells for these rare CVs without enabling global Devel::LexAlias support. + public boolean tracksRuntimeRegexLexicals = false; // Implementation callbacks such as map/grep do not introduce a Perl // subroutine scope, so their __SUB__ comes from the enclosing RuntimeCode. public boolean inheritsSelfReference = false; @@ -1196,6 +1205,14 @@ public static RuntimeScalar attachLexicalVariableNames( return codeRef; } + /** Mark a generated CODE value as requiring live lexical regex-source access. */ + public static RuntimeScalar markRuntimeRegexLexicals(RuntimeScalar codeRef) { + if (codeRef != null && codeRef.value instanceof RuntimeCode code) { + code.tracksRuntimeRegexLexicals = true; + } + return codeRef; + } + /** Devel::LexAlias replacements applied when a lexical is instantiated. */ public Map lexicalAliases; @@ -1432,6 +1449,7 @@ public RuntimeCode cloneForClosure() { clone.cvStartLine = this.cvStartLine; clone.isRegexCallbackPseudoBlock = this.isRegexCallbackPseudoBlock; clone.isQuotedRegexCallback = this.isQuotedRegexCallback; + clone.tracksRuntimeRegexLexicals = this.tracksRuntimeRegexLexicals; clone.deparseSourceText = this.deparseSourceText; clone.deparseFlags = this.deparseFlags; clone.deparseSourceOffset = this.deparseSourceOffset; @@ -1990,6 +2008,11 @@ public void adoptDefinitionFrom(RuntimeCode codeFrom) { this.isMapGrepBlock = codeFrom.isMapGrepBlock; this.isRegexCallbackPseudoBlock = codeFrom.isRegexCallbackPseudoBlock; this.isQuotedRegexCallback = codeFrom.isQuotedRegexCallback; + // A lazy named-CV placeholder is annotated from its parsed body before + // the backend executable exists. Materialization must not overwrite + // that source-policy marker with the backend object's default false. + this.tracksRuntimeRegexLexicals = this.tracksRuntimeRegexLexicals + || codeFrom.tracksRuntimeRegexLexicals; this.inheritsSelfReference = codeFrom.inheritsSelfReference; this.isEvalBlock = codeFrom.isEvalBlock; this.explicitlyRenamed = codeFrom.explicitlyRenamed; @@ -2870,6 +2893,7 @@ public static RuntimeList evalStringWithInterpreter( // Create parser context ScopedSymbolTable parseSymbolTable = capturedSymbolTable.snapShot(); + String lexicalEvalWarningBits = parseSymbolTable.getWarningBitsString(); // Eval STRING inherits the caller's lexical warning bits. The // interpreter does not have JVM call-site instructions to // reconstruct this state later, so seed the parser scope from @@ -2906,9 +2930,12 @@ public static RuntimeList evalStringWithInterpreter( Parser parser = new Parser(evalCtx, tokens); BHooksEndOfScope.beginFileLoad(evalCompilerOptions.fileName); + String savedRegexWarningBits = RegexQuoteMeta.getParserWarningBits(); + RegexQuoteMeta.setParserWarningBits(lexicalEvalWarningBits); try { ast = parser.parse(); } finally { + RegexQuoteMeta.setParserWarningBits(savedRegexWarningBits); BHooksEndOfScope.endFileLoad(evalCompilerOptions.fileName); } @@ -3902,6 +3929,12 @@ public static RuntimeList callerWithSub(RuntimeList args, int ctx, RuntimeScalar } frame = callerFrameIncludingRegexPseudoBlocks(frame); + // Perl treats every negative caller depth as an out-of-range frame. + // Return the usual empty result before indexing implementation stacks; + // in scalar context an empty RuntimeList naturally becomes undef. + if (frame < 0) { + return res; + } // Save the original user-supplied frame before the JVM skip adjustment. // This value maps directly to hasArgsStack depth: caller(0) → depth 0 (current frame), diff --git a/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeGraphCloner.java b/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeGraphCloner.java index 185693fb1c..18eacec20a 100644 --- a/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeGraphCloner.java +++ b/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeGraphCloner.java @@ -1,7 +1,9 @@ package org.perlonjava.runtime.runtimetypes; import org.perlonjava.backend.bytecode.InterpretedCode; +import org.perlonjava.runtime.CompilationRuntimeState; import org.perlonjava.runtime.regex.RuntimeRegex; +import org.perlonjava.runtime.regex.RuntimeRegexCallback; import org.perlonjava.runtime.io.BorrowedIOHandle; import org.perlonjava.runtime.io.ClosedIOHandle; import org.perlonjava.runtime.io.DupIOHandle; @@ -95,6 +97,28 @@ List cloneSnapshotRoots(List roots) { return result; } + /** + * Clone the compile-time hint snapshots referenced by compiled call sites. + * + *

    The integer IDs are embedded in JVM/interpreter code. Their typed + * values must therefore cross an ithread boundary with the same IDs and + * through the same graph map as package globals and entry CODE. In + * particular, a lexical {@code %^H} CODE reference must resolve to the + * child-owned clone of that callback rather than the parent's pad.

    + */ + void cloneCompilationHints( + CompilationRuntimeState source, CompilationRuntimeState target) { + source.hintSnapshots.forEach((id, snapshot) -> + target.hintSnapshots.put(id, Map.copyOf(snapshot))); + source.hintScalarSnapshots.forEach((id, snapshot) -> { + Map cloned = new LinkedHashMap<>(); + snapshot.forEach((name, value) -> + cloned.put(name, (RuntimeScalar) cloneValue(value))); + target.hintScalarSnapshots.put(id, Map.copyOf(cloned)); + }); + target.nextHintSnapshotId.set(source.nextHintSnapshotId.get()); + } + private void finishCloneBoundary() { Map observed = sourceRuntime.snapshotReferenceAddresses(); // A stringified object can remain visible only through a weak Perl @@ -197,6 +221,15 @@ protected RuntimeBase cloneCode(RuntimeCode source) { return target; } + private RuntimeRegexCallback cloneRegexCallback(RuntimeRegexCallback source) { + Object existing = clones.get(source); + if (existing != null) return (RuntimeRegexCallback) existing; + RuntimeRegexCallback target = source.cloneForThread( + code -> (RuntimeCode) cloneValue(code)); + clones.put(source, target); + return target; + } + private InterpretedCode cloneInterpretedCode(InterpretedCode source) { // Register a temporary RuntimeCode first so recursive captured CODE // edges resolve. The finished interpreted object replaces it before @@ -251,6 +284,7 @@ private void copyCodeMetadata(RuntimeCode source, RuntimeCode target) { target.isDeclared = source.isDeclared; target.isSymbolicReference = source.isSymbolicReference; target.isClosurePrototype = source.isClosurePrototype; + target.tracksRuntimeRegexLexicals = source.tracksRuntimeRegexLexicals; target.definitionPending = source.definitionPending; if (source.compilerSupplier == null) { target.compilerSupplier = null; @@ -441,7 +475,7 @@ private RuntimeScalar cloneScalar(RuntimeScalar source) { } else if (source.type == CODE && source.value instanceof RuntimeCode code) { target.value = cloneCode(code); } else if (source.value instanceof RuntimeRegex regex) { - target.value = regex.cloneTracked(); + target.value = regex.cloneTrackedForThread(this::cloneRegexCallback); } else if (source.value instanceof RuntimeIO io) { RuntimeIO inherited = cloneRuntimeIO(io); if (inherited != null) { diff --git a/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeHashProxyEntry.java b/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeHashProxyEntry.java index 5f7dedb036..d80d7d606d 100644 --- a/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeHashProxyEntry.java +++ b/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeHashProxyEntry.java @@ -192,4 +192,27 @@ public void dynamicRestoreState() { } } } + + /** + * Detach a localized hash element while a regex callback frame is held by + * the matcher. The ordinary save/restore stack remembers the outer value; + * this token separately carries the active localized value to the next + * callback on the same successful path. + */ + @Override + public Object dynamicSuspendState() { + RuntimeScalar active = parent.elements.get(key); + RuntimeScalar token = active == null ? null : new RuntimeScalar(active); + dynamicRestoreState(); + return token; + } + + /** Reinstall a localized hash element detached by dynamicSuspendState(). */ + @Override + public void dynamicResumeState(Object token) { + dynamicSaveState(); + if (token instanceof RuntimeScalar active) { + active.addToScalar(this); + } + } } diff --git a/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeScalar.java b/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeScalar.java index 0dc8511bdb..f65577fd3f 100644 --- a/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeScalar.java +++ b/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeScalar.java @@ -717,16 +717,16 @@ Object snapshotRegexMutationState() { void restoreRegexMutationState(Object token) { if (!(token instanceof RegexMutationState state)) return; - type = state.type; - value = state.value; - utf8UncheckedOctets = state.utf8UncheckedOctets; - tainted = state.tainted; - numericLiteralText = state.numericLiteralText; - numericContextSeen = state.numericContextSeen; - firstClassRegexScalar = state.firstClassRegexScalar; - formatPictureTainted = state.formatPictureTainted; - RuntimePosLvalue.invalidatePos(this); - refreshSubstrLvalues(); + RuntimeScalar restored = new RuntimeScalar(); + restored.type = state.type; + restored.value = state.value; + restored.utf8UncheckedOctets = state.utf8UncheckedOctets; + restored.tainted = state.tainted; + restored.numericLiteralText = state.numericLiteralText; + restored.numericContextSeen = state.numericContextSeen; + restored.firstClassRegexScalar = state.firstClassRegexScalar; + restored.formatPictureTainted = state.formatPictureTainted; + set(restored); } private record RegexMutationState(int type, Object value, @@ -2746,16 +2746,7 @@ public RuntimeScalar scalarDeref() { yield newScalar; } case REFERENCE -> (RuntimeScalar) value; - case REGEX -> { - // Dereferencing qr// produces a non-reference scalar whose - // string value is the compiled pattern, but whose referent type - // remains REGEXP (reftype(\${qr/foo/}) eq "REGEXP"). - RuntimeScalar result = new RuntimeScalar(); - result.type = RuntimeScalarType.STRING; - result.value = this.value.toString(); - result.firstClassRegexScalar = true; - yield result.propagateTaint(this); - } + case REGEX -> dereferencedRegexScalar(); case GLOB -> { // Dereferencing a glob as scalar returns the scalar slot // e.g., ${*Foo::VERSION} or ${$glob} where $glob is a glob @@ -2803,6 +2794,7 @@ public RuntimeScalar scalarDerefNonStrict(String packageName) { return switch (type) { case REFERENCE -> (RuntimeScalar) value; + case REGEX -> dereferencedRegexScalar(); case GLOB -> { // Dereferencing a glob as scalar returns the scalar slot if (value instanceof RuntimeGlob glob) { @@ -2832,6 +2824,14 @@ public RuntimeScalar scalarDerefNonStrict(String packageName) { }; } + private RuntimeScalar dereferencedRegexScalar() { + RuntimeScalar result = new RuntimeScalar(); + result.type = RuntimeScalarType.STRING; + result.value = this.value.toString(); + result.firstClassRegexScalar = true; + return result.propagateTaint(this); + } + // Method to implement `%$v`, when "no strict refs" is in effect public RuntimeHash hashDerefNonStrict(String packageName) { // Check if object is eligible for overloading @@ -3746,15 +3746,15 @@ private RuntimeScalar preAutoIncrementWithoutWatcherNotification() { // Prepare overload context and check if object is eligible for overloading OverloadContext ctx = OverloadContext.prepare(blessId); if (ctx != null) { + boolean copiedToPlainScalar = false; // Copy-on-write: If the object has the = overload, call it to create // a copy BEFORE any mutation. This implements Perl's COW semantics // where shared references are copied before modification. // Example: my $b = $a; $b++; should NOT modify $a RuntimeScalar copyResult = ctx.tryOverload("(=", new RuntimeArray(this)); if (copyResult != null) { - // Copy the cloned object's fields into this - this.type = copyResult.type; - this.value = copyResult.value; + set(copyResult); + copiedToPlainScalar = !RuntimeScalarType.isReference(this); } // Try direct overload method for ++ @@ -3773,6 +3773,13 @@ private RuntimeScalar preAutoIncrementWithoutWatcherNotification() { this.value = result.value; return this; } + + // An explicit copy constructor may return a plain value. + // Perl applies the native increment to that copied value + // when neither ++ nor + supplies the mutation. + if (copiedToPlainScalar) { + return preAutoIncrementWithoutWatcherNotification(); + } } } @@ -3881,14 +3888,14 @@ private RuntimeScalar postAutoIncrementLarge() { // Prepare overload context and check if object is eligible for overloading OverloadContext ctx = OverloadContext.prepare(blessId); if (ctx != null) { + boolean copiedToPlainScalar = false; // Copy-on-write: If the object has the = overload, call it to create // a copy BEFORE any mutation. This implements Perl's COW semantics // where shared references are copied before modification. RuntimeScalar copyResult = ctx.tryOverload("(=", new RuntimeArray(this)); if (copyResult != null) { - // Copy the cloned object's fields into this - this.type = copyResult.type; - this.value = copyResult.value; + set(copyResult); + copiedToPlainScalar = !RuntimeScalarType.isReference(this); } // Try direct overload method for ++ @@ -3907,6 +3914,11 @@ private RuntimeScalar postAutoIncrementLarge() { this.value = result.value; return old; } + + if (copiedToPlainScalar) { + preAutoIncrementWithoutWatcherNotification(); + return old; + } } } diff --git a/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeScalarReadOnly.java b/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeScalarReadOnly.java index baaaa43b6f..7ee739f5b1 100644 --- a/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeScalarReadOnly.java +++ b/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeScalarReadOnly.java @@ -1,5 +1,7 @@ package org.perlonjava.runtime.runtimetypes; +import org.perlonjava.runtime.operators.PerlUtfString; + import static org.perlonjava.runtime.runtimetypes.RuntimeScalarType.BYTE_STRING; import static org.perlonjava.runtime.runtimetypes.RuntimeScalarType.DOUBLE; import static org.perlonjava.runtime.runtimetypes.RuntimeScalarType.INTEGER; @@ -154,7 +156,8 @@ public RuntimeScalar chop() { return new RuntimeScalar(""); } if (s == null || s.isEmpty()) return new RuntimeScalar(""); - return new RuntimeScalar(s.substring(s.length() - 1)); + return new RuntimeScalar(s.substring( + PerlUtfString.lastLogicalCharacterStart(s))); } /** diff --git a/src/main/java/org/perlonjava/runtime/runtimetypes/WarningFlags.java b/src/main/java/org/perlonjava/runtime/runtimetypes/WarningFlags.java index a37c15c2e9..1163d10f04 100644 --- a/src/main/java/org/perlonjava/runtime/runtimetypes/WarningFlags.java +++ b/src/main/java/org/perlonjava/runtime/runtimetypes/WarningFlags.java @@ -692,6 +692,12 @@ public static boolean areWarningsForcedOn() { public static boolean areWarningsForcedOff() { return state().commandLineWarningOverride < 0; } + + /** Whether Perl's package-global {@code $^W} warning switch is active. */ + public static boolean isGlobalWarningVariableEnabled() { + return GlobalVariable.getGlobalVariable( + "main::" + Character.toString('W' - 'A' + 1)).getBoolean(); + } /** * Expands a warning category to include all its subcategories. diff --git a/src/main/perl/lib/I18N/LangTags/List.pm b/src/main/perl/lib/I18N/LangTags/List.pm index 005c2eb9d5..6bbb1980a0 100644 --- a/src/main/perl/lib/I18N/LangTags/List.pm +++ b/src/main/perl/lib/I18N/LangTags/List.pm @@ -28,6 +28,7 @@ our $VERSION = '0.42'; $Is_Disrec{$1} = 1; } } + close DATA; die "No tags read??" unless $count; } #---------------------------------------------------------------------- diff --git a/src/main/perl/lib/IO/Dir.pm b/src/main/perl/lib/IO/Dir.pm index a62c146ee6..fa1ec63dac 100644 --- a/src/main/perl/lib/IO/Dir.pm +++ b/src/main/perl/lib/IO/Dir.pm @@ -18,7 +18,7 @@ use File::stat; use File::Spec; our @ISA = qw(Tie::Hash Exporter); -our $VERSION = "1.56"; +our $VERSION = "1.57"; our @EXPORT_OK = qw(DIR_UNLINK); diff --git a/src/main/perl/lib/IO/Select.pm b/src/main/perl/lib/IO/Select.pm index 97ffd0f499..8e8846fa75 100644 --- a/src/main/perl/lib/IO/Select.pm +++ b/src/main/perl/lib/IO/Select.pm @@ -10,7 +10,7 @@ use strict; use warnings::register; require Exporter; -our $VERSION = "1.56"; +our $VERSION = "1.57"; our @ISA = qw(Exporter); # This is only so we can do version checking diff --git a/src/main/perl/lib/IO/Socket.pm b/src/main/perl/lib/IO/Socket.pm index 779b23bf8b..f8a0cd552c 100644 --- a/src/main/perl/lib/IO/Socket.pm +++ b/src/main/perl/lib/IO/Socket.pm @@ -23,7 +23,7 @@ require IO::Socket::UNIX if ($^O ne 'epoc' && $^O ne 'symbian'); our @ISA = qw(IO::Handle); -our $VERSION = "1.56"; +our $VERSION = "1.57"; our @EXPORT_OK = qw(sockatmark); diff --git a/src/main/perl/lib/IO/Socket/INET.pm b/src/main/perl/lib/IO/Socket/INET.pm index 45fd139d92..ed981bbcdf 100644 --- a/src/main/perl/lib/IO/Socket/INET.pm +++ b/src/main/perl/lib/IO/Socket/INET.pm @@ -14,7 +14,7 @@ use Exporter; use Errno; our @ISA = qw(IO::Socket); -our $VERSION = "1.56"; +our $VERSION = "1.57"; my $EINVAL = exists(&Errno::EINVAL) ? Errno::EINVAL() : 1; diff --git a/src/main/perl/lib/IO/Socket/UNIX.pm b/src/main/perl/lib/IO/Socket/UNIX.pm index 2542b82b14..fb9ee5e8ef 100644 --- a/src/main/perl/lib/IO/Socket/UNIX.pm +++ b/src/main/perl/lib/IO/Socket/UNIX.pm @@ -11,7 +11,7 @@ use IO::Socket; use Carp; our @ISA = qw(IO::Socket); -our $VERSION = "1.56"; +our $VERSION = "1.57"; IO::Socket::UNIX->register_domain( AF_UNIX ); diff --git a/src/main/perl/lib/Net/Ping.pm b/src/main/perl/lib/Net/Ping.pm index 2b1e51b113..e51d854498 100644 --- a/src/main/perl/lib/Net/Ping.pm +++ b/src/main/perl/lib/Net/Ping.pm @@ -22,7 +22,7 @@ use Time::HiRes; @ISA = qw(Exporter); @EXPORT = qw(pingecho); @EXPORT_OK = qw(wakeonlan); -$VERSION = "2.77"; +$VERSION = "2.78"; # Globals diff --git a/src/main/perl/lib/Pod/perl.pod b/src/main/perl/lib/Pod/perl.pod index 55f95cde84..0a4e0a5f2f 100644 --- a/src/main/perl/lib/Pod/perl.pod +++ b/src/main/perl/lib/Pod/perl.pod @@ -182,7 +182,8 @@ aux h2ph h2xs perlbug pl2pm pod2html pod2man splain xsubpp perlhist Perl history records perldelta Perl changes since previous version - perl5450delta Perl changes in version 5.45.0 + perl5452delta Perl changes in version 5.45.2 + perl5451delta Perl changes in version 5.45.1 perl5440delta Perl changes in version 5.44.0 perl5423delta Perl changes in version 5.42.3 perl5422delta Perl changes in version 5.42.2 diff --git a/src/main/perl/lib/Pod/perl5450delta.pod b/src/main/perl/lib/Pod/perl5450delta.pod index 8edcaca4cc..2df22e1a95 100644 --- a/src/main/perl/lib/Pod/perl5450delta.pod +++ b/src/main/perl/lib/Pod/perl5450delta.pod @@ -168,7 +168,7 @@ accuracy will hopefully follow within this development cycle. =head1 Acknowledgements -Perl 5.45.1 represents approximately 1 week of development since Perl 5.44.0 +Perl 5.45.0 represents approximately 1 week of development since Perl 5.44.0 and contains approximately 36,000 lines of changes across 470 files from 19 authors. @@ -177,7 +177,7 @@ approximately 12,000 lines of changes to 310 .pm, .t, .c and .h files. Perl continues to flourish into its fourth decade thanks to a vibrant community of users and developers. The following people are known to have -contributed the improvements that became Perl 5.45.1: +contributed the improvements that became Perl 5.45.0: Andrew Fresh, Chad Granum, Chris 'BinGOs' Williams, Craig A. Berry, Dagfinn Ilmari Mannsåker, David Mitchell, Georgij Tsarin, Graham Knop, James E diff --git a/src/main/perl/lib/Pod/perl5451delta.pod b/src/main/perl/lib/Pod/perl5451delta.pod new file mode 100644 index 0000000000..aac1395f26 --- /dev/null +++ b/src/main/perl/lib/Pod/perl5451delta.pod @@ -0,0 +1,254 @@ +=encoding utf8 + +=head1 NAME + +perl5451delta - what is new for perl v5.45.1 + +=head1 DESCRIPTION + +This document describes differences between the 5.44.0 release and the 5.45.1 +release. + +If you are upgrading from an earlier release such as 5.43.0, first read +L, which describes differences between 5.43.0 and 5.44.0. + +=head1 Performance Enhancements + +=over 4 + +=item * + +Some pattern matches against long strings are now faster: in particular +where the pattern: is anchored; contains a short fixed substring; and +contains a floating substring which is as long or longer than than the +fixed substring; but where the fixed substring isn't present in the +target string. For example this match will be rejected much faster now: + + "-" x 10_000_000 =~ /^abc.*def/ + +=back + +=head1 Modules and Pragmata + +=head2 Updated Modules and Pragmata + +=over 4 + +=item * + +L has been upgraded from version 1.11 to 1.12. + +=item * + +L has been upgraded from version 3.63 to 3.64. + +=item * + +L has been upgraded from version 3.63 to 3.64. + +=item * + +L has been upgraded from version 1.20 to 1.21. + +=item * + +L has been upgraded from version 2.02 to 2.03. + +=item * + +L has been upgraded from version 4.16 to 4.18. + +=item * + +L has been upgraded from version 5.20260715 to 5.20260720. + +=item * + +L has been upgraded from version v6.0.2 to v6.1.0. + +=item * + +L has been upgraded from version 1.29 to 1.30. + +=item * + +L has been upgraded from version 1.302219 to 1.302222. + +=item * + +L has been upgraded from version 2.45 to 2.46. + +=item * + +L has been upgraded from version 1.73 to 1.74. + +=item * + +L has been upgraded from version 1.50 to 1.51. + +=back + +=head1 Platform Support + +=head2 Platform-Specific Notes + +=over 4 + +=item VMS + +Socket support is no longer a configure-time option on OpenVMS; sockets will +always be available in Perl and are based on the universal socket support in the +CRTL. + +=back + +=head1 Internal Changes + +=over 4 + +=item * + +Added new API function C which does the same lexical export +that the L function does. + +=item * + +Mutex locks for C and C are removed + +The macros C and C macros are +removed, along with their unlocking counterparts. These macros, though +never documented, were intended to create thread safety when using their +corresponding functions in a threaded-perl. But they didn't actually +furnish that, so using them would give a false sense of security. +Another thread simultaneously accessing the database could move the +pointers, so these would act unpredictably. + +=item * + +New macros created for thread-safety in libc calls + +Many C library functions are not thread safe, but can be made so by +using mutexes around them to lock out other threads from interrupting +their execution. Many macros have now been created for this purpose. +Guidance for using them, and the functions they protect are listed in +L; their actual definitions are found in +F. If you call a libc function, look in +L to see if we have created locking macros for it. The macros +are based on man pages (especially Linux ones), and our experience. We +also know from experience that man pages can be wrong or incomplete, and +the behavior of any given function may be platform dependent. Patches +to update our knowledge base are welcome. + +More detail can be found in +L. + +=back + +=head1 Selected Bug Fixes + +=over 4 + +=item * + +Allow field lookups within methods in nested scopes to succeed, +previously they could complain that C. + +This was most confusingly broken with a use: + + class A { + field $fieldname; + use overload '""' => method (@) { $fieldname }; + } + +since the syntax hides the C sub. + +[L] + +=item * + +Many potential threads-related race conditions have been fixed in the perl +core and the two L and L modules. + +=item * + +Line numbers reported by C and diagnostic messages are now more +accurate when the relevant COP has been optimized out (occurring often +when the line is the first in an C block, or when the line is +inside a loop condition (such as within a C). +[L] +[L] + +Note that (i) these changes could break any tests that hardcode the +less-accurate line numbers (ii) further improvements to line number +accuracy will hopefully follow within this development cycle. + +=back + +=head1 Acknowledgements + +Perl 5.45.1 represents approximately 1 week of development since Perl 5.44.0 +and contains approximately 36,000 lines of changes across 470 files from 19 +authors. + +Excluding auto-generated files, documentation and release tools, there were +approximately 12,000 lines of changes to 310 .pm, .t, .c and .h files. + +Perl continues to flourish into its fourth decade thanks to a vibrant +community of users and developers. The following people are known to have +contributed the improvements that became Perl 5.45.1: + +Andrew Fresh, Chad Granum, Chris 'BinGOs' Williams, Craig A. Berry, Dagfinn +Ilmari Mannsåker, David Mitchell, Georgij Tsarin, Graham Knop, James E +Keenan, Karl Williamson, Leon Timmermans, Lukas Mai, Paul Evans, Philippe +Bruhat (BooK), Richard Leach, Russ Allbery, Steve Hay, Tony Cook, Yves +Orton. + +The list above is almost certainly incomplete as it is automatically +generated from version control history. In particular, it does not include +the names of the (very much appreciated) contributors who reported issues to +the Perl bug tracker. + +Many of the changes included in this version originated in the CPAN modules +included in Perl's core. We're grateful to the entire CPAN community for +helping Perl to flourish. + +For a more complete list of all of Perl's historical contributors, please +see the F file in the Perl source distribution. + +=head1 Reporting Bugs + +If you find what you think is a bug, you might check the perl bug database +at L. There may also be information at +L, the Perl Home Page. + +If you believe you have an unreported bug, please open an issue at +L. Be sure to trim your bug down to a +tiny but sufficient test case. + +If the bug you are reporting has security implications which make it +inappropriate to send to a public issue tracker, then see +L +for details of how to report the issue. + +=head1 Give Thanks + +If you wish to thank the Perl 5 Porters for the work we had done in Perl 5, +you can do so by running the C program: + + perlthanks + +This will send an email to the Perl 5 Porters list with your show of thanks. + +=head1 SEE ALSO + +The F file for an explanation of how to view exhaustive details on +what changed. + +The F file for how to build Perl. + +The F file for general stuff. + +The F and F files for copyright information. + +=cut diff --git a/src/main/perl/lib/Pod/perl5452delta.pod b/src/main/perl/lib/Pod/perl5452delta.pod new file mode 100644 index 0000000000..bce2d88dc1 --- /dev/null +++ b/src/main/perl/lib/Pod/perl5452delta.pod @@ -0,0 +1,434 @@ +=encoding utf8 + +=head1 NAME + +perl5452delta - what is new for perl v5.45.2 + +=head1 DESCRIPTION + +This document describes differences between the 5.45.1 release and the 5.45.2 +release. + +If you are upgrading from an earlier release such as 5.44.0, first read +L, which describes differences between 5.44.0 and 5.45.1. + +=head1 Core Enhancements + +=head2 Magic v2 + +This version introduces a whole new set of API functions, data structures, and +related items that provides a new kind of variable magic; providing the +ability to attach user-supplied trigger functions to behaviours on existing +variables. + +The eventual intention of this new version is to extend magic with new trigger +functions that can apply at different times to those currently supported, and +to allow magic to be attached to new kinds of items than are currently +permitted. Right now as of this iteration, it does not offer any new abilities +but simply changes the shape and structure of existing things to allow space +for those extensions to be made at a later date. + +For more details, see L. + +=head1 Incompatible Changes + +=head2 Names derived from class fields skip a leading underscore + +If the name of a class field starts with an underscore, any derived constructor +parameters (C<:param>) or methods (C<:reader>, C<:writer>) will skip that +underscore: + + class Foo { + field $_bar :param :reader :writer; + # Equivalent to: + # field $_bar :param(bar) :reader(bar) :writer(set_bar); + } + +This is how L works, too. + +In previous versions of Perl, the underscore was retained, making the above +declaration equivalent to C<< field $_bar :param(_bar) :reader(_bar) +:writer(set__bar); >>. + +=head1 Performance Enhancements + +=over 4 + +=item * + +C has been added to streamline expressions such as +C<(ref $x eq 'SCALAR')> where (i) the first operator is C or +C, (ii) the comparison is C or C, and (iii) the value +being compared against is one of the internal reftype strings mentioned +in L, is C, or is the empty string C<''>. + +=item * + +Counting the number of matches within a string using the following common +idiom is now much more performant. + + my $count = () = $str =~ /$pat/g; + +Instead of pushing all matches to the stack as mortal SVs, just so that +the list assignment can count them, C maintains an internal +count during matching and pushes just that upon completion. +[L] + +=back + +=head1 Modules and Pragmata + +=head2 Updated Modules and Pragmata + +=over 4 + +=item * + +L has been upgraded from version 1.92 to 1.93. + +=item * + +L has been upgraded from version 1.89 to 1.90. + +=item * + +L has been upgraded from version 0.39 to 0.40. + +=item * + +L has been upgraded from version 1.06 to 1.07. + +=item * + +L has been upgraded from version 3.64 to 3.65. + +XS files compiled with this new version now output a slightly nicer message +when loaded in an incompatible perl binary. For example: + + XS.c in List::MoreUtils::XS: loadable library and perl binaries are + mismatched (got first handshake key 0xed00080, needed 0xee00080) + +The old message didn't include the module name, just the (potentially +ambiguous) name of the C source file: + + XS.c: loadable library and perl binaries are mismatched + (got first handshake key 0xed00080, needed 0xee00080) + +[L], [L], [L] + +=item * + +L has been upgraded from version 3.64 to 3.65. + +=item * + +L has been upgraded from version 0.41 to 0.42. + +It no longer sets C<$_> to C when loaded, and it now closes an internal +filehandle that it only uses during initialization (instead of keeping it open +for the rest of the program's lifetime). + +=item * + +L has been upgraded from version 5.20260720 to 5.20260722. + +=item * + +L has been upgraded from version 1.000039 to 1.000040. + +=item * + +L has been upgraded from version 2.77 to 2.78. + +=item * + +L has been upgraded from version 1.71 to 1.72. + +=item * + +L has been upgraded from version 0.31 to 0.32. + +=item * + +L has been upgraded from version 0.21 to 0.22. + +=item * + +L has been upgraded from version 1.36 to 1.37. + +=item * + +L has been upgraded from version 2.041 to 2.043. + +=item * + +L has been upgraded from version 1.9780 to 1.9781. + +=item * + +L has been upgraded from version 0.59_01 to 0.64. + +=item * + +L has been upgraded from version 1.51 to 1.52. + +=back + +=head1 Documentation + +=head2 Changes to Existing Documentation + +We have attempted to update the documentation to reflect the changes +listed in this document. If you find any we have missed, open an issue +at L. + +Additionally, the following selected changes have been made: + +=head3 L + +=over 4 + +=item * + +Expanded commentary on symbol visibility + +=back + +=head1 Diagnostics + +The following additions or changes have been made to diagnostic output, +including warnings and fatal error messages. For the complete list of +diagnostic messages, see L. + +=head2 New Diagnostics + +=head3 New Errors + +=over 4 + +=item * + +L + +=item * + +Lshape value %d|perldiag/"Unrecognized magicfuncs-Eshape value %d"> + +=item * + +Lver value of %u|perldiag/"Unsupported MagicFunctions-Ever value of %u"> + +=back + +=head1 Configuration and Compilation + +=over 4 + +=item * + +Perl can now be built from a directory whose path contains spaces. (However, a +few module tests still fail.) +[L] + +=item * + +The C<-[DU]usetaint> option has been added to Configure. + +=back + +=head1 Testing + +Tests were added and changed to reflect the other additions and +changes in this release. Furthermore, these significant changes were +made: + +=over 4 + +=item * + +F: Corrected to now check for entries in +F that no longer need to be there. + +=back + +=head1 Platform Support + +=head2 Platform-Specific Notes + +=over 4 + +=item MacOS (Darwin) + +Use of mkostemp(3) enabled on macOS 10.12 Sierra (Darwin 16) and newer, +where it is available. + +=back + +=head1 Internal Changes + +=over 4 + +=item * + +During compiletime of a named subroutine, the name of the new sub +currently being compiled is now accessible via C. + +=item * + +A new internal function, C attaches an SV onto a +PADNAME instance, which is used to store the name string of that padname. +This SV can be used by code that wishes to attach magic onto the padname. + +=item * + +The C pragma previously lacked increment/decrement operators that +implemented the documented pragma behaviour; these have now been added. +Code or tests that depend upon increment/decrement behaving identically +under both C and C may need revising. +[L] +[L] + +=item * + +The values of C and C no longer clash. +C is supposed to be unambiguously bitwise-or-able with any of the +C constants, but the collision with C was missed. +[L] + +=back + +=head1 Selected Bug Fixes + +=over 4 + +=item * + +Cleanup of field initialization ops for an incomplete class now +happens within the correct CV. Previously, if an error was thrown +with an incomplete class this would release pad entries on the wrong +CV and eventually crash. [L] + +=item * + +sv_set_undef() no longer blindly clears the C flag. This +could break code that expected to detect mortal SVs, like constant +folding. [L] + +=item * + +The regular expression engine's "super-linear cache" wasn't 64-bit clean +and so could in principle overflow on huge (>256Mb) strings, resulting in +incorrect matches and potential memory corruption. (The cache engages on +nested variable-width patterns such as C, to avoid exponential +backtracking.) + +[GH security issue #149] + +=item * + +The increment/decrement operators, under both C and +C, check for I magic before testing if the supplied variable +contains a reference. +[L] + +=item * + +The increment/decrement operators, under both C and +C, should now handle C<0+> overloading correctly. +[L] + +=back + +=head1 Known Problems + +=over 4 + +=item * + +Some of the CPAN module tests shipped with perl don't handle spaces in the +build path yet. +[L] + +=back + +=head1 Errata From Previous Releases + +=over 4 + +=item * + +In L, we inadvertently noted a change about mutex locks in the +section under "Incompatible Changes". That change should have been under +"Internal Changes", and has since been moved. + +=back + +=head1 Acknowledgements + +Perl 5.45.2 represents approximately 4 weeks of development since Perl +5.45.1 and contains approximately 24,000 lines of changes across 320 files +from 25 authors. + +Excluding auto-generated files, documentation and release tools, there were +approximately 15,000 lines of changes to 220 .pm, .t, .c and .h files. + +Perl continues to flourish into its fourth decade thanks to a vibrant +community of users and developers. The following people are known to have +contributed the improvements that became Perl 5.45.2: + +Andreas König, Aristotle Pagaltzis, Bartosz Jarzyna, Craig A. Berry, Dagfinn +Ilmari Mannsåker, Daniel Tang, David Mitchell, H.Merijn Brand, James E +Keenan, Jan Dubois, Karen Etheridge, Karl Williamson, Leon Timmermans, Lukas +Mai, Marc Reisner, Max Maischein, Paul Evans, Philippe Bruhat (BooK), +Richard Leach, Sevan Janiyan, Stan Ulbrych, Steve Hay, theoremoon, Tony +Cook, Yves Orton. + +The list above is almost certainly incomplete as it is automatically +generated from version control history. In particular, it does not include +the names of the (very much appreciated) contributors who reported issues to +the Perl bug tracker. + +Many of the changes included in this version originated in the CPAN modules +included in Perl's core. We're grateful to the entire CPAN community for +helping Perl to flourish. + +For a more complete list of all of Perl's historical contributors, please +see the F file in the Perl source distribution. + +=head1 Reporting Bugs + +If you find what you think is a bug, you might check the perl bug database +at L. There may also be information at +L, the Perl Home Page. + +If you believe you have an unreported bug, please open an issue at +L. Be sure to trim your bug down to a +tiny but sufficient test case. + +If the bug you are reporting has security implications which make it +inappropriate to send to a public issue tracker, then see +L +for details of how to report the issue. + +=head1 Give Thanks + +If you wish to thank the Perl 5 Porters for the work we had done in Perl 5, +you can do so by running the C program: + + perlthanks + +This will send an email to the Perl 5 Porters list with your show of thanks. + +=head1 SEE ALSO + +The F file for an explanation of how to view exhaustive details on +what changed. + +The F file for how to build Perl. + +The F file for general stuff. + +The F and F files for copyright information. + +=cut diff --git a/src/main/perl/lib/Pod/perlclass.pod b/src/main/perl/lib/Pod/perlclass.pod index e526186d78..96348f7999 100644 --- a/src/main/perl/lib/Pod/perlclass.pod +++ b/src/main/perl/lib/Pod/perlclass.pod @@ -248,6 +248,12 @@ can be specified in the attribute. field $x :param; field $y :param(the_y_value); +If the field name starts with an underscore, one underscore will be removed +from the default parameter name: + + field $_foo :param; # equivalent to :param(foo) + field $__bar :param; # equivalent to :param(_bar) + If there is no defaulting expression, then the parameter is required by the constructor; the caller must pass it or an exception is thrown. With a defaulting expression this becomes optional. @@ -272,6 +278,12 @@ leading sigil), but a different name can be specified in the attribute's value. # Generates a method method get_x () { return $x; } +As with C<:param>, if the field name starts with an underscore, one underscore +will be removed from the default method name: + + field $_foo :reader; # equivalent to :reader(foo) + field $__bar :reader; # equivalent to :reader(_bar) + Reader methods can be applied to non-scalar fields. When invoked in list context, they yield the contents of the field; in scalar context they yield the count of elements, as if the field variable had been placed in scalar @@ -304,6 +316,12 @@ can be specified in the attribute's value. # Generates a method method write_x ($new) { ... } +As with C<:reader>, if the field name starts with an underscore, one underscore +will be removed from the default method name: + + field $_foo :writer; # equivalent to :writer(set_foo) + field $__bar :writer; # equivalent to :writer(set__bar) + Currently, writer accessors can only be applied to scalar fields. Attempts to apply this attribute to a non-scalar field will result in a fatal exception at compile-time. This may be relaxed in a future version to allow writers on diff --git a/src/main/perl/lib/Pod/perldelta.pod b/src/main/perl/lib/Pod/perldelta.pod index a31d60e0a0..a38d28ca4a 100644 --- a/src/main/perl/lib/Pod/perldelta.pod +++ b/src/main/perl/lib/Pod/perldelta.pod @@ -5,15 +5,15 @@ [ this is a template for a new perldelta file. Any text flagged as XXX needs to be processed before release. ] -perldelta - what is new for perl v5.45.1 +perldelta - what is new for perl v5.45.3 =head1 DESCRIPTION -This document describes differences between the 5.45.0 release and the 5.45.1 +This document describes differences between the 5.45.2 release and the 5.45.3 release. -If you are upgrading from an earlier release such as 5.44.0, first read -L, which describes differences between 5.44.0 and 5.45.0. +If you are upgrading from an earlier release such as 5.45.1, first read +L, which describes differences between 5.45.1 and 5.45.2. =head1 Notice @@ -27,22 +27,6 @@ here, but most should go in the L section. [ List each enhancement as a =head2 entry ] -=head2 Magic v2 - -This version introduces a whole new set of API functions, data structures, and -related items that provides a new kind of variable magic; providing the -ability to attach user-supplied trigger functions to behaviours on existing -variables. - -The eventual intention of this new version is to extend magic with new trigger -functions that can apply at different times to those currently supported, and -to allow magic to be attached to new kinds of items than are currently -permitted. Right now as of this iteration, it does not offer any new abilities -but simply changes the shape and structure of existing things to allow space -for those extensions to be made at a later date. - -For more details, see L. - =head1 Security XXX Any security-related notices go here. In particular, any security @@ -105,26 +89,6 @@ There may well be none in a stable release. =item * -C has been added to streamline expressions such as -C<(ref $x eq 'SCALAR')> where (i) the first operator is C or -C, (ii) the comparison is C or C, and (iii) the value -being compared against is one of the internal reftype strings mentioned -in L, is C, or is the empty string C<''>. - -=item * - -Counting the number of matches within a string using the following common -idiom is now more streamlined. - - C - -Instead of pushing all matches to the stack as mortal SVs, just so that -the list assignment can count them, C maintains an internal -count during matching and pushes just that upon completion. -[GH #24558] - -=item * - XXX =back @@ -370,11 +334,6 @@ L section. XXX -=item MacOS (Darwin) - -Use of mkostemp(3) enabled on macOS 10.12 Sierra (Darwin 16) and newer, -where it is available. - =back =head1 Internal Changes @@ -391,48 +350,6 @@ well. XXX -=item * - -Mutex locks for C and C are removed - -The macros C and C macros are -removed, along with their unlocking counterparts. These macros, though -never documented, were intended to create thread safety when using their -corresponding functions in a threaded-perl. But they didn't actually -furnish that, so using them would give a false sense of security. -Another thread simultaneously accessing the database could move the -pointers, so these would act unpredictably. - -=item * - -New macros created for thread-safety in libc calls - -Many C library functions are not thread safe, but can be made so by -using mutexes around them to lock out other threads from interrupting -their execution. Many macros have now been created for this purpose. -Guidance for using them, and the functions they protect are listed in -L; their actual definitions are found in -F. If you call a libc function, look in -L to see if we have created locking macros for it. The macros -are based on man pages (especially Linux ones), and our experience. We -also know from experience that man pages can be wrong or incomplete, and -the behavior of any given function may be platform dependent. Patches -to update our knowledge base are welcome. - -More detail can be found in -L. - -=item * - -During compiletime of a named subroutine, the name of the new sub -currently being compiled is now accessible via C. - -=item * - -A new internal function, C attaches an SV onto a -PADNAME instance, which is used to store the name string of that padname. -This SV can be used by code that wishes to attach magic onto the padname. - =back =head1 Selected Bug Fixes @@ -449,26 +366,7 @@ manager will later use a regex to expand these into links. =item * -Cleanup of field initialization ops for an incomplete class now -happens within the correct CV. Previously, if an error was thrown -with an incomplete class this would release pad entries on the wrong -CV and eventually crash. [GH #24616] - -=item * - -sv_set_undef() no longer blindly clears the C flag. This -could break code that expected to detect mortal SVs, like constant -folding. [GH #24661] - -=item * - -The regular expression engine's "super-linear cache" wasn't 64-bit clean -and so could in principle overflow on huge (>256Mb) strings, resulting in -incorrect matches and potential memory corruption. (The cache engages on -nested variable-width patterns such as C, to avoid exponential -backtracking.) - -[GH security issue #149] +XXX =back @@ -508,7 +406,7 @@ died, add a short obituary here. XXX Generate this with: - perl Porting/acknowledgements.pl v5.45.1..HEAD + perl Porting/acknowledgements.pl v5.45.2..HEAD =head1 Reporting Bugs diff --git a/src/main/perl/lib/Pod/perlguts.pod b/src/main/perl/lib/Pod/perlguts.pod index 658ce80aa4..c9250d939d 100644 --- a/src/main/perl/lib/Pod/perlguts.pod +++ b/src/main/perl/lib/Pod/perlguts.pod @@ -3240,7 +3240,7 @@ bits. =head2 Background and MULTIPLICITY =for apidoc_section $concurrency -=for apidoc Amnh||PERL_IMPLICIT_CONTEXT +=for apidoc Amnh||MULTIPLICITY The Perl interpreter can be regarded as a closed box: it has an API for feeding it code or otherwise making it do things, but it also has @@ -3258,9 +3258,6 @@ ithreads threading model, related to the macro USE_ITHREADS.) PERL_IMPLICIT_CONTEXT is a legacy synonym for MULTIPLICITY. -=for apidoc_section $concurrency -=for apidoc Amnh||MULTIPLICITY - To see whether you have non-const data you can use a BSD (or GNU) compatible C: diff --git a/src/main/perl/lib/Pod/perlhacktips.pod b/src/main/perl/lib/Pod/perlhacktips.pod index 7b5365e577..1bff2acfd6 100644 --- a/src/main/perl/lib/Pod/perlhacktips.pod +++ b/src/main/perl/lib/Pod/perlhacktips.pod @@ -396,53 +396,108 @@ with C, C, or C, or ending with C<_pl_>. =head3 Symbol visibility For most of its life, Perl made little or no effort to hide its internal -symbols or functions. This has led to programmers using Perl to use -functionality that was dependent on Perl internal implementation -details, breaking when we unknowingly tried to change our -implementation, and thus hindering progress. - -That has been changing in recent releases, and as of v5.44, the -visibility of new symbols is restricted to just the perl core, unless an -explicit declaration is made otherwise. (Except symbol names which -match the pattern C<$names_reserved_for_perl_use_re> found in -F are made visible everywhere.) This means you can add -symbols with whatever C-compliant spelling you want, without fear that -they will be misused by someone. +symbols or functions. This made it easy for programmers to, even +inadvertently, use functionality that depended on Perl's internal +implementation details. When we tried to change those details, user +functionality often broke, thus creating frictions, and slowing down +adding improvements. -Note that symbols not placed in header files have never been visible to -outside code. +That has been changing in recent releases. In 5.38, the default +visibility of functions was changed to automatically be restricted to +just the Perl core. This was extended in 5.44 to newly added macros. +This means you can add these kinds of symbols with whatever C-compliant +spelling you want, without fear that they will clash with a user's +existing symbol or be misused by someone, + +You can override the default to make any symbol more visible as follows: + +=over 4 + +=item * To everyone + +=item * To modules considered to be Perl extensions + +=item * To just the regular expression (C) extension. + +=back + +The methods to do this vary depending on the type of symbol. + +=over 4 + +=item Functions -You should consider several things before making a new symbol visible. -The bottom line is "Who really needs to see it?" +Every function not static to a single file must have an entry in +F. Each entry will have various flags that apply to it, +including some that determine its visibility. They are listed in the +comments at the beginning of the file. -The best method is to document the symbol. How to do this is described -near the top of F, and that file can be used to mark a -symbol's visibility. But the main documentation remains using -C<=for apidoc> lines in the source and various pods. There are several -advantages to doing this +To restrict the visibilty to just the C module, more work is needed, +in the form of C preprocessor conditionals surrounding the entry, like +so: + + # if defined(PERL_EXT_RE_BUILD) + E...|return-type|function-name|arguments + # endif + +The C flag restricts the symbol's visibility to Perl Extensions; and +the #ifdef further to just the C module. + +Static functions are not required to have an F entry, but +doing so is encouraged, and has some advantages, and no downsides: =over =item 1 -People will know how to use your symbol without having to puzzle it out -from the code. That might even be you 6 months from now. +The function can be referred to by its short name, without having to +consider if it needs a thread-context parameter. =item 2 -Various services are automatically generated for symbols naming -functions, such as Cs for parameter input conditions. +Various services are automatically generated for functions, such as +Cs for parameter sanity checking. + +=back + +New services keep getting added, which mainly automatically will be +applied to your function without any effort on your part. + +=item Macros -One service is that specifying the visibility with one of the flags for -the purpose automatically makes sure the symbol has that visibility -without you having to do anything else. +You can put an entry for it in F, just like a function, but +adding the C (for macro) flag. -=item 3 +But it is often more convenient to specify the visibility at the place +where the macro is documented via C<=for apidoc> lines. The same flags +as in F entries are recognized. To restrict the visibility +to just the C module, you also need to use the same C preprocessor +conditional as you would for a function. -Simple test cases can be automatically generated. +There is an exception for macros that don't have such entries. Ones +whose names match the pattern (C<$names_reserved_for_perl_use_re> are +made visible, under the theory that you wouldn't have bothered to add +the clumsier spelling if you didn't want them visible. + +=item Enums, Typedefs, Structs, and Unions + +These unfortunately by default are visible to everyone. To restrict +their visibility, you have to resort to C preprocessor conditionals +surrounding them, like + + # if defined(PERL_CORE) + typedef enum { ... } my_enum; + # endif + +Use C to restrict the visibilty to perl extensions. =back +Note that in all cases, setting the visibility flag in an F +entry or C<=for apidoc> line, cannot make the symbol more visible than +any cpp conditionals do. You can make a symbol less visible by using +such a flag, but not more visible. + Some symbols need to be visible everywhere even though they aren't supposed to be used directly by outside code. These typically are helper functions or flag values, I, used in a public macro. @@ -453,6 +508,8 @@ likely to clash with ones an author might choose, problems don't arise. If you choose to not document a new symbol that needs to be visible everywhere, add it to the array C<@undocumented_always_visible> in F. +Note that symbols not placed in header files have never been visible to +outside code. =head3 Choosing good symbol names @@ -555,7 +612,7 @@ Therefore, if a macro does use variables, their names should be such that it is very unlikely that they would collide with any caller, now or forever. One way to do that, now being used in the perl source, is to include the name of the macro itself as part of the name of each -variable in the macro. Suppose the macro is named C Then we +variable in the macro. Suppose the macro is named C. Then we could have int foo_svpv_ = 0; diff --git a/src/main/perl/lib/Pod/perlhist.pod b/src/main/perl/lib/Pod/perlhist.pod index a6413e4427..ed4b1e58f9 100644 --- a/src/main/perl/lib/Pod/perlhist.pod +++ b/src/main/perl/lib/Pod/perlhist.pod @@ -854,6 +854,7 @@ the strings?). Leon T 5.45.0 2026-Jul-16 The 5.45 development track Paul E 5.45.1 2026-Jul-21 + Ether 5.45.2 2026-Aug-20 =head2 SELECTED RELEASE SIZES diff --git a/src/main/perl/lib/Pod/perlpod.pod b/src/main/perl/lib/Pod/perlpod.pod index c81870ffa7..626e57beb5 100644 --- a/src/main/perl/lib/Pod/perlpod.pod +++ b/src/main/perl/lib/Pod/perlpod.pod @@ -713,11 +713,11 @@ Without that empty line before the "=head1", many translators wouldn't have recognized the "=head1" as starting a Pod block. =head2 Hints for Writing Pod +X X =over =item * -X X The B command is provided for checking Pod syntax for errors and warnings. For example, it checks for completely blank lines in diff --git a/src/main/perl/lib/_charnames.pm b/src/main/perl/lib/_charnames.pm index d5bb3c4b8e..d67ef09505 100644 --- a/src/main/perl/lib/_charnames.pm +++ b/src/main/perl/lib/_charnames.pm @@ -137,12 +137,6 @@ my sub populate_txt { return if $txt; $txt = do "unicore/Name.pl"; - if (!defined $txt || $txt eq '') { - # unicore/Name.pl not available (e.g. on PerlOnJava); - # set $txt to a truthy placeholder so we don't retry and crash. - # viacode() will fall back to _java_viacode() for name lookups. - $txt = "# unavailable\n"; - } Internals::SvREADONLY($txt, 1); } @@ -428,15 +422,6 @@ sub lookup_name ($name, $wants_ord, $runtime, $regex_loose //= 0) { { $result = chr $ord; } - # PerlOnJava bundles ICU4J, whose Unicode name database is complete and - # current. Use it for strict official-name lookup before falling back to - # the generated Perl table, just as viacode() does for reverse lookup. - elsif (! $loose && $^H{charnames_full} && defined &_java_vianame - && defined(my $java_ord = _java_vianame($lookup_name))) - { - $result = chr $java_ord; - $full_names_cache{$name} = $result; - } else { # Not algorithmically determinable; look up in the table. The name @@ -822,16 +807,6 @@ sub viacode ($arg) { return $algorithmic; } - # Try Java-backed ICU4J name lookup if available (PerlOnJava). - # This provides complete Unicode name data without needing unicore/Name.pl. - if (defined &_java_viacode) { - my $java_name = _java_viacode(CORE::hex $hex); - if (defined $java_name && $java_name ne '') { - $viacode{$hex} = $java_name; - return $java_name; - } - } - # Return the official name, if exists. It's unclear to me (khw) at # this juncture if it is better to return a user-defined override, so # leaving it as is for now. diff --git a/src/main/perl/lib/overloading.pm b/src/main/perl/lib/overloading.pm index e78724e93d..3189434d2f 100644 --- a/src/main/perl/lib/overloading.pm +++ b/src/main/perl/lib/overloading.pm @@ -27,7 +27,6 @@ sub import ($, @ops) { delete $^H{overloading}; $^H &= ~$HINT_NO_AMAGIC; } - } sub unimport ($, @ops) { diff --git a/src/main/perl/lib/re.pm b/src/main/perl/lib/re.pm index b7a5fbd06b..03f1ea5122 100644 --- a/src/main/perl/lib/re.pm +++ b/src/main/perl/lib/re.pm @@ -12,6 +12,8 @@ our $VERSION = "0.48"; # - use re '/a', '/aa', '/u' - regex character class modifiers # - use re 'strict' - enable experimental regex warnings # - re::is_regexp($ref) - check if reference is compiled regex +# - re::regexp_pattern($ref) - return a compiled regex's source and modifiers +# - re::optimization($ref) - inspect optimization facts selected by Joni 1; diff --git a/src/main/perl/lib/unicore/Name.pl b/src/main/perl/lib/unicore/Name.pl new file mode 100644 index 0000000000..c934be8872 --- /dev/null +++ b/src/main/perl/lib/unicore/Name.pl @@ -0,0 +1,106633 @@ +# !!!!!!! DO NOT EDIT THIS FILE !!!!!!! +# This file is machine-generated by perl5/lib/unicore/mktables from the Unicode +# database, Version 17.0.0. Any changes made here will be lost! + +# !!!!!!! INTERNAL PERL USE ONLY !!!!!!! +# This file is for internal use by core Perl only. The format and even the +# name or existence of this file are subject to change without notice. Don't +# use it directly. Use Unicode::UCD to access the Unicode character data +# base. + + +return <<'END'; +00000 +NULL + +00000 +NUL + +00001 +START OF HEADING + +00001 +SOH + +00002 +START OF TEXT + +00002 +STX + +00003 +END OF TEXT + +00003 +ETX + +00004 +END OF TRANSMISSION + +00004 +EOT + +00005 +ENQUIRY + +00005 +ENQ + +00006 +ACKNOWLEDGE + +00006 +ACK + +00007 +ALERT + +00007 +BEL + +00008 +BACKSPACE + +00008 +BS + +00009 +CHARACTER TABULATION + +00009 +HORIZONTAL TABULATION + +00009 +HT + +00009 +TAB + +0000A +LINE FEED + +0000A +NEW LINE + +0000A +END OF LINE + +0000A +LINE FEED (LF) + +0000A +EOL + +0000A +LF + +0000A +NL + +0000B +LINE TABULATION + +0000B +VERTICAL TABULATION + +0000B +VT + +0000C +FORM FEED + +0000C +FORM FEED (FF) + +0000C +FF + +0000D +CARRIAGE RETURN + +0000D +CARRIAGE RETURN (CR) + +0000D +CR + +0000E +SHIFT OUT + +0000E +LOCKING-SHIFT ONE + +0000E +SO + +0000F +SHIFT IN + +0000F +LOCKING-SHIFT ZERO + +0000F +SI + +00010 +DATA LINK ESCAPE + +00010 +DLE + +00011 +DEVICE CONTROL ONE + +00011 +DC1 + +00012 +DEVICE CONTROL TWO + +00012 +DC2 + +00013 +DEVICE CONTROL THREE + +00013 +DC3 + +00014 +DEVICE CONTROL FOUR + +00014 +DC4 + +00015 +NEGATIVE ACKNOWLEDGE + +00015 +NAK + +00016 +SYNCHRONOUS IDLE + +00016 +SYN + +00017 +END OF TRANSMISSION BLOCK + +00017 +ETB + +00018 +CANCEL + +00018 +CAN + +00019 +END OF MEDIUM + +00019 +EM + +00019 +EOM + +0001A +SUBSTITUTE + +0001A +SUB + +0001B +ESCAPE + +0001B +ESC + +0001C +INFORMATION SEPARATOR FOUR + +0001C +FILE SEPARATOR + +0001C +FS + +0001D +INFORMATION SEPARATOR THREE + +0001D +GROUP SEPARATOR + +0001D +GS + +0001E +INFORMATION SEPARATOR TWO + +0001E +RECORD SEPARATOR + +0001E +RS + +0001F +INFORMATION SEPARATOR ONE + +0001F +UNIT SEPARATOR + +0001F +US + +00020 +SPACE + +00020 +SP + +00021 +EXCLAMATION MARK + +00022 +QUOTATION MARK + +00023 +NUMBER SIGN + +00024 +DOLLAR SIGN + +00025 +PERCENT SIGN + +00026 +AMPERSAND + +00027 +APOSTROPHE + +00028 +LEFT PARENTHESIS + +00029 +RIGHT PARENTHESIS + +0002A +ASTERISK + +0002B +PLUS SIGN + +0002C +COMMA + +0002D +HYPHEN-MINUS + +0002E +FULL STOP + +0002F +SOLIDUS + +00030 +DIGIT ZERO + +00031 +DIGIT ONE + +00032 +DIGIT TWO + +00033 +DIGIT THREE + +00034 +DIGIT FOUR + +00035 +DIGIT FIVE + +00036 +DIGIT SIX + +00037 +DIGIT SEVEN + +00038 +DIGIT EIGHT + +00039 +DIGIT NINE + +0003A +COLON + +0003B +SEMICOLON + +0003C +LESS-THAN SIGN + +0003D +EQUALS SIGN + +0003E +GREATER-THAN SIGN + +0003F +QUESTION MARK + +00040 +COMMERCIAL AT + +00041 +LATIN CAPITAL LETTER A + +00042 +LATIN CAPITAL LETTER B + +00043 +LATIN CAPITAL LETTER C + +00044 +LATIN CAPITAL LETTER D + +00045 +LATIN CAPITAL LETTER E + +00046 +LATIN CAPITAL LETTER F + +00047 +LATIN CAPITAL LETTER G + +00048 +LATIN CAPITAL LETTER H + +00049 +LATIN CAPITAL LETTER I + +0004A +LATIN CAPITAL LETTER J + +0004B +LATIN CAPITAL LETTER K + +0004C +LATIN CAPITAL LETTER L + +0004D +LATIN CAPITAL LETTER M + +0004E +LATIN CAPITAL LETTER N + +0004F +LATIN CAPITAL LETTER O + +00050 +LATIN CAPITAL LETTER P + +00051 +LATIN CAPITAL LETTER Q + +00052 +LATIN CAPITAL LETTER R + +00053 +LATIN CAPITAL LETTER S + +00054 +LATIN CAPITAL LETTER T + +00055 +LATIN CAPITAL LETTER U + +00056 +LATIN CAPITAL LETTER V + +00057 +LATIN CAPITAL LETTER W + +00058 +LATIN CAPITAL LETTER X + +00059 +LATIN CAPITAL LETTER Y + +0005A +LATIN CAPITAL LETTER Z + +0005B +LEFT SQUARE BRACKET + +0005C +REVERSE SOLIDUS + +0005D +RIGHT SQUARE BRACKET + +0005E +CIRCUMFLEX ACCENT + +0005F +LOW LINE + +00060 +GRAVE ACCENT + +00061 +LATIN SMALL LETTER A + +00062 +LATIN SMALL LETTER B + +00063 +LATIN SMALL LETTER C + +00064 +LATIN SMALL LETTER D + +00065 +LATIN SMALL LETTER E + +00066 +LATIN SMALL LETTER F + +00067 +LATIN SMALL LETTER G + +00068 +LATIN SMALL LETTER H + +00069 +LATIN SMALL LETTER I + +0006A +LATIN SMALL LETTER J + +0006B +LATIN SMALL LETTER K + +0006C +LATIN SMALL LETTER L + +0006D +LATIN SMALL LETTER M + +0006E +LATIN SMALL LETTER N + +0006F +LATIN SMALL LETTER O + +00070 +LATIN SMALL LETTER P + +00071 +LATIN SMALL LETTER Q + +00072 +LATIN SMALL LETTER R + +00073 +LATIN SMALL LETTER S + +00074 +LATIN SMALL LETTER T + +00075 +LATIN SMALL LETTER U + +00076 +LATIN SMALL LETTER V + +00077 +LATIN SMALL LETTER W + +00078 +LATIN SMALL LETTER X + +00079 +LATIN SMALL LETTER Y + +0007A +LATIN SMALL LETTER Z + +0007B +LEFT CURLY BRACKET + +0007C +VERTICAL LINE + +0007D +RIGHT CURLY BRACKET + +0007E +TILDE + +0007F +DELETE + +0007F +DEL + +00080 +PADDING CHARACTER + +00080 +PAD + +00081 +HIGH OCTET PRESET + +00081 +HOP + +00082 +BREAK PERMITTED HERE + +00082 +BPH + +00083 +NO BREAK HERE + +00083 +NBH + +00084 +INDEX + +00084 +IND + +00085 +NEXT LINE + +00085 +NEXT LINE (NEL) + +00085 +NEL + +00086 +START OF SELECTED AREA + +00086 +SSA + +00087 +END OF SELECTED AREA + +00087 +ESA + +00088 +CHARACTER TABULATION SET + +00088 +HORIZONTAL TABULATION SET + +00088 +HTS + +00089 +CHARACTER TABULATION WITH JUSTIFICATION + +00089 +HORIZONTAL TABULATION WITH JUSTIFICATION + +00089 +HTJ + +0008A +LINE TABULATION SET + +0008A +VERTICAL TABULATION SET + +0008A +VTS + +0008B +PARTIAL LINE FORWARD + +0008B +PARTIAL LINE DOWN + +0008B +PLD + +0008C +PARTIAL LINE BACKWARD + +0008C +PARTIAL LINE UP + +0008C +PLU + +0008D +REVERSE LINE FEED + +0008D +REVERSE INDEX + +0008D +RI + +0008E +SINGLE SHIFT TWO + +0008E +SINGLE-SHIFT-2 + +0008E +SS2 + +0008F +SINGLE SHIFT THREE + +0008F +SINGLE-SHIFT-3 + +0008F +SS3 + +00090 +DEVICE CONTROL STRING + +00090 +DCS + +00091 +PRIVATE USE ONE + +00091 +PRIVATE USE-1 + +00091 +PU1 + +00092 +PRIVATE USE TWO + +00092 +PRIVATE USE-2 + +00092 +PU2 + +00093 +SET TRANSMIT STATE + +00093 +STS + +00094 +CANCEL CHARACTER + +00094 +CCH + +00095 +MESSAGE WAITING + +00095 +MW + +00096 +START OF GUARDED AREA + +00096 +START OF PROTECTED AREA + +00096 +SPA + +00097 +END OF GUARDED AREA + +00097 +END OF PROTECTED AREA + +00097 +EPA + +00098 +START OF STRING + +00098 +SOS + +00099 +SINGLE GRAPHIC CHARACTER INTRODUCER + +00099 +SGC + +0009A +SINGLE CHARACTER INTRODUCER + +0009A +SCI + +0009B +CONTROL SEQUENCE INTRODUCER + +0009B +CSI + +0009C +STRING TERMINATOR + +0009C +ST + +0009D +OPERATING SYSTEM COMMAND + +0009D +OSC + +0009E +PRIVACY MESSAGE + +0009E +PM + +0009F +APPLICATION PROGRAM COMMAND + +0009F +APC + +000A0 +NO-BREAK SPACE + +000A0 +NBSP + +000A1 +INVERTED EXCLAMATION MARK + +000A2 +CENT SIGN + +000A3 +POUND SIGN + +000A4 +CURRENCY SIGN + +000A5 +YEN SIGN + +000A6 +BROKEN BAR + +000A7 +SECTION SIGN + +000A8 +DIAERESIS + +000A9 +COPYRIGHT SIGN + +000AA +FEMININE ORDINAL INDICATOR + +000AB +LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + +000AC +NOT SIGN + +000AD +SOFT HYPHEN + +000AD +SHY + +000AE +REGISTERED SIGN + +000AF +MACRON + +000B0 +DEGREE SIGN + +000B1 +PLUS-MINUS SIGN + +000B2 +SUPERSCRIPT TWO + +000B3 +SUPERSCRIPT THREE + +000B4 +ACUTE ACCENT + +000B5 +MICRO SIGN + +000B6 +PILCROW SIGN + +000B7 +MIDDLE DOT + +000B8 +CEDILLA + +000B9 +SUPERSCRIPT ONE + +000BA +MASCULINE ORDINAL INDICATOR + +000BB +RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + +000BC +VULGAR FRACTION ONE QUARTER + +000BD +VULGAR FRACTION ONE HALF + +000BE +VULGAR FRACTION THREE QUARTERS + +000BF +INVERTED QUESTION MARK + +000C0 +LATIN CAPITAL LETTER A WITH GRAVE + +000C1 +LATIN CAPITAL LETTER A WITH ACUTE + +000C2 +LATIN CAPITAL LETTER A WITH CIRCUMFLEX + +000C3 +LATIN CAPITAL LETTER A WITH TILDE + +000C4 +LATIN CAPITAL LETTER A WITH DIAERESIS + +000C5 +LATIN CAPITAL LETTER A WITH RING ABOVE + +000C6 +LATIN CAPITAL LETTER AE + +000C7 +LATIN CAPITAL LETTER C WITH CEDILLA + +000C8 +LATIN CAPITAL LETTER E WITH GRAVE + +000C9 +LATIN CAPITAL LETTER E WITH ACUTE + +000CA +LATIN CAPITAL LETTER E WITH CIRCUMFLEX + +000CB +LATIN CAPITAL LETTER E WITH DIAERESIS + +000CC +LATIN CAPITAL LETTER I WITH GRAVE + +000CD +LATIN CAPITAL LETTER I WITH ACUTE + +000CE +LATIN CAPITAL LETTER I WITH CIRCUMFLEX + +000CF +LATIN CAPITAL LETTER I WITH DIAERESIS + +000D0 +LATIN CAPITAL LETTER ETH + +000D1 +LATIN CAPITAL LETTER N WITH TILDE + +000D2 +LATIN CAPITAL LETTER O WITH GRAVE + +000D3 +LATIN CAPITAL LETTER O WITH ACUTE + +000D4 +LATIN CAPITAL LETTER O WITH CIRCUMFLEX + +000D5 +LATIN CAPITAL LETTER O WITH TILDE + +000D6 +LATIN CAPITAL LETTER O WITH DIAERESIS + +000D7 +MULTIPLICATION SIGN + +000D8 +LATIN CAPITAL LETTER O WITH STROKE + +000D9 +LATIN CAPITAL LETTER U WITH GRAVE + +000DA +LATIN CAPITAL LETTER U WITH ACUTE + +000DB +LATIN CAPITAL LETTER U WITH CIRCUMFLEX + +000DC +LATIN CAPITAL LETTER U WITH DIAERESIS + +000DD +LATIN CAPITAL LETTER Y WITH ACUTE + +000DE +LATIN CAPITAL LETTER THORN + +000DF +LATIN SMALL LETTER SHARP S + +000E0 +LATIN SMALL LETTER A WITH GRAVE + +000E1 +LATIN SMALL LETTER A WITH ACUTE + +000E2 +LATIN SMALL LETTER A WITH CIRCUMFLEX + +000E3 +LATIN SMALL LETTER A WITH TILDE + +000E4 +LATIN SMALL LETTER A WITH DIAERESIS + +000E5 +LATIN SMALL LETTER A WITH RING ABOVE + +000E6 +LATIN SMALL LETTER AE + +000E7 +LATIN SMALL LETTER C WITH CEDILLA + +000E8 +LATIN SMALL LETTER E WITH GRAVE + +000E9 +LATIN SMALL LETTER E WITH ACUTE + +000EA +LATIN SMALL LETTER E WITH CIRCUMFLEX + +000EB +LATIN SMALL LETTER E WITH DIAERESIS + +000EC +LATIN SMALL LETTER I WITH GRAVE + +000ED +LATIN SMALL LETTER I WITH ACUTE + +000EE +LATIN SMALL LETTER I WITH CIRCUMFLEX + +000EF +LATIN SMALL LETTER I WITH DIAERESIS + +000F0 +LATIN SMALL LETTER ETH + +000F1 +LATIN SMALL LETTER N WITH TILDE + +000F2 +LATIN SMALL LETTER O WITH GRAVE + +000F3 +LATIN SMALL LETTER O WITH ACUTE + +000F4 +LATIN SMALL LETTER O WITH CIRCUMFLEX + +000F5 +LATIN SMALL LETTER O WITH TILDE + +000F6 +LATIN SMALL LETTER O WITH DIAERESIS + +000F7 +DIVISION SIGN + +000F8 +LATIN SMALL LETTER O WITH STROKE + +000F9 +LATIN SMALL LETTER U WITH GRAVE + +000FA +LATIN SMALL LETTER U WITH ACUTE + +000FB +LATIN SMALL LETTER U WITH CIRCUMFLEX + +000FC +LATIN SMALL LETTER U WITH DIAERESIS + +000FD +LATIN SMALL LETTER Y WITH ACUTE + +000FE +LATIN SMALL LETTER THORN + +000FF +LATIN SMALL LETTER Y WITH DIAERESIS + +00100 +LATIN CAPITAL LETTER A WITH MACRON + +00101 +LATIN SMALL LETTER A WITH MACRON + +00102 +LATIN CAPITAL LETTER A WITH BREVE + +00103 +LATIN SMALL LETTER A WITH BREVE + +00104 +LATIN CAPITAL LETTER A WITH OGONEK + +00105 +LATIN SMALL LETTER A WITH OGONEK + +00106 +LATIN CAPITAL LETTER C WITH ACUTE + +00107 +LATIN SMALL LETTER C WITH ACUTE + +00108 +LATIN CAPITAL LETTER C WITH CIRCUMFLEX + +00109 +LATIN SMALL LETTER C WITH CIRCUMFLEX + +0010A +LATIN CAPITAL LETTER C WITH DOT ABOVE + +0010B +LATIN SMALL LETTER C WITH DOT ABOVE + +0010C +LATIN CAPITAL LETTER C WITH CARON + +0010D +LATIN SMALL LETTER C WITH CARON + +0010E +LATIN CAPITAL LETTER D WITH CARON + +0010F +LATIN SMALL LETTER D WITH CARON + +00110 +LATIN CAPITAL LETTER D WITH STROKE + +00111 +LATIN SMALL LETTER D WITH STROKE + +00112 +LATIN CAPITAL LETTER E WITH MACRON + +00113 +LATIN SMALL LETTER E WITH MACRON + +00114 +LATIN CAPITAL LETTER E WITH BREVE + +00115 +LATIN SMALL LETTER E WITH BREVE + +00116 +LATIN CAPITAL LETTER E WITH DOT ABOVE + +00117 +LATIN SMALL LETTER E WITH DOT ABOVE + +00118 +LATIN CAPITAL LETTER E WITH OGONEK + +00119 +LATIN SMALL LETTER E WITH OGONEK + +0011A +LATIN CAPITAL LETTER E WITH CARON + +0011B +LATIN SMALL LETTER E WITH CARON + +0011C +LATIN CAPITAL LETTER G WITH CIRCUMFLEX + +0011D +LATIN SMALL LETTER G WITH CIRCUMFLEX + +0011E +LATIN CAPITAL LETTER G WITH BREVE + +0011F +LATIN SMALL LETTER G WITH BREVE + +00120 +LATIN CAPITAL LETTER G WITH DOT ABOVE + +00121 +LATIN SMALL LETTER G WITH DOT ABOVE + +00122 +LATIN CAPITAL LETTER G WITH CEDILLA + +00123 +LATIN SMALL LETTER G WITH CEDILLA + +00124 +LATIN CAPITAL LETTER H WITH CIRCUMFLEX + +00125 +LATIN SMALL LETTER H WITH CIRCUMFLEX + +00126 +LATIN CAPITAL LETTER H WITH STROKE + +00127 +LATIN SMALL LETTER H WITH STROKE + +00128 +LATIN CAPITAL LETTER I WITH TILDE + +00129 +LATIN SMALL LETTER I WITH TILDE + +0012A +LATIN CAPITAL LETTER I WITH MACRON + +0012B +LATIN SMALL LETTER I WITH MACRON + +0012C +LATIN CAPITAL LETTER I WITH BREVE + +0012D +LATIN SMALL LETTER I WITH BREVE + +0012E +LATIN CAPITAL LETTER I WITH OGONEK + +0012F +LATIN SMALL LETTER I WITH OGONEK + +00130 +LATIN CAPITAL LETTER I WITH DOT ABOVE + +00131 +LATIN SMALL LETTER DOTLESS I + +00132 +LATIN CAPITAL LIGATURE IJ + +00133 +LATIN SMALL LIGATURE IJ + +00134 +LATIN CAPITAL LETTER J WITH CIRCUMFLEX + +00135 +LATIN SMALL LETTER J WITH CIRCUMFLEX + +00136 +LATIN CAPITAL LETTER K WITH CEDILLA + +00137 +LATIN SMALL LETTER K WITH CEDILLA + +00138 +LATIN SMALL LETTER KRA + +00139 +LATIN CAPITAL LETTER L WITH ACUTE + +0013A +LATIN SMALL LETTER L WITH ACUTE + +0013B +LATIN CAPITAL LETTER L WITH CEDILLA + +0013C +LATIN SMALL LETTER L WITH CEDILLA + +0013D +LATIN CAPITAL LETTER L WITH CARON + +0013E +LATIN SMALL LETTER L WITH CARON + +0013F +LATIN CAPITAL LETTER L WITH MIDDLE DOT + +00140 +LATIN SMALL LETTER L WITH MIDDLE DOT + +00141 +LATIN CAPITAL LETTER L WITH STROKE + +00142 +LATIN SMALL LETTER L WITH STROKE + +00143 +LATIN CAPITAL LETTER N WITH ACUTE + +00144 +LATIN SMALL LETTER N WITH ACUTE + +00145 +LATIN CAPITAL LETTER N WITH CEDILLA + +00146 +LATIN SMALL LETTER N WITH CEDILLA + +00147 +LATIN CAPITAL LETTER N WITH CARON + +00148 +LATIN SMALL LETTER N WITH CARON + +00149 +LATIN SMALL LETTER N PRECEDED BY APOSTROPHE + +0014A +LATIN CAPITAL LETTER ENG + +0014B +LATIN SMALL LETTER ENG + +0014C +LATIN CAPITAL LETTER O WITH MACRON + +0014D +LATIN SMALL LETTER O WITH MACRON + +0014E +LATIN CAPITAL LETTER O WITH BREVE + +0014F +LATIN SMALL LETTER O WITH BREVE + +00150 +LATIN CAPITAL LETTER O WITH DOUBLE ACUTE + +00151 +LATIN SMALL LETTER O WITH DOUBLE ACUTE + +00152 +LATIN CAPITAL LIGATURE OE + +00153 +LATIN SMALL LIGATURE OE + +00154 +LATIN CAPITAL LETTER R WITH ACUTE + +00155 +LATIN SMALL LETTER R WITH ACUTE + +00156 +LATIN CAPITAL LETTER R WITH CEDILLA + +00157 +LATIN SMALL LETTER R WITH CEDILLA + +00158 +LATIN CAPITAL LETTER R WITH CARON + +00159 +LATIN SMALL LETTER R WITH CARON + +0015A +LATIN CAPITAL LETTER S WITH ACUTE + +0015B +LATIN SMALL LETTER S WITH ACUTE + +0015C +LATIN CAPITAL LETTER S WITH CIRCUMFLEX + +0015D +LATIN SMALL LETTER S WITH CIRCUMFLEX + +0015E +LATIN CAPITAL LETTER S WITH CEDILLA + +0015F +LATIN SMALL LETTER S WITH CEDILLA + +00160 +LATIN CAPITAL LETTER S WITH CARON + +00161 +LATIN SMALL LETTER S WITH CARON + +00162 +LATIN CAPITAL LETTER T WITH CEDILLA + +00163 +LATIN SMALL LETTER T WITH CEDILLA + +00164 +LATIN CAPITAL LETTER T WITH CARON + +00165 +LATIN SMALL LETTER T WITH CARON + +00166 +LATIN CAPITAL LETTER T WITH STROKE + +00167 +LATIN SMALL LETTER T WITH STROKE + +00168 +LATIN CAPITAL LETTER U WITH TILDE + +00169 +LATIN SMALL LETTER U WITH TILDE + +0016A +LATIN CAPITAL LETTER U WITH MACRON + +0016B +LATIN SMALL LETTER U WITH MACRON + +0016C +LATIN CAPITAL LETTER U WITH BREVE + +0016D +LATIN SMALL LETTER U WITH BREVE + +0016E +LATIN CAPITAL LETTER U WITH RING ABOVE + +0016F +LATIN SMALL LETTER U WITH RING ABOVE + +00170 +LATIN CAPITAL LETTER U WITH DOUBLE ACUTE + +00171 +LATIN SMALL LETTER U WITH DOUBLE ACUTE + +00172 +LATIN CAPITAL LETTER U WITH OGONEK + +00173 +LATIN SMALL LETTER U WITH OGONEK + +00174 +LATIN CAPITAL LETTER W WITH CIRCUMFLEX + +00175 +LATIN SMALL LETTER W WITH CIRCUMFLEX + +00176 +LATIN CAPITAL LETTER Y WITH CIRCUMFLEX + +00177 +LATIN SMALL LETTER Y WITH CIRCUMFLEX + +00178 +LATIN CAPITAL LETTER Y WITH DIAERESIS + +00179 +LATIN CAPITAL LETTER Z WITH ACUTE + +0017A +LATIN SMALL LETTER Z WITH ACUTE + +0017B +LATIN CAPITAL LETTER Z WITH DOT ABOVE + +0017C +LATIN SMALL LETTER Z WITH DOT ABOVE + +0017D +LATIN CAPITAL LETTER Z WITH CARON + +0017E +LATIN SMALL LETTER Z WITH CARON + +0017F +LATIN SMALL LETTER LONG S + +00180 +LATIN SMALL LETTER B WITH STROKE + +00181 +LATIN CAPITAL LETTER B WITH HOOK + +00182 +LATIN CAPITAL LETTER B WITH TOPBAR + +00183 +LATIN SMALL LETTER B WITH TOPBAR + +00184 +LATIN CAPITAL LETTER TONE SIX + +00185 +LATIN SMALL LETTER TONE SIX + +00186 +LATIN CAPITAL LETTER OPEN O + +00187 +LATIN CAPITAL LETTER C WITH HOOK + +00188 +LATIN SMALL LETTER C WITH HOOK + +00189 +LATIN CAPITAL LETTER AFRICAN D + +0018A +LATIN CAPITAL LETTER D WITH HOOK + +0018B +LATIN CAPITAL LETTER D WITH TOPBAR + +0018C +LATIN SMALL LETTER D WITH TOPBAR + +0018D +LATIN SMALL LETTER TURNED DELTA + +0018E +LATIN CAPITAL LETTER REVERSED E + +0018F +LATIN CAPITAL LETTER SCHWA + +00190 +LATIN CAPITAL LETTER OPEN E + +00191 +LATIN CAPITAL LETTER F WITH HOOK + +00192 +LATIN SMALL LETTER F WITH HOOK + +00193 +LATIN CAPITAL LETTER G WITH HOOK + +00194 +LATIN CAPITAL LETTER GAMMA + +00195 +LATIN SMALL LETTER HV + +00196 +LATIN CAPITAL LETTER IOTA + +00197 +LATIN CAPITAL LETTER I WITH STROKE + +00198 +LATIN CAPITAL LETTER K WITH HOOK + +00199 +LATIN SMALL LETTER K WITH HOOK + +0019A +LATIN SMALL LETTER L WITH BAR + +0019B +LATIN SMALL LETTER LAMBDA WITH STROKE + +0019C +LATIN CAPITAL LETTER TURNED M + +0019D +LATIN CAPITAL LETTER N WITH LEFT HOOK + +0019E +LATIN SMALL LETTER N WITH LONG RIGHT LEG + +0019F +LATIN CAPITAL LETTER O WITH MIDDLE TILDE + +001A0 +LATIN CAPITAL LETTER O WITH HORN + +001A1 +LATIN SMALL LETTER O WITH HORN + +001A2 +LATIN CAPITAL LETTER GHA + +001A2 +LATIN CAPITAL LETTER OI + +001A3 +LATIN SMALL LETTER GHA + +001A3 +LATIN SMALL LETTER OI + +001A4 +LATIN CAPITAL LETTER P WITH HOOK + +001A5 +LATIN SMALL LETTER P WITH HOOK + +001A6 +LATIN LETTER YR + +001A7 +LATIN CAPITAL LETTER TONE TWO + +001A8 +LATIN SMALL LETTER TONE TWO + +001A9 +LATIN CAPITAL LETTER ESH + +001AA +LATIN LETTER REVERSED ESH LOOP + +001AB +LATIN SMALL LETTER T WITH PALATAL HOOK + +001AC +LATIN CAPITAL LETTER T WITH HOOK + +001AD +LATIN SMALL LETTER T WITH HOOK + +001AE +LATIN CAPITAL LETTER T WITH RETROFLEX HOOK + +001AF +LATIN CAPITAL LETTER U WITH HORN + +001B0 +LATIN SMALL LETTER U WITH HORN + +001B1 +LATIN CAPITAL LETTER UPSILON + +001B2 +LATIN CAPITAL LETTER V WITH HOOK + +001B3 +LATIN CAPITAL LETTER Y WITH HOOK + +001B4 +LATIN SMALL LETTER Y WITH HOOK + +001B5 +LATIN CAPITAL LETTER Z WITH STROKE + +001B6 +LATIN SMALL LETTER Z WITH STROKE + +001B7 +LATIN CAPITAL LETTER EZH + +001B8 +LATIN CAPITAL LETTER EZH REVERSED + +001B9 +LATIN SMALL LETTER EZH REVERSED + +001BA +LATIN SMALL LETTER EZH WITH TAIL + +001BB +LATIN LETTER TWO WITH STROKE + +001BC +LATIN CAPITAL LETTER TONE FIVE + +001BD +LATIN SMALL LETTER TONE FIVE + +001BE +LATIN LETTER INVERTED GLOTTAL STOP WITH STROKE + +001BF +LATIN LETTER WYNN + +001C0 +LATIN LETTER DENTAL CLICK + +001C1 +LATIN LETTER LATERAL CLICK + +001C2 +LATIN LETTER ALVEOLAR CLICK + +001C3 +LATIN LETTER RETROFLEX CLICK + +001C4 +LATIN CAPITAL LETTER DZ WITH CARON + +001C5 +LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON + +001C6 +LATIN SMALL LETTER DZ WITH CARON + +001C7 +LATIN CAPITAL LETTER LJ + +001C8 +LATIN CAPITAL LETTER L WITH SMALL LETTER J + +001C9 +LATIN SMALL LETTER LJ + +001CA +LATIN CAPITAL LETTER NJ + +001CB +LATIN CAPITAL LETTER N WITH SMALL LETTER J + +001CC +LATIN SMALL LETTER NJ + +001CD +LATIN CAPITAL LETTER A WITH CARON + +001CE +LATIN SMALL LETTER A WITH CARON + +001CF +LATIN CAPITAL LETTER I WITH CARON + +001D0 +LATIN SMALL LETTER I WITH CARON + +001D1 +LATIN CAPITAL LETTER O WITH CARON + +001D2 +LATIN SMALL LETTER O WITH CARON + +001D3 +LATIN CAPITAL LETTER U WITH CARON + +001D4 +LATIN SMALL LETTER U WITH CARON + +001D5 +LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON + +001D6 +LATIN SMALL LETTER U WITH DIAERESIS AND MACRON + +001D7 +LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE + +001D8 +LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE + +001D9 +LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON + +001DA +LATIN SMALL LETTER U WITH DIAERESIS AND CARON + +001DB +LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE + +001DC +LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE + +001DD +LATIN SMALL LETTER TURNED E + +001DE +LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON + +001DF +LATIN SMALL LETTER A WITH DIAERESIS AND MACRON + +001E0 +LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON + +001E1 +LATIN SMALL LETTER A WITH DOT ABOVE AND MACRON + +001E2 +LATIN CAPITAL LETTER AE WITH MACRON + +001E3 +LATIN SMALL LETTER AE WITH MACRON + +001E4 +LATIN CAPITAL LETTER G WITH STROKE + +001E5 +LATIN SMALL LETTER G WITH STROKE + +001E6 +LATIN CAPITAL LETTER G WITH CARON + +001E7 +LATIN SMALL LETTER G WITH CARON + +001E8 +LATIN CAPITAL LETTER K WITH CARON + +001E9 +LATIN SMALL LETTER K WITH CARON + +001EA +LATIN CAPITAL LETTER O WITH OGONEK + +001EB +LATIN SMALL LETTER O WITH OGONEK + +001EC +LATIN CAPITAL LETTER O WITH OGONEK AND MACRON + +001ED +LATIN SMALL LETTER O WITH OGONEK AND MACRON + +001EE +LATIN CAPITAL LETTER EZH WITH CARON + +001EF +LATIN SMALL LETTER EZH WITH CARON + +001F0 +LATIN SMALL LETTER J WITH CARON + +001F1 +LATIN CAPITAL LETTER DZ + +001F2 +LATIN CAPITAL LETTER D WITH SMALL LETTER Z + +001F3 +LATIN SMALL LETTER DZ + +001F4 +LATIN CAPITAL LETTER G WITH ACUTE + +001F5 +LATIN SMALL LETTER G WITH ACUTE + +001F6 +LATIN CAPITAL LETTER HWAIR + +001F7 +LATIN CAPITAL LETTER WYNN + +001F8 +LATIN CAPITAL LETTER N WITH GRAVE + +001F9 +LATIN SMALL LETTER N WITH GRAVE + +001FA +LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE + +001FB +LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE + +001FC +LATIN CAPITAL LETTER AE WITH ACUTE + +001FD +LATIN SMALL LETTER AE WITH ACUTE + +001FE +LATIN CAPITAL LETTER O WITH STROKE AND ACUTE + +001FF +LATIN SMALL LETTER O WITH STROKE AND ACUTE + +00200 +LATIN CAPITAL LETTER A WITH DOUBLE GRAVE + +00201 +LATIN SMALL LETTER A WITH DOUBLE GRAVE + +00202 +LATIN CAPITAL LETTER A WITH INVERTED BREVE + +00203 +LATIN SMALL LETTER A WITH INVERTED BREVE + +00204 +LATIN CAPITAL LETTER E WITH DOUBLE GRAVE + +00205 +LATIN SMALL LETTER E WITH DOUBLE GRAVE + +00206 +LATIN CAPITAL LETTER E WITH INVERTED BREVE + +00207 +LATIN SMALL LETTER E WITH INVERTED BREVE + +00208 +LATIN CAPITAL LETTER I WITH DOUBLE GRAVE + +00209 +LATIN SMALL LETTER I WITH DOUBLE GRAVE + +0020A +LATIN CAPITAL LETTER I WITH INVERTED BREVE + +0020B +LATIN SMALL LETTER I WITH INVERTED BREVE + +0020C +LATIN CAPITAL LETTER O WITH DOUBLE GRAVE + +0020D +LATIN SMALL LETTER O WITH DOUBLE GRAVE + +0020E +LATIN CAPITAL LETTER O WITH INVERTED BREVE + +0020F +LATIN SMALL LETTER O WITH INVERTED BREVE + +00210 +LATIN CAPITAL LETTER R WITH DOUBLE GRAVE + +00211 +LATIN SMALL LETTER R WITH DOUBLE GRAVE + +00212 +LATIN CAPITAL LETTER R WITH INVERTED BREVE + +00213 +LATIN SMALL LETTER R WITH INVERTED BREVE + +00214 +LATIN CAPITAL LETTER U WITH DOUBLE GRAVE + +00215 +LATIN SMALL LETTER U WITH DOUBLE GRAVE + +00216 +LATIN CAPITAL LETTER U WITH INVERTED BREVE + +00217 +LATIN SMALL LETTER U WITH INVERTED BREVE + +00218 +LATIN CAPITAL LETTER S WITH COMMA BELOW + +00219 +LATIN SMALL LETTER S WITH COMMA BELOW + +0021A +LATIN CAPITAL LETTER T WITH COMMA BELOW + +0021B +LATIN SMALL LETTER T WITH COMMA BELOW + +0021C +LATIN CAPITAL LETTER YOGH + +0021D +LATIN SMALL LETTER YOGH + +0021E +LATIN CAPITAL LETTER H WITH CARON + +0021F +LATIN SMALL LETTER H WITH CARON + +00220 +LATIN CAPITAL LETTER N WITH LONG RIGHT LEG + +00221 +LATIN SMALL LETTER D WITH CURL + +00222 +LATIN CAPITAL LETTER OU + +00223 +LATIN SMALL LETTER OU + +00224 +LATIN CAPITAL LETTER Z WITH HOOK + +00225 +LATIN SMALL LETTER Z WITH HOOK + +00226 +LATIN CAPITAL LETTER A WITH DOT ABOVE + +00227 +LATIN SMALL LETTER A WITH DOT ABOVE + +00228 +LATIN CAPITAL LETTER E WITH CEDILLA + +00229 +LATIN SMALL LETTER E WITH CEDILLA + +0022A +LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON + +0022B +LATIN SMALL LETTER O WITH DIAERESIS AND MACRON + +0022C +LATIN CAPITAL LETTER O WITH TILDE AND MACRON + +0022D +LATIN SMALL LETTER O WITH TILDE AND MACRON + +0022E +LATIN CAPITAL LETTER O WITH DOT ABOVE + +0022F +LATIN SMALL LETTER O WITH DOT ABOVE + +00230 +LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON + +00231 +LATIN SMALL LETTER O WITH DOT ABOVE AND MACRON + +00232 +LATIN CAPITAL LETTER Y WITH MACRON + +00233 +LATIN SMALL LETTER Y WITH MACRON + +00234 +LATIN SMALL LETTER L WITH CURL + +00235 +LATIN SMALL LETTER N WITH CURL + +00236 +LATIN SMALL LETTER T WITH CURL + +00237 +LATIN SMALL LETTER DOTLESS J + +00238 +LATIN SMALL LETTER DB DIGRAPH + +00239 +LATIN SMALL LETTER QP DIGRAPH + +0023A +LATIN CAPITAL LETTER A WITH STROKE + +0023B +LATIN CAPITAL LETTER C WITH STROKE + +0023C +LATIN SMALL LETTER C WITH STROKE + +0023D +LATIN CAPITAL LETTER L WITH BAR + +0023E +LATIN CAPITAL LETTER T WITH DIAGONAL STROKE + +0023F +LATIN SMALL LETTER S WITH SWASH TAIL + +00240 +LATIN SMALL LETTER Z WITH SWASH TAIL + +00241 +LATIN CAPITAL LETTER GLOTTAL STOP + +00242 +LATIN SMALL LETTER GLOTTAL STOP + +00243 +LATIN CAPITAL LETTER B WITH STROKE + +00244 +LATIN CAPITAL LETTER U BAR + +00245 +LATIN CAPITAL LETTER TURNED V + +00246 +LATIN CAPITAL LETTER E WITH STROKE + +00247 +LATIN SMALL LETTER E WITH STROKE + +00248 +LATIN CAPITAL LETTER J WITH STROKE + +00249 +LATIN SMALL LETTER J WITH STROKE + +0024A +LATIN CAPITAL LETTER SMALL Q WITH HOOK TAIL + +0024B +LATIN SMALL LETTER Q WITH HOOK TAIL + +0024C +LATIN CAPITAL LETTER R WITH STROKE + +0024D +LATIN SMALL LETTER R WITH STROKE + +0024E +LATIN CAPITAL LETTER Y WITH STROKE + +0024F +LATIN SMALL LETTER Y WITH STROKE + +00250 +LATIN SMALL LETTER TURNED A + +00251 +LATIN SMALL LETTER ALPHA + +00252 +LATIN SMALL LETTER TURNED ALPHA + +00253 +LATIN SMALL LETTER B WITH HOOK + +00254 +LATIN SMALL LETTER OPEN O + +00255 +LATIN SMALL LETTER C WITH CURL + +00256 +LATIN SMALL LETTER D WITH TAIL + +00257 +LATIN SMALL LETTER D WITH HOOK + +00258 +LATIN SMALL LETTER REVERSED E + +00259 +LATIN SMALL LETTER SCHWA + +0025A +LATIN SMALL LETTER SCHWA WITH HOOK + +0025B +LATIN SMALL LETTER OPEN E + +0025C +LATIN SMALL LETTER REVERSED OPEN E + +0025D +LATIN SMALL LETTER REVERSED OPEN E WITH HOOK + +0025E +LATIN SMALL LETTER CLOSED REVERSED OPEN E + +0025F +LATIN SMALL LETTER DOTLESS J WITH STROKE + +00260 +LATIN SMALL LETTER G WITH HOOK + +00261 +LATIN SMALL LETTER SCRIPT G + +00262 +LATIN LETTER SMALL CAPITAL G + +00263 +LATIN SMALL LETTER GAMMA + +00264 +LATIN SMALL LETTER RAMS HORN + +00265 +LATIN SMALL LETTER TURNED H + +00266 +LATIN SMALL LETTER H WITH HOOK + +00267 +LATIN SMALL LETTER HENG WITH HOOK + +00268 +LATIN SMALL LETTER I WITH STROKE + +00269 +LATIN SMALL LETTER IOTA + +0026A +LATIN LETTER SMALL CAPITAL I + +0026B +LATIN SMALL LETTER L WITH MIDDLE TILDE + +0026C +LATIN SMALL LETTER L WITH BELT + +0026D +LATIN SMALL LETTER L WITH RETROFLEX HOOK + +0026E +LATIN SMALL LETTER LEZH + +0026F +LATIN SMALL LETTER TURNED M + +00270 +LATIN SMALL LETTER TURNED M WITH LONG LEG + +00271 +LATIN SMALL LETTER M WITH HOOK + +00272 +LATIN SMALL LETTER N WITH LEFT HOOK + +00273 +LATIN SMALL LETTER N WITH RETROFLEX HOOK + +00274 +LATIN LETTER SMALL CAPITAL N + +00275 +LATIN SMALL LETTER BARRED O + +00276 +LATIN LETTER SMALL CAPITAL OE + +00277 +LATIN SMALL LETTER CLOSED OMEGA + +00278 +LATIN SMALL LETTER PHI + +00279 +LATIN SMALL LETTER TURNED R + +0027A +LATIN SMALL LETTER TURNED R WITH LONG LEG + +0027B +LATIN SMALL LETTER TURNED R WITH HOOK + +0027C +LATIN SMALL LETTER R WITH LONG LEG + +0027D +LATIN SMALL LETTER R WITH TAIL + +0027E +LATIN SMALL LETTER R WITH FISHHOOK + +0027F +LATIN SMALL LETTER REVERSED R WITH FISHHOOK + +00280 +LATIN LETTER SMALL CAPITAL R + +00281 +LATIN LETTER SMALL CAPITAL INVERTED R + +00282 +LATIN SMALL LETTER S WITH HOOK + +00283 +LATIN SMALL LETTER ESH + +00284 +LATIN SMALL LETTER DOTLESS J WITH STROKE AND HOOK + +00285 +LATIN SMALL LETTER SQUAT REVERSED ESH + +00286 +LATIN SMALL LETTER ESH WITH CURL + +00287 +LATIN SMALL LETTER TURNED T + +00288 +LATIN SMALL LETTER T WITH RETROFLEX HOOK + +00289 +LATIN SMALL LETTER U BAR + +0028A +LATIN SMALL LETTER UPSILON + +0028B +LATIN SMALL LETTER V WITH HOOK + +0028C +LATIN SMALL LETTER TURNED V + +0028D +LATIN SMALL LETTER TURNED W + +0028E +LATIN SMALL LETTER TURNED Y + +0028F +LATIN LETTER SMALL CAPITAL Y + +00290 +LATIN SMALL LETTER Z WITH RETROFLEX HOOK + +00291 +LATIN SMALL LETTER Z WITH CURL + +00292 +LATIN SMALL LETTER EZH + +00293 +LATIN SMALL LETTER EZH WITH CURL + +00294 +LATIN LETTER GLOTTAL STOP + +00295 +LATIN LETTER PHARYNGEAL VOICED FRICATIVE + +00296 +LATIN LETTER INVERTED GLOTTAL STOP + +00297 +LATIN LETTER STRETCHED C + +00298 +LATIN LETTER BILABIAL CLICK + +00299 +LATIN LETTER SMALL CAPITAL B + +0029A +LATIN SMALL LETTER CLOSED OPEN E + +0029B +LATIN LETTER SMALL CAPITAL G WITH HOOK + +0029C +LATIN LETTER SMALL CAPITAL H + +0029D +LATIN SMALL LETTER J WITH CROSSED-TAIL + +0029E +LATIN SMALL LETTER TURNED K + +0029F +LATIN LETTER SMALL CAPITAL L + +002A0 +LATIN SMALL LETTER Q WITH HOOK + +002A1 +LATIN LETTER GLOTTAL STOP WITH STROKE + +002A2 +LATIN LETTER REVERSED GLOTTAL STOP WITH STROKE + +002A3 +LATIN SMALL LETTER DZ DIGRAPH + +002A4 +LATIN SMALL LETTER DEZH DIGRAPH + +002A5 +LATIN SMALL LETTER DZ DIGRAPH WITH CURL + +002A6 +LATIN SMALL LETTER TS DIGRAPH + +002A7 +LATIN SMALL LETTER TESH DIGRAPH + +002A8 +LATIN SMALL LETTER TC DIGRAPH WITH CURL + +002A9 +LATIN SMALL LETTER FENG DIGRAPH + +002AA +LATIN SMALL LETTER LS DIGRAPH + +002AB +LATIN SMALL LETTER LZ DIGRAPH + +002AC +LATIN LETTER BILABIAL PERCUSSIVE + +002AD +LATIN LETTER BIDENTAL PERCUSSIVE + +002AE +LATIN SMALL LETTER TURNED H WITH FISHHOOK + +002AF +LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL + +002B0 +MODIFIER LETTER SMALL H + +002B1 +MODIFIER LETTER SMALL H WITH HOOK + +002B2 +MODIFIER LETTER SMALL J + +002B3 +MODIFIER LETTER SMALL R + +002B4 +MODIFIER LETTER SMALL TURNED R + +002B5 +MODIFIER LETTER SMALL TURNED R WITH HOOK + +002B6 +MODIFIER LETTER SMALL CAPITAL INVERTED R + +002B7 +MODIFIER LETTER SMALL W + +002B8 +MODIFIER LETTER SMALL Y + +002B9 +MODIFIER LETTER PRIME + +002BA +MODIFIER LETTER DOUBLE PRIME + +002BB +MODIFIER LETTER TURNED COMMA + +002BC +MODIFIER LETTER APOSTROPHE + +002BD +MODIFIER LETTER REVERSED COMMA + +002BE +MODIFIER LETTER RIGHT HALF RING + +002BF +MODIFIER LETTER LEFT HALF RING + +002C0 +MODIFIER LETTER GLOTTAL STOP + +002C1 +MODIFIER LETTER REVERSED GLOTTAL STOP + +002C2 +MODIFIER LETTER LEFT ARROWHEAD + +002C3 +MODIFIER LETTER RIGHT ARROWHEAD + +002C4 +MODIFIER LETTER UP ARROWHEAD + +002C5 +MODIFIER LETTER DOWN ARROWHEAD + +002C6 +MODIFIER LETTER CIRCUMFLEX ACCENT + +002C7 +CARON + +002C8 +MODIFIER LETTER VERTICAL LINE + +002C9 +MODIFIER LETTER MACRON + +002CA +MODIFIER LETTER ACUTE ACCENT + +002CB +MODIFIER LETTER GRAVE ACCENT + +002CC +MODIFIER LETTER LOW VERTICAL LINE + +002CD +MODIFIER LETTER LOW MACRON + +002CE +MODIFIER LETTER LOW GRAVE ACCENT + +002CF +MODIFIER LETTER LOW ACUTE ACCENT + +002D0 +MODIFIER LETTER TRIANGULAR COLON + +002D1 +MODIFIER LETTER HALF TRIANGULAR COLON + +002D2 +MODIFIER LETTER CENTRED RIGHT HALF RING + +002D3 +MODIFIER LETTER CENTRED LEFT HALF RING + +002D4 +MODIFIER LETTER UP TACK + +002D5 +MODIFIER LETTER DOWN TACK + +002D6 +MODIFIER LETTER PLUS SIGN + +002D7 +MODIFIER LETTER MINUS SIGN + +002D8 +BREVE + +002D9 +DOT ABOVE + +002DA +RING ABOVE + +002DB +OGONEK + +002DC +SMALL TILDE + +002DD +DOUBLE ACUTE ACCENT + +002DE +MODIFIER LETTER RHOTIC HOOK + +002DF +MODIFIER LETTER CROSS ACCENT + +002E0 +MODIFIER LETTER SMALL GAMMA + +002E1 +MODIFIER LETTER SMALL L + +002E2 +MODIFIER LETTER SMALL S + +002E3 +MODIFIER LETTER SMALL X + +002E4 +MODIFIER LETTER SMALL REVERSED GLOTTAL STOP + +002E5 +MODIFIER LETTER EXTRA-HIGH TONE BAR + +002E6 +MODIFIER LETTER HIGH TONE BAR + +002E7 +MODIFIER LETTER MID TONE BAR + +002E8 +MODIFIER LETTER LOW TONE BAR + +002E9 +MODIFIER LETTER EXTRA-LOW TONE BAR + +002EA +MODIFIER LETTER YIN DEPARTING TONE MARK + +002EB +MODIFIER LETTER YANG DEPARTING TONE MARK + +002EC +MODIFIER LETTER VOICING + +002ED +MODIFIER LETTER UNASPIRATED + +002EE +MODIFIER LETTER DOUBLE APOSTROPHE + +002EF +MODIFIER LETTER LOW DOWN ARROWHEAD + +002F0 +MODIFIER LETTER LOW UP ARROWHEAD + +002F1 +MODIFIER LETTER LOW LEFT ARROWHEAD + +002F2 +MODIFIER LETTER LOW RIGHT ARROWHEAD + +002F3 +MODIFIER LETTER LOW RING + +002F4 +MODIFIER LETTER MIDDLE GRAVE ACCENT + +002F5 +MODIFIER LETTER MIDDLE DOUBLE GRAVE ACCENT + +002F6 +MODIFIER LETTER MIDDLE DOUBLE ACUTE ACCENT + +002F7 +MODIFIER LETTER LOW TILDE + +002F8 +MODIFIER LETTER RAISED COLON + +002F9 +MODIFIER LETTER BEGIN HIGH TONE + +002FA +MODIFIER LETTER END HIGH TONE + +002FB +MODIFIER LETTER BEGIN LOW TONE + +002FC +MODIFIER LETTER END LOW TONE + +002FD +MODIFIER LETTER SHELF + +002FE +MODIFIER LETTER OPEN SHELF + +002FF +MODIFIER LETTER LOW LEFT ARROW + +00300 +COMBINING GRAVE ACCENT + +00301 +COMBINING ACUTE ACCENT + +00302 +COMBINING CIRCUMFLEX ACCENT + +00303 +COMBINING TILDE + +00304 +COMBINING MACRON + +00305 +COMBINING OVERLINE + +00306 +COMBINING BREVE + +00307 +COMBINING DOT ABOVE + +00308 +COMBINING DIAERESIS + +00309 +COMBINING HOOK ABOVE + +0030A +COMBINING RING ABOVE + +0030B +COMBINING DOUBLE ACUTE ACCENT + +0030C +COMBINING CARON + +0030D +COMBINING VERTICAL LINE ABOVE + +0030E +COMBINING DOUBLE VERTICAL LINE ABOVE + +0030F +COMBINING DOUBLE GRAVE ACCENT + +00310 +COMBINING CANDRABINDU + +00311 +COMBINING INVERTED BREVE + +00312 +COMBINING TURNED COMMA ABOVE + +00313 +COMBINING COMMA ABOVE + +00314 +COMBINING REVERSED COMMA ABOVE + +00315 +COMBINING COMMA ABOVE RIGHT + +00316 +COMBINING GRAVE ACCENT BELOW + +00317 +COMBINING ACUTE ACCENT BELOW + +00318 +COMBINING LEFT TACK BELOW + +00319 +COMBINING RIGHT TACK BELOW + +0031A +COMBINING LEFT ANGLE ABOVE + +0031B +COMBINING HORN + +0031C +COMBINING LEFT HALF RING BELOW + +0031D +COMBINING UP TACK BELOW + +0031E +COMBINING DOWN TACK BELOW + +0031F +COMBINING PLUS SIGN BELOW + +00320 +COMBINING MINUS SIGN BELOW + +00321 +COMBINING PALATALIZED HOOK BELOW + +00322 +COMBINING RETROFLEX HOOK BELOW + +00323 +COMBINING DOT BELOW + +00324 +COMBINING DIAERESIS BELOW + +00325 +COMBINING RING BELOW + +00326 +COMBINING COMMA BELOW + +00327 +COMBINING CEDILLA + +00328 +COMBINING OGONEK + +00329 +COMBINING VERTICAL LINE BELOW + +0032A +COMBINING BRIDGE BELOW + +0032B +COMBINING INVERTED DOUBLE ARCH BELOW + +0032C +COMBINING CARON BELOW + +0032D +COMBINING CIRCUMFLEX ACCENT BELOW + +0032E +COMBINING BREVE BELOW + +0032F +COMBINING INVERTED BREVE BELOW + +00330 +COMBINING TILDE BELOW + +00331 +COMBINING MACRON BELOW + +00332 +COMBINING LOW LINE + +00333 +COMBINING DOUBLE LOW LINE + +00334 +COMBINING TILDE OVERLAY + +00335 +COMBINING SHORT STROKE OVERLAY + +00336 +COMBINING LONG STROKE OVERLAY + +00337 +COMBINING SHORT SOLIDUS OVERLAY + +00338 +COMBINING LONG SOLIDUS OVERLAY + +00339 +COMBINING RIGHT HALF RING BELOW + +0033A +COMBINING INVERTED BRIDGE BELOW + +0033B +COMBINING SQUARE BELOW + +0033C +COMBINING SEAGULL BELOW + +0033D +COMBINING X ABOVE + +0033E +COMBINING VERTICAL TILDE + +0033F +COMBINING DOUBLE OVERLINE + +00340 +COMBINING GRAVE TONE MARK + +00341 +COMBINING ACUTE TONE MARK + +00342 +COMBINING GREEK PERISPOMENI + +00343 +COMBINING GREEK KORONIS + +00344 +COMBINING GREEK DIALYTIKA TONOS + +00345 +COMBINING GREEK YPOGEGRAMMENI + +00346 +COMBINING BRIDGE ABOVE + +00347 +COMBINING EQUALS SIGN BELOW + +00348 +COMBINING DOUBLE VERTICAL LINE BELOW + +00349 +COMBINING LEFT ANGLE BELOW + +0034A +COMBINING NOT TILDE ABOVE + +0034B +COMBINING HOMOTHETIC ABOVE + +0034C +COMBINING ALMOST EQUAL TO ABOVE + +0034D +COMBINING LEFT RIGHT ARROW BELOW + +0034E +COMBINING UPWARDS ARROW BELOW + +0034F +COMBINING GRAPHEME JOINER + +0034F +CGJ + +00350 +COMBINING RIGHT ARROWHEAD ABOVE + +00351 +COMBINING LEFT HALF RING ABOVE + +00352 +COMBINING FERMATA + +00353 +COMBINING X BELOW + +00354 +COMBINING LEFT ARROWHEAD BELOW + +00355 +COMBINING RIGHT ARROWHEAD BELOW + +00356 +COMBINING RIGHT ARROWHEAD AND UP ARROWHEAD BELOW + +00357 +COMBINING RIGHT HALF RING ABOVE + +00358 +COMBINING DOT ABOVE RIGHT + +00359 +COMBINING ASTERISK BELOW + +0035A +COMBINING DOUBLE RING BELOW + +0035B +COMBINING ZIGZAG ABOVE + +0035C +COMBINING DOUBLE BREVE BELOW + +0035D +COMBINING DOUBLE BREVE + +0035E +COMBINING DOUBLE MACRON + +0035F +COMBINING DOUBLE MACRON BELOW + +00360 +COMBINING DOUBLE TILDE + +00361 +COMBINING DOUBLE INVERTED BREVE + +00362 +COMBINING DOUBLE RIGHTWARDS ARROW BELOW + +00363 +COMBINING LATIN SMALL LETTER A + +00364 +COMBINING LATIN SMALL LETTER E + +00365 +COMBINING LATIN SMALL LETTER I + +00366 +COMBINING LATIN SMALL LETTER O + +00367 +COMBINING LATIN SMALL LETTER U + +00368 +COMBINING LATIN SMALL LETTER C + +00369 +COMBINING LATIN SMALL LETTER D + +0036A +COMBINING LATIN SMALL LETTER H + +0036B +COMBINING LATIN SMALL LETTER M + +0036C +COMBINING LATIN SMALL LETTER R + +0036D +COMBINING LATIN SMALL LETTER T + +0036E +COMBINING LATIN SMALL LETTER V + +0036F +COMBINING LATIN SMALL LETTER X + +00370 +GREEK CAPITAL LETTER HETA + +00371 +GREEK SMALL LETTER HETA + +00372 +GREEK CAPITAL LETTER ARCHAIC SAMPI + +00373 +GREEK SMALL LETTER ARCHAIC SAMPI + +00374 +GREEK NUMERAL SIGN + +00375 +GREEK LOWER NUMERAL SIGN + +00376 +GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA + +00377 +GREEK SMALL LETTER PAMPHYLIAN DIGAMMA + +0037A +GREEK YPOGEGRAMMENI + +0037B +GREEK SMALL REVERSED LUNATE SIGMA SYMBOL + +0037C +GREEK SMALL DOTTED LUNATE SIGMA SYMBOL + +0037D +GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL + +0037E +GREEK QUESTION MARK + +0037F +GREEK CAPITAL LETTER YOT + +00384 +GREEK TONOS + +00385 +GREEK DIALYTIKA TONOS + +00386 +GREEK CAPITAL LETTER ALPHA WITH TONOS + +00387 +GREEK ANO TELEIA + +00388 +GREEK CAPITAL LETTER EPSILON WITH TONOS + +00389 +GREEK CAPITAL LETTER ETA WITH TONOS + +0038A +GREEK CAPITAL LETTER IOTA WITH TONOS + +0038C +GREEK CAPITAL LETTER OMICRON WITH TONOS + +0038E +GREEK CAPITAL LETTER UPSILON WITH TONOS + +0038F +GREEK CAPITAL LETTER OMEGA WITH TONOS + +00390 +GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS + +00391 +GREEK CAPITAL LETTER ALPHA + +00392 +GREEK CAPITAL LETTER BETA + +00393 +GREEK CAPITAL LETTER GAMMA + +00394 +GREEK CAPITAL LETTER DELTA + +00395 +GREEK CAPITAL LETTER EPSILON + +00396 +GREEK CAPITAL LETTER ZETA + +00397 +GREEK CAPITAL LETTER ETA + +00398 +GREEK CAPITAL LETTER THETA + +00399 +GREEK CAPITAL LETTER IOTA + +0039A +GREEK CAPITAL LETTER KAPPA + +0039B +GREEK CAPITAL LETTER LAMDA + +0039C +GREEK CAPITAL LETTER MU + +0039D +GREEK CAPITAL LETTER NU + +0039E +GREEK CAPITAL LETTER XI + +0039F +GREEK CAPITAL LETTER OMICRON + +003A0 +GREEK CAPITAL LETTER PI + +003A1 +GREEK CAPITAL LETTER RHO + +003A3 +GREEK CAPITAL LETTER SIGMA + +003A4 +GREEK CAPITAL LETTER TAU + +003A5 +GREEK CAPITAL LETTER UPSILON + +003A6 +GREEK CAPITAL LETTER PHI + +003A7 +GREEK CAPITAL LETTER CHI + +003A8 +GREEK CAPITAL LETTER PSI + +003A9 +GREEK CAPITAL LETTER OMEGA + +003AA +GREEK CAPITAL LETTER IOTA WITH DIALYTIKA + +003AB +GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA + +003AC +GREEK SMALL LETTER ALPHA WITH TONOS + +003AD +GREEK SMALL LETTER EPSILON WITH TONOS + +003AE +GREEK SMALL LETTER ETA WITH TONOS + +003AF +GREEK SMALL LETTER IOTA WITH TONOS + +003B0 +GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS + +003B1 +GREEK SMALL LETTER ALPHA + +003B2 +GREEK SMALL LETTER BETA + +003B3 +GREEK SMALL LETTER GAMMA + +003B4 +GREEK SMALL LETTER DELTA + +003B5 +GREEK SMALL LETTER EPSILON + +003B6 +GREEK SMALL LETTER ZETA + +003B7 +GREEK SMALL LETTER ETA + +003B8 +GREEK SMALL LETTER THETA + +003B9 +GREEK SMALL LETTER IOTA + +003BA +GREEK SMALL LETTER KAPPA + +003BB +GREEK SMALL LETTER LAMDA + +003BC +GREEK SMALL LETTER MU + +003BD +GREEK SMALL LETTER NU + +003BE +GREEK SMALL LETTER XI + +003BF +GREEK SMALL LETTER OMICRON + +003C0 +GREEK SMALL LETTER PI + +003C1 +GREEK SMALL LETTER RHO + +003C2 +GREEK SMALL LETTER FINAL SIGMA + +003C3 +GREEK SMALL LETTER SIGMA + +003C4 +GREEK SMALL LETTER TAU + +003C5 +GREEK SMALL LETTER UPSILON + +003C6 +GREEK SMALL LETTER PHI + +003C7 +GREEK SMALL LETTER CHI + +003C8 +GREEK SMALL LETTER PSI + +003C9 +GREEK SMALL LETTER OMEGA + +003CA +GREEK SMALL LETTER IOTA WITH DIALYTIKA + +003CB +GREEK SMALL LETTER UPSILON WITH DIALYTIKA + +003CC +GREEK SMALL LETTER OMICRON WITH TONOS + +003CD +GREEK SMALL LETTER UPSILON WITH TONOS + +003CE +GREEK SMALL LETTER OMEGA WITH TONOS + +003CF +GREEK CAPITAL KAI SYMBOL + +003D0 +GREEK BETA SYMBOL + +003D1 +GREEK THETA SYMBOL + +003D2 +GREEK UPSILON WITH HOOK SYMBOL + +003D3 +GREEK UPSILON WITH ACUTE AND HOOK SYMBOL + +003D4 +GREEK UPSILON WITH DIAERESIS AND HOOK SYMBOL + +003D5 +GREEK PHI SYMBOL + +003D6 +GREEK PI SYMBOL + +003D7 +GREEK KAI SYMBOL + +003D8 +GREEK LETTER ARCHAIC KOPPA + +003D9 +GREEK SMALL LETTER ARCHAIC KOPPA + +003DA +GREEK LETTER STIGMA + +003DB +GREEK SMALL LETTER STIGMA + +003DC +GREEK LETTER DIGAMMA + +003DD +GREEK SMALL LETTER DIGAMMA + +003DE +GREEK LETTER KOPPA + +003DF +GREEK SMALL LETTER KOPPA + +003E0 +GREEK LETTER SAMPI + +003E1 +GREEK SMALL LETTER SAMPI + +003E2 +COPTIC CAPITAL LETTER SHEI + +003E3 +COPTIC SMALL LETTER SHEI + +003E4 +COPTIC CAPITAL LETTER FEI + +003E5 +COPTIC SMALL LETTER FEI + +003E6 +COPTIC CAPITAL LETTER KHEI + +003E7 +COPTIC SMALL LETTER KHEI + +003E8 +COPTIC CAPITAL LETTER HORI + +003E9 +COPTIC SMALL LETTER HORI + +003EA +COPTIC CAPITAL LETTER GANGIA + +003EB +COPTIC SMALL LETTER GANGIA + +003EC +COPTIC CAPITAL LETTER SHIMA + +003ED +COPTIC SMALL LETTER SHIMA + +003EE +COPTIC CAPITAL LETTER DEI + +003EF +COPTIC SMALL LETTER DEI + +003F0 +GREEK KAPPA SYMBOL + +003F1 +GREEK RHO SYMBOL + +003F2 +GREEK LUNATE SIGMA SYMBOL + +003F3 +GREEK LETTER YOT + +003F4 +GREEK CAPITAL THETA SYMBOL + +003F5 +GREEK LUNATE EPSILON SYMBOL + +003F6 +GREEK REVERSED LUNATE EPSILON SYMBOL + +003F7 +GREEK CAPITAL LETTER SHO + +003F8 +GREEK SMALL LETTER SHO + +003F9 +GREEK CAPITAL LUNATE SIGMA SYMBOL + +003FA +GREEK CAPITAL LETTER SAN + +003FB +GREEK SMALL LETTER SAN + +003FC +GREEK RHO WITH STROKE SYMBOL + +003FD +GREEK CAPITAL REVERSED LUNATE SIGMA SYMBOL + +003FE +GREEK CAPITAL DOTTED LUNATE SIGMA SYMBOL + +003FF +GREEK CAPITAL REVERSED DOTTED LUNATE SIGMA SYMBOL + +00400 +CYRILLIC CAPITAL LETTER IE WITH GRAVE + +00401 +CYRILLIC CAPITAL LETTER IO + +00402 +CYRILLIC CAPITAL LETTER DJE + +00403 +CYRILLIC CAPITAL LETTER GJE + +00404 +CYRILLIC CAPITAL LETTER UKRAINIAN IE + +00405 +CYRILLIC CAPITAL LETTER DZE + +00406 +CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I + +00407 +CYRILLIC CAPITAL LETTER YI + +00408 +CYRILLIC CAPITAL LETTER JE + +00409 +CYRILLIC CAPITAL LETTER LJE + +0040A +CYRILLIC CAPITAL LETTER NJE + +0040B +CYRILLIC CAPITAL LETTER TSHE + +0040C +CYRILLIC CAPITAL LETTER KJE + +0040D +CYRILLIC CAPITAL LETTER I WITH GRAVE + +0040E +CYRILLIC CAPITAL LETTER SHORT U + +0040F +CYRILLIC CAPITAL LETTER DZHE + +00410 +CYRILLIC CAPITAL LETTER A + +00411 +CYRILLIC CAPITAL LETTER BE + +00412 +CYRILLIC CAPITAL LETTER VE + +00413 +CYRILLIC CAPITAL LETTER GHE + +00414 +CYRILLIC CAPITAL LETTER DE + +00415 +CYRILLIC CAPITAL LETTER IE + +00416 +CYRILLIC CAPITAL LETTER ZHE + +00417 +CYRILLIC CAPITAL LETTER ZE + +00418 +CYRILLIC CAPITAL LETTER I + +00419 +CYRILLIC CAPITAL LETTER SHORT I + +0041A +CYRILLIC CAPITAL LETTER KA + +0041B +CYRILLIC CAPITAL LETTER EL + +0041C +CYRILLIC CAPITAL LETTER EM + +0041D +CYRILLIC CAPITAL LETTER EN + +0041E +CYRILLIC CAPITAL LETTER O + +0041F +CYRILLIC CAPITAL LETTER PE + +00420 +CYRILLIC CAPITAL LETTER ER + +00421 +CYRILLIC CAPITAL LETTER ES + +00422 +CYRILLIC CAPITAL LETTER TE + +00423 +CYRILLIC CAPITAL LETTER U + +00424 +CYRILLIC CAPITAL LETTER EF + +00425 +CYRILLIC CAPITAL LETTER HA + +00426 +CYRILLIC CAPITAL LETTER TSE + +00427 +CYRILLIC CAPITAL LETTER CHE + +00428 +CYRILLIC CAPITAL LETTER SHA + +00429 +CYRILLIC CAPITAL LETTER SHCHA + +0042A +CYRILLIC CAPITAL LETTER HARD SIGN + +0042B +CYRILLIC CAPITAL LETTER YERU + +0042C +CYRILLIC CAPITAL LETTER SOFT SIGN + +0042D +CYRILLIC CAPITAL LETTER E + +0042E +CYRILLIC CAPITAL LETTER YU + +0042F +CYRILLIC CAPITAL LETTER YA + +00430 +CYRILLIC SMALL LETTER A + +00431 +CYRILLIC SMALL LETTER BE + +00432 +CYRILLIC SMALL LETTER VE + +00433 +CYRILLIC SMALL LETTER GHE + +00434 +CYRILLIC SMALL LETTER DE + +00435 +CYRILLIC SMALL LETTER IE + +00436 +CYRILLIC SMALL LETTER ZHE + +00437 +CYRILLIC SMALL LETTER ZE + +00438 +CYRILLIC SMALL LETTER I + +00439 +CYRILLIC SMALL LETTER SHORT I + +0043A +CYRILLIC SMALL LETTER KA + +0043B +CYRILLIC SMALL LETTER EL + +0043C +CYRILLIC SMALL LETTER EM + +0043D +CYRILLIC SMALL LETTER EN + +0043E +CYRILLIC SMALL LETTER O + +0043F +CYRILLIC SMALL LETTER PE + +00440 +CYRILLIC SMALL LETTER ER + +00441 +CYRILLIC SMALL LETTER ES + +00442 +CYRILLIC SMALL LETTER TE + +00443 +CYRILLIC SMALL LETTER U + +00444 +CYRILLIC SMALL LETTER EF + +00445 +CYRILLIC SMALL LETTER HA + +00446 +CYRILLIC SMALL LETTER TSE + +00447 +CYRILLIC SMALL LETTER CHE + +00448 +CYRILLIC SMALL LETTER SHA + +00449 +CYRILLIC SMALL LETTER SHCHA + +0044A +CYRILLIC SMALL LETTER HARD SIGN + +0044B +CYRILLIC SMALL LETTER YERU + +0044C +CYRILLIC SMALL LETTER SOFT SIGN + +0044D +CYRILLIC SMALL LETTER E + +0044E +CYRILLIC SMALL LETTER YU + +0044F +CYRILLIC SMALL LETTER YA + +00450 +CYRILLIC SMALL LETTER IE WITH GRAVE + +00451 +CYRILLIC SMALL LETTER IO + +00452 +CYRILLIC SMALL LETTER DJE + +00453 +CYRILLIC SMALL LETTER GJE + +00454 +CYRILLIC SMALL LETTER UKRAINIAN IE + +00455 +CYRILLIC SMALL LETTER DZE + +00456 +CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I + +00457 +CYRILLIC SMALL LETTER YI + +00458 +CYRILLIC SMALL LETTER JE + +00459 +CYRILLIC SMALL LETTER LJE + +0045A +CYRILLIC SMALL LETTER NJE + +0045B +CYRILLIC SMALL LETTER TSHE + +0045C +CYRILLIC SMALL LETTER KJE + +0045D +CYRILLIC SMALL LETTER I WITH GRAVE + +0045E +CYRILLIC SMALL LETTER SHORT U + +0045F +CYRILLIC SMALL LETTER DZHE + +00460 +CYRILLIC CAPITAL LETTER OMEGA + +00461 +CYRILLIC SMALL LETTER OMEGA + +00462 +CYRILLIC CAPITAL LETTER YAT + +00463 +CYRILLIC SMALL LETTER YAT + +00464 +CYRILLIC CAPITAL LETTER IOTIFIED E + +00465 +CYRILLIC SMALL LETTER IOTIFIED E + +00466 +CYRILLIC CAPITAL LETTER LITTLE YUS + +00467 +CYRILLIC SMALL LETTER LITTLE YUS + +00468 +CYRILLIC CAPITAL LETTER IOTIFIED LITTLE YUS + +00469 +CYRILLIC SMALL LETTER IOTIFIED LITTLE YUS + +0046A +CYRILLIC CAPITAL LETTER BIG YUS + +0046B +CYRILLIC SMALL LETTER BIG YUS + +0046C +CYRILLIC CAPITAL LETTER IOTIFIED BIG YUS + +0046D +CYRILLIC SMALL LETTER IOTIFIED BIG YUS + +0046E +CYRILLIC CAPITAL LETTER KSI + +0046F +CYRILLIC SMALL LETTER KSI + +00470 +CYRILLIC CAPITAL LETTER PSI + +00471 +CYRILLIC SMALL LETTER PSI + +00472 +CYRILLIC CAPITAL LETTER FITA + +00473 +CYRILLIC SMALL LETTER FITA + +00474 +CYRILLIC CAPITAL LETTER IZHITSA + +00475 +CYRILLIC SMALL LETTER IZHITSA + +00476 +CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT + +00477 +CYRILLIC SMALL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT + +00478 +CYRILLIC CAPITAL LETTER UK + +00479 +CYRILLIC SMALL LETTER UK + +0047A +CYRILLIC CAPITAL LETTER ROUND OMEGA + +0047B +CYRILLIC SMALL LETTER ROUND OMEGA + +0047C +CYRILLIC CAPITAL LETTER OMEGA WITH TITLO + +0047D +CYRILLIC SMALL LETTER OMEGA WITH TITLO + +0047E +CYRILLIC CAPITAL LETTER OT + +0047F +CYRILLIC SMALL LETTER OT + +00480 +CYRILLIC CAPITAL LETTER KOPPA + +00481 +CYRILLIC SMALL LETTER KOPPA + +00482 +CYRILLIC THOUSANDS SIGN + +00483 +COMBINING CYRILLIC TITLO + +00484 +COMBINING CYRILLIC PALATALIZATION + +00485 +COMBINING CYRILLIC DASIA PNEUMATA + +00486 +COMBINING CYRILLIC PSILI PNEUMATA + +00487 +COMBINING CYRILLIC POKRYTIE + +00488 +COMBINING CYRILLIC HUNDRED THOUSANDS SIGN + +00489 +COMBINING CYRILLIC MILLIONS SIGN + +0048A +CYRILLIC CAPITAL LETTER SHORT I WITH TAIL + +0048B +CYRILLIC SMALL LETTER SHORT I WITH TAIL + +0048C +CYRILLIC CAPITAL LETTER SEMISOFT SIGN + +0048D +CYRILLIC SMALL LETTER SEMISOFT SIGN + +0048E +CYRILLIC CAPITAL LETTER ER WITH TICK + +0048F +CYRILLIC SMALL LETTER ER WITH TICK + +00490 +CYRILLIC CAPITAL LETTER GHE WITH UPTURN + +00491 +CYRILLIC SMALL LETTER GHE WITH UPTURN + +00492 +CYRILLIC CAPITAL LETTER GHE WITH STROKE + +00493 +CYRILLIC SMALL LETTER GHE WITH STROKE + +00494 +CYRILLIC CAPITAL LETTER GHE WITH MIDDLE HOOK + +00495 +CYRILLIC SMALL LETTER GHE WITH MIDDLE HOOK + +00496 +CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER + +00497 +CYRILLIC SMALL LETTER ZHE WITH DESCENDER + +00498 +CYRILLIC CAPITAL LETTER ZE WITH DESCENDER + +00499 +CYRILLIC SMALL LETTER ZE WITH DESCENDER + +0049A +CYRILLIC CAPITAL LETTER KA WITH DESCENDER + +0049B +CYRILLIC SMALL LETTER KA WITH DESCENDER + +0049C +CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE + +0049D +CYRILLIC SMALL LETTER KA WITH VERTICAL STROKE + +0049E +CYRILLIC CAPITAL LETTER KA WITH STROKE + +0049F +CYRILLIC SMALL LETTER KA WITH STROKE + +004A0 +CYRILLIC CAPITAL LETTER BASHKIR KA + +004A1 +CYRILLIC SMALL LETTER BASHKIR KA + +004A2 +CYRILLIC CAPITAL LETTER EN WITH DESCENDER + +004A3 +CYRILLIC SMALL LETTER EN WITH DESCENDER + +004A4 +CYRILLIC CAPITAL LIGATURE EN GHE + +004A5 +CYRILLIC SMALL LIGATURE EN GHE + +004A6 +CYRILLIC CAPITAL LETTER PE WITH MIDDLE HOOK + +004A7 +CYRILLIC SMALL LETTER PE WITH MIDDLE HOOK + +004A8 +CYRILLIC CAPITAL LETTER ABKHASIAN HA + +004A9 +CYRILLIC SMALL LETTER ABKHASIAN HA + +004AA +CYRILLIC CAPITAL LETTER ES WITH DESCENDER + +004AB +CYRILLIC SMALL LETTER ES WITH DESCENDER + +004AC +CYRILLIC CAPITAL LETTER TE WITH DESCENDER + +004AD +CYRILLIC SMALL LETTER TE WITH DESCENDER + +004AE +CYRILLIC CAPITAL LETTER STRAIGHT U + +004AF +CYRILLIC SMALL LETTER STRAIGHT U + +004B0 +CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE + +004B1 +CYRILLIC SMALL LETTER STRAIGHT U WITH STROKE + +004B2 +CYRILLIC CAPITAL LETTER HA WITH DESCENDER + +004B3 +CYRILLIC SMALL LETTER HA WITH DESCENDER + +004B4 +CYRILLIC CAPITAL LIGATURE TE TSE + +004B5 +CYRILLIC SMALL LIGATURE TE TSE + +004B6 +CYRILLIC CAPITAL LETTER CHE WITH DESCENDER + +004B7 +CYRILLIC SMALL LETTER CHE WITH DESCENDER + +004B8 +CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE + +004B9 +CYRILLIC SMALL LETTER CHE WITH VERTICAL STROKE + +004BA +CYRILLIC CAPITAL LETTER SHHA + +004BB +CYRILLIC SMALL LETTER SHHA + +004BC +CYRILLIC CAPITAL LETTER ABKHASIAN CHE + +004BD +CYRILLIC SMALL LETTER ABKHASIAN CHE + +004BE +CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER + +004BF +CYRILLIC SMALL LETTER ABKHASIAN CHE WITH DESCENDER + +004C0 +CYRILLIC LETTER PALOCHKA + +004C1 +CYRILLIC CAPITAL LETTER ZHE WITH BREVE + +004C2 +CYRILLIC SMALL LETTER ZHE WITH BREVE + +004C3 +CYRILLIC CAPITAL LETTER KA WITH HOOK + +004C4 +CYRILLIC SMALL LETTER KA WITH HOOK + +004C5 +CYRILLIC CAPITAL LETTER EL WITH TAIL + +004C6 +CYRILLIC SMALL LETTER EL WITH TAIL + +004C7 +CYRILLIC CAPITAL LETTER EN WITH HOOK + +004C8 +CYRILLIC SMALL LETTER EN WITH HOOK + +004C9 +CYRILLIC CAPITAL LETTER EN WITH TAIL + +004CA +CYRILLIC SMALL LETTER EN WITH TAIL + +004CB +CYRILLIC CAPITAL LETTER KHAKASSIAN CHE + +004CC +CYRILLIC SMALL LETTER KHAKASSIAN CHE + +004CD +CYRILLIC CAPITAL LETTER EM WITH TAIL + +004CE +CYRILLIC SMALL LETTER EM WITH TAIL + +004CF +CYRILLIC SMALL LETTER PALOCHKA + +004D0 +CYRILLIC CAPITAL LETTER A WITH BREVE + +004D1 +CYRILLIC SMALL LETTER A WITH BREVE + +004D2 +CYRILLIC CAPITAL LETTER A WITH DIAERESIS + +004D3 +CYRILLIC SMALL LETTER A WITH DIAERESIS + +004D4 +CYRILLIC CAPITAL LIGATURE A IE + +004D5 +CYRILLIC SMALL LIGATURE A IE + +004D6 +CYRILLIC CAPITAL LETTER IE WITH BREVE + +004D7 +CYRILLIC SMALL LETTER IE WITH BREVE + +004D8 +CYRILLIC CAPITAL LETTER SCHWA + +004D9 +CYRILLIC SMALL LETTER SCHWA + +004DA +CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS + +004DB +CYRILLIC SMALL LETTER SCHWA WITH DIAERESIS + +004DC +CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS + +004DD +CYRILLIC SMALL LETTER ZHE WITH DIAERESIS + +004DE +CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS + +004DF +CYRILLIC SMALL LETTER ZE WITH DIAERESIS + +004E0 +CYRILLIC CAPITAL LETTER ABKHASIAN DZE + +004E1 +CYRILLIC SMALL LETTER ABKHASIAN DZE + +004E2 +CYRILLIC CAPITAL LETTER I WITH MACRON + +004E3 +CYRILLIC SMALL LETTER I WITH MACRON + +004E4 +CYRILLIC CAPITAL LETTER I WITH DIAERESIS + +004E5 +CYRILLIC SMALL LETTER I WITH DIAERESIS + +004E6 +CYRILLIC CAPITAL LETTER O WITH DIAERESIS + +004E7 +CYRILLIC SMALL LETTER O WITH DIAERESIS + +004E8 +CYRILLIC CAPITAL LETTER BARRED O + +004E9 +CYRILLIC SMALL LETTER BARRED O + +004EA +CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS + +004EB +CYRILLIC SMALL LETTER BARRED O WITH DIAERESIS + +004EC +CYRILLIC CAPITAL LETTER E WITH DIAERESIS + +004ED +CYRILLIC SMALL LETTER E WITH DIAERESIS + +004EE +CYRILLIC CAPITAL LETTER U WITH MACRON + +004EF +CYRILLIC SMALL LETTER U WITH MACRON + +004F0 +CYRILLIC CAPITAL LETTER U WITH DIAERESIS + +004F1 +CYRILLIC SMALL LETTER U WITH DIAERESIS + +004F2 +CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE + +004F3 +CYRILLIC SMALL LETTER U WITH DOUBLE ACUTE + +004F4 +CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS + +004F5 +CYRILLIC SMALL LETTER CHE WITH DIAERESIS + +004F6 +CYRILLIC CAPITAL LETTER GHE WITH DESCENDER + +004F7 +CYRILLIC SMALL LETTER GHE WITH DESCENDER + +004F8 +CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS + +004F9 +CYRILLIC SMALL LETTER YERU WITH DIAERESIS + +004FA +CYRILLIC CAPITAL LETTER GHE WITH STROKE AND HOOK + +004FB +CYRILLIC SMALL LETTER GHE WITH STROKE AND HOOK + +004FC +CYRILLIC CAPITAL LETTER HA WITH HOOK + +004FD +CYRILLIC SMALL LETTER HA WITH HOOK + +004FE +CYRILLIC CAPITAL LETTER HA WITH STROKE + +004FF +CYRILLIC SMALL LETTER HA WITH STROKE + +00500 +CYRILLIC CAPITAL LETTER KOMI DE + +00501 +CYRILLIC SMALL LETTER KOMI DE + +00502 +CYRILLIC CAPITAL LETTER KOMI DJE + +00503 +CYRILLIC SMALL LETTER KOMI DJE + +00504 +CYRILLIC CAPITAL LETTER KOMI ZJE + +00505 +CYRILLIC SMALL LETTER KOMI ZJE + +00506 +CYRILLIC CAPITAL LETTER KOMI DZJE + +00507 +CYRILLIC SMALL LETTER KOMI DZJE + +00508 +CYRILLIC CAPITAL LETTER KOMI LJE + +00509 +CYRILLIC SMALL LETTER KOMI LJE + +0050A +CYRILLIC CAPITAL LETTER KOMI NJE + +0050B +CYRILLIC SMALL LETTER KOMI NJE + +0050C +CYRILLIC CAPITAL LETTER KOMI SJE + +0050D +CYRILLIC SMALL LETTER KOMI SJE + +0050E +CYRILLIC CAPITAL LETTER KOMI TJE + +0050F +CYRILLIC SMALL LETTER KOMI TJE + +00510 +CYRILLIC CAPITAL LETTER REVERSED ZE + +00511 +CYRILLIC SMALL LETTER REVERSED ZE + +00512 +CYRILLIC CAPITAL LETTER EL WITH HOOK + +00513 +CYRILLIC SMALL LETTER EL WITH HOOK + +00514 +CYRILLIC CAPITAL LETTER LHA + +00515 +CYRILLIC SMALL LETTER LHA + +00516 +CYRILLIC CAPITAL LETTER RHA + +00517 +CYRILLIC SMALL LETTER RHA + +00518 +CYRILLIC CAPITAL LETTER YAE + +00519 +CYRILLIC SMALL LETTER YAE + +0051A +CYRILLIC CAPITAL LETTER QA + +0051B +CYRILLIC SMALL LETTER QA + +0051C +CYRILLIC CAPITAL LETTER WE + +0051D +CYRILLIC SMALL LETTER WE + +0051E +CYRILLIC CAPITAL LETTER ALEUT KA + +0051F +CYRILLIC SMALL LETTER ALEUT KA + +00520 +CYRILLIC CAPITAL LETTER EL WITH MIDDLE HOOK + +00521 +CYRILLIC SMALL LETTER EL WITH MIDDLE HOOK + +00522 +CYRILLIC CAPITAL LETTER EN WITH MIDDLE HOOK + +00523 +CYRILLIC SMALL LETTER EN WITH MIDDLE HOOK + +00524 +CYRILLIC CAPITAL LETTER PE WITH DESCENDER + +00525 +CYRILLIC SMALL LETTER PE WITH DESCENDER + +00526 +CYRILLIC CAPITAL LETTER SHHA WITH DESCENDER + +00527 +CYRILLIC SMALL LETTER SHHA WITH DESCENDER + +00528 +CYRILLIC CAPITAL LETTER EN WITH LEFT HOOK + +00529 +CYRILLIC SMALL LETTER EN WITH LEFT HOOK + +0052A +CYRILLIC CAPITAL LETTER DZZHE + +0052B +CYRILLIC SMALL LETTER DZZHE + +0052C +CYRILLIC CAPITAL LETTER DCHE + +0052D +CYRILLIC SMALL LETTER DCHE + +0052E +CYRILLIC CAPITAL LETTER EL WITH DESCENDER + +0052F +CYRILLIC SMALL LETTER EL WITH DESCENDER + +00531 +ARMENIAN CAPITAL LETTER AYB + +00532 +ARMENIAN CAPITAL LETTER BEN + +00533 +ARMENIAN CAPITAL LETTER GIM + +00534 +ARMENIAN CAPITAL LETTER DA + +00535 +ARMENIAN CAPITAL LETTER ECH + +00536 +ARMENIAN CAPITAL LETTER ZA + +00537 +ARMENIAN CAPITAL LETTER EH + +00538 +ARMENIAN CAPITAL LETTER ET + +00539 +ARMENIAN CAPITAL LETTER TO + +0053A +ARMENIAN CAPITAL LETTER ZHE + +0053B +ARMENIAN CAPITAL LETTER INI + +0053C +ARMENIAN CAPITAL LETTER LIWN + +0053D +ARMENIAN CAPITAL LETTER XEH + +0053E +ARMENIAN CAPITAL LETTER CA + +0053F +ARMENIAN CAPITAL LETTER KEN + +00540 +ARMENIAN CAPITAL LETTER HO + +00541 +ARMENIAN CAPITAL LETTER JA + +00542 +ARMENIAN CAPITAL LETTER GHAD + +00543 +ARMENIAN CAPITAL LETTER CHEH + +00544 +ARMENIAN CAPITAL LETTER MEN + +00545 +ARMENIAN CAPITAL LETTER YI + +00546 +ARMENIAN CAPITAL LETTER NOW + +00547 +ARMENIAN CAPITAL LETTER SHA + +00548 +ARMENIAN CAPITAL LETTER VO + +00549 +ARMENIAN CAPITAL LETTER CHA + +0054A +ARMENIAN CAPITAL LETTER PEH + +0054B +ARMENIAN CAPITAL LETTER JHEH + +0054C +ARMENIAN CAPITAL LETTER RA + +0054D +ARMENIAN CAPITAL LETTER SEH + +0054E +ARMENIAN CAPITAL LETTER VEW + +0054F +ARMENIAN CAPITAL LETTER TIWN + +00550 +ARMENIAN CAPITAL LETTER REH + +00551 +ARMENIAN CAPITAL LETTER CO + +00552 +ARMENIAN CAPITAL LETTER YIWN + +00553 +ARMENIAN CAPITAL LETTER PIWR + +00554 +ARMENIAN CAPITAL LETTER KEH + +00555 +ARMENIAN CAPITAL LETTER OH + +00556 +ARMENIAN CAPITAL LETTER FEH + +00559 +ARMENIAN MODIFIER LETTER LEFT HALF RING + +0055A +ARMENIAN APOSTROPHE + +0055B +ARMENIAN EMPHASIS MARK + +0055C +ARMENIAN EXCLAMATION MARK + +0055D +ARMENIAN COMMA + +0055E +ARMENIAN QUESTION MARK + +0055F +ARMENIAN ABBREVIATION MARK + +00560 +ARMENIAN SMALL LETTER TURNED AYB + +00561 +ARMENIAN SMALL LETTER AYB + +00562 +ARMENIAN SMALL LETTER BEN + +00563 +ARMENIAN SMALL LETTER GIM + +00564 +ARMENIAN SMALL LETTER DA + +00565 +ARMENIAN SMALL LETTER ECH + +00566 +ARMENIAN SMALL LETTER ZA + +00567 +ARMENIAN SMALL LETTER EH + +00568 +ARMENIAN SMALL LETTER ET + +00569 +ARMENIAN SMALL LETTER TO + +0056A +ARMENIAN SMALL LETTER ZHE + +0056B +ARMENIAN SMALL LETTER INI + +0056C +ARMENIAN SMALL LETTER LIWN + +0056D +ARMENIAN SMALL LETTER XEH + +0056E +ARMENIAN SMALL LETTER CA + +0056F +ARMENIAN SMALL LETTER KEN + +00570 +ARMENIAN SMALL LETTER HO + +00571 +ARMENIAN SMALL LETTER JA + +00572 +ARMENIAN SMALL LETTER GHAD + +00573 +ARMENIAN SMALL LETTER CHEH + +00574 +ARMENIAN SMALL LETTER MEN + +00575 +ARMENIAN SMALL LETTER YI + +00576 +ARMENIAN SMALL LETTER NOW + +00577 +ARMENIAN SMALL LETTER SHA + +00578 +ARMENIAN SMALL LETTER VO + +00579 +ARMENIAN SMALL LETTER CHA + +0057A +ARMENIAN SMALL LETTER PEH + +0057B +ARMENIAN SMALL LETTER JHEH + +0057C +ARMENIAN SMALL LETTER RA + +0057D +ARMENIAN SMALL LETTER SEH + +0057E +ARMENIAN SMALL LETTER VEW + +0057F +ARMENIAN SMALL LETTER TIWN + +00580 +ARMENIAN SMALL LETTER REH + +00581 +ARMENIAN SMALL LETTER CO + +00582 +ARMENIAN SMALL LETTER YIWN + +00583 +ARMENIAN SMALL LETTER PIWR + +00584 +ARMENIAN SMALL LETTER KEH + +00585 +ARMENIAN SMALL LETTER OH + +00586 +ARMENIAN SMALL LETTER FEH + +00587 +ARMENIAN SMALL LIGATURE ECH YIWN + +00588 +ARMENIAN SMALL LETTER YI WITH STROKE + +00589 +ARMENIAN FULL STOP + +0058A +ARMENIAN HYPHEN + +0058D +RIGHT-FACING ARMENIAN ETERNITY SIGN + +0058E +LEFT-FACING ARMENIAN ETERNITY SIGN + +0058F +ARMENIAN DRAM SIGN + +00591 +HEBREW ACCENT ETNAHTA + +00592 +HEBREW ACCENT SEGOL + +00593 +HEBREW ACCENT SHALSHELET + +00594 +HEBREW ACCENT ZAQEF QATAN + +00595 +HEBREW ACCENT ZAQEF GADOL + +00596 +HEBREW ACCENT TIPEHA + +00597 +HEBREW ACCENT REVIA + +00598 +HEBREW ACCENT ZARQA + +00599 +HEBREW ACCENT PASHTA + +0059A +HEBREW ACCENT YETIV + +0059B +HEBREW ACCENT TEVIR + +0059C +HEBREW ACCENT GERESH + +0059D +HEBREW ACCENT GERESH MUQDAM + +0059E +HEBREW ACCENT GERSHAYIM + +0059F +HEBREW ACCENT QARNEY PARA + +005A0 +HEBREW ACCENT TELISHA GEDOLA + +005A1 +HEBREW ACCENT PAZER + +005A2 +HEBREW ACCENT ATNAH HAFUKH + +005A3 +HEBREW ACCENT MUNAH + +005A4 +HEBREW ACCENT MAHAPAKH + +005A5 +HEBREW ACCENT MERKHA + +005A6 +HEBREW ACCENT MERKHA KEFULA + +005A7 +HEBREW ACCENT DARGA + +005A8 +HEBREW ACCENT QADMA + +005A9 +HEBREW ACCENT TELISHA QETANA + +005AA +HEBREW ACCENT YERAH BEN YOMO + +005AB +HEBREW ACCENT OLE + +005AC +HEBREW ACCENT ILUY + +005AD +HEBREW ACCENT DEHI + +005AE +HEBREW ACCENT ZINOR + +005AF +HEBREW MARK MASORA CIRCLE + +005B0 +HEBREW POINT SHEVA + +005B1 +HEBREW POINT HATAF SEGOL + +005B2 +HEBREW POINT HATAF PATAH + +005B3 +HEBREW POINT HATAF QAMATS + +005B4 +HEBREW POINT HIRIQ + +005B5 +HEBREW POINT TSERE + +005B6 +HEBREW POINT SEGOL + +005B7 +HEBREW POINT PATAH + +005B8 +HEBREW POINT QAMATS + +005B9 +HEBREW POINT HOLAM + +005BA +HEBREW POINT HOLAM HASER FOR VAV + +005BB +HEBREW POINT QUBUTS + +005BC +HEBREW POINT DAGESH OR MAPIQ + +005BD +HEBREW POINT METEG + +005BE +HEBREW PUNCTUATION MAQAF + +005BF +HEBREW POINT RAFE + +005C0 +HEBREW PUNCTUATION PASEQ + +005C1 +HEBREW POINT SHIN DOT + +005C2 +HEBREW POINT SIN DOT + +005C3 +HEBREW PUNCTUATION SOF PASUQ + +005C4 +HEBREW MARK UPPER DOT + +005C5 +HEBREW MARK LOWER DOT + +005C6 +HEBREW PUNCTUATION NUN HAFUKHA + +005C7 +HEBREW POINT QAMATS QATAN + +005D0 +HEBREW LETTER ALEF + +005D1 +HEBREW LETTER BET + +005D2 +HEBREW LETTER GIMEL + +005D3 +HEBREW LETTER DALET + +005D4 +HEBREW LETTER HE + +005D5 +HEBREW LETTER VAV + +005D6 +HEBREW LETTER ZAYIN + +005D7 +HEBREW LETTER HET + +005D8 +HEBREW LETTER TET + +005D9 +HEBREW LETTER YOD + +005DA +HEBREW LETTER FINAL KAF + +005DB +HEBREW LETTER KAF + +005DC +HEBREW LETTER LAMED + +005DD +HEBREW LETTER FINAL MEM + +005DE +HEBREW LETTER MEM + +005DF +HEBREW LETTER FINAL NUN + +005E0 +HEBREW LETTER NUN + +005E1 +HEBREW LETTER SAMEKH + +005E2 +HEBREW LETTER AYIN + +005E3 +HEBREW LETTER FINAL PE + +005E4 +HEBREW LETTER PE + +005E5 +HEBREW LETTER FINAL TSADI + +005E6 +HEBREW LETTER TSADI + +005E7 +HEBREW LETTER QOF + +005E8 +HEBREW LETTER RESH + +005E9 +HEBREW LETTER SHIN + +005EA +HEBREW LETTER TAV + +005EF +HEBREW YOD TRIANGLE + +005F0 +HEBREW LIGATURE YIDDISH DOUBLE VAV + +005F1 +HEBREW LIGATURE YIDDISH VAV YOD + +005F2 +HEBREW LIGATURE YIDDISH DOUBLE YOD + +005F3 +HEBREW PUNCTUATION GERESH + +005F4 +HEBREW PUNCTUATION GERSHAYIM + +00600 +ARABIC NUMBER SIGN + +00601 +ARABIC SIGN SANAH + +00602 +ARABIC FOOTNOTE MARKER + +00603 +ARABIC SIGN SAFHA + +00604 +ARABIC SIGN SAMVAT + +00605 +ARABIC NUMBER MARK ABOVE + +00606 +ARABIC-INDIC CUBE ROOT + +00607 +ARABIC-INDIC FOURTH ROOT + +00608 +ARABIC RAY + +00609 +ARABIC-INDIC PER MILLE SIGN + +0060A +ARABIC-INDIC PER TEN THOUSAND SIGN + +0060B +AFGHANI SIGN + +0060C +ARABIC COMMA + +0060D +ARABIC DATE SEPARATOR + +0060E +ARABIC POETIC VERSE SIGN + +0060F +ARABIC SIGN MISRA + +00610 +ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM + +00611 +ARABIC SIGN ALAYHE ASSALLAM + +00612 +ARABIC SIGN RAHMATULLAH ALAYHE + +00613 +ARABIC SIGN RADI ALLAHOU ANHU + +00614 +ARABIC SIGN TAKHALLUS + +00615 +ARABIC SMALL HIGH TAH + +00616 +ARABIC SMALL HIGH LIGATURE ALEF WITH YEH BARREE + +00616 +ARABIC SMALL HIGH LIGATURE ALEF WITH LAM WITH YEH + +00617 +ARABIC SMALL HIGH ZAIN + +00618 +ARABIC SMALL FATHA + +00619 +ARABIC SMALL DAMMA + +0061A +ARABIC SMALL KASRA + +0061B +ARABIC SEMICOLON + +0061C +ARABIC LETTER MARK + +0061C +ALM + +0061D +ARABIC END OF TEXT MARK + +0061E +ARABIC TRIPLE DOT PUNCTUATION MARK + +0061F +ARABIC QUESTION MARK + +00620 +ARABIC LETTER KASHMIRI YEH + +00621 +ARABIC LETTER HAMZA + +00622 +ARABIC LETTER ALEF WITH MADDA ABOVE + +00623 +ARABIC LETTER ALEF WITH HAMZA ABOVE + +00624 +ARABIC LETTER WAW WITH HAMZA ABOVE + +00625 +ARABIC LETTER ALEF WITH HAMZA BELOW + +00626 +ARABIC LETTER YEH WITH HAMZA ABOVE + +00627 +ARABIC LETTER ALEF + +00628 +ARABIC LETTER BEH + +00629 +ARABIC LETTER TEH MARBUTA + +0062A +ARABIC LETTER TEH + +0062B +ARABIC LETTER THEH + +0062C +ARABIC LETTER JEEM + +0062D +ARABIC LETTER HAH + +0062E +ARABIC LETTER KHAH + +0062F +ARABIC LETTER DAL + +00630 +ARABIC LETTER THAL + +00631 +ARABIC LETTER REH + +00632 +ARABIC LETTER ZAIN + +00633 +ARABIC LETTER SEEN + +00634 +ARABIC LETTER SHEEN + +00635 +ARABIC LETTER SAD + +00636 +ARABIC LETTER DAD + +00637 +ARABIC LETTER TAH + +00638 +ARABIC LETTER ZAH + +00639 +ARABIC LETTER AIN + +0063A +ARABIC LETTER GHAIN + +0063B +ARABIC LETTER KEHEH WITH TWO DOTS ABOVE + +0063C +ARABIC LETTER KEHEH WITH THREE DOTS BELOW + +0063D +ARABIC LETTER FARSI YEH WITH INVERTED V + +0063E +ARABIC LETTER FARSI YEH WITH TWO DOTS ABOVE + +0063F +ARABIC LETTER FARSI YEH WITH THREE DOTS ABOVE + +00640 +ARABIC TATWEEL + +00641 +ARABIC LETTER FEH + +00642 +ARABIC LETTER QAF + +00643 +ARABIC LETTER KAF + +00644 +ARABIC LETTER LAM + +00645 +ARABIC LETTER MEEM + +00646 +ARABIC LETTER NOON + +00647 +ARABIC LETTER HEH + +00648 +ARABIC LETTER WAW + +00649 +ARABIC LETTER ALEF MAKSURA + +0064A +ARABIC LETTER YEH + +0064B +ARABIC FATHATAN + +0064C +ARABIC DAMMATAN + +0064D +ARABIC KASRATAN + +0064E +ARABIC FATHA + +0064F +ARABIC DAMMA + +00650 +ARABIC KASRA + +00651 +ARABIC SHADDA + +00652 +ARABIC SUKUN + +00653 +ARABIC MADDAH ABOVE + +00654 +ARABIC HAMZA ABOVE + +00655 +ARABIC HAMZA BELOW + +00656 +ARABIC SUBSCRIPT ALEF + +00657 +ARABIC INVERTED DAMMA + +00658 +ARABIC MARK NOON GHUNNA + +00659 +ARABIC ZWARAKAY + +0065A +ARABIC VOWEL SIGN SMALL V ABOVE + +0065B +ARABIC VOWEL SIGN INVERTED SMALL V ABOVE + +0065C +ARABIC VOWEL SIGN DOT BELOW + +0065D +ARABIC REVERSED DAMMA + +0065E +ARABIC FATHA WITH TWO DOTS + +0065F +ARABIC WAVY HAMZA BELOW + +00660 +ARABIC-INDIC DIGIT ZERO + +00661 +ARABIC-INDIC DIGIT ONE + +00662 +ARABIC-INDIC DIGIT TWO + +00663 +ARABIC-INDIC DIGIT THREE + +00664 +ARABIC-INDIC DIGIT FOUR + +00665 +ARABIC-INDIC DIGIT FIVE + +00666 +ARABIC-INDIC DIGIT SIX + +00667 +ARABIC-INDIC DIGIT SEVEN + +00668 +ARABIC-INDIC DIGIT EIGHT + +00669 +ARABIC-INDIC DIGIT NINE + +0066A +ARABIC PERCENT SIGN + +0066B +ARABIC DECIMAL SEPARATOR + +0066C +ARABIC THOUSANDS SEPARATOR + +0066D +ARABIC FIVE POINTED STAR + +0066E +ARABIC LETTER DOTLESS BEH + +0066F +ARABIC LETTER DOTLESS QAF + +00670 +ARABIC LETTER SUPERSCRIPT ALEF + +00671 +ARABIC LETTER ALEF WASLA + +00672 +ARABIC LETTER ALEF WITH WAVY HAMZA ABOVE + +00673 +ARABIC LETTER ALEF WITH WAVY HAMZA BELOW + +00674 +ARABIC LETTER HIGH HAMZA + +00675 +ARABIC LETTER HIGH HAMZA ALEF + +00676 +ARABIC LETTER HIGH HAMZA WAW + +00677 +ARABIC LETTER U WITH HAMZA ABOVE + +00678 +ARABIC LETTER HIGH HAMZA YEH + +00679 +ARABIC LETTER TTEH + +0067A +ARABIC LETTER TTEHEH + +0067B +ARABIC LETTER BEEH + +0067C +ARABIC LETTER TEH WITH RING + +0067D +ARABIC LETTER TEH WITH THREE DOTS ABOVE DOWNWARDS + +0067E +ARABIC LETTER PEH + +0067F +ARABIC LETTER TEHEH + +00680 +ARABIC LETTER BEHEH + +00681 +ARABIC LETTER HAH WITH HAMZA ABOVE + +00682 +ARABIC LETTER HAH WITH TWO DOTS VERTICAL ABOVE + +00683 +ARABIC LETTER NYEH + +00684 +ARABIC LETTER DYEH + +00685 +ARABIC LETTER HAH WITH THREE DOTS ABOVE + +00686 +ARABIC LETTER TCHEH + +00687 +ARABIC LETTER TCHEHEH + +00688 +ARABIC LETTER DDAL + +00689 +ARABIC LETTER DAL WITH RING + +0068A +ARABIC LETTER DAL WITH DOT BELOW + +0068B +ARABIC LETTER DAL WITH DOT BELOW AND SMALL TAH + +0068C +ARABIC LETTER DAHAL + +0068D +ARABIC LETTER DDAHAL + +0068E +ARABIC LETTER DUL + +0068F +ARABIC LETTER DAL WITH THREE DOTS ABOVE DOWNWARDS + +00690 +ARABIC LETTER DAL WITH FOUR DOTS ABOVE + +00691 +ARABIC LETTER RREH + +00692 +ARABIC LETTER REH WITH SMALL V + +00693 +ARABIC LETTER REH WITH RING + +00694 +ARABIC LETTER REH WITH DOT BELOW + +00695 +ARABIC LETTER REH WITH SMALL V BELOW + +00696 +ARABIC LETTER REH WITH DOT BELOW AND DOT ABOVE + +00697 +ARABIC LETTER REH WITH TWO DOTS ABOVE + +00698 +ARABIC LETTER JEH + +00699 +ARABIC LETTER REH WITH FOUR DOTS ABOVE + +0069A +ARABIC LETTER SEEN WITH DOT BELOW AND DOT ABOVE + +0069B +ARABIC LETTER SEEN WITH THREE DOTS BELOW + +0069C +ARABIC LETTER SEEN WITH THREE DOTS BELOW AND THREE DOTS ABOVE + +0069D +ARABIC LETTER SAD WITH TWO DOTS BELOW + +0069E +ARABIC LETTER SAD WITH THREE DOTS ABOVE + +0069F +ARABIC LETTER TAH WITH THREE DOTS ABOVE + +006A0 +ARABIC LETTER AIN WITH THREE DOTS ABOVE + +006A1 +ARABIC LETTER DOTLESS FEH + +006A2 +ARABIC LETTER FEH WITH DOT MOVED BELOW + +006A3 +ARABIC LETTER FEH WITH DOT BELOW + +006A4 +ARABIC LETTER VEH + +006A5 +ARABIC LETTER FEH WITH THREE DOTS BELOW + +006A6 +ARABIC LETTER PEHEH + +006A7 +ARABIC LETTER QAF WITH DOT ABOVE + +006A8 +ARABIC LETTER QAF WITH THREE DOTS ABOVE + +006A9 +ARABIC LETTER KEHEH + +006AA +ARABIC LETTER SWASH KAF + +006AB +ARABIC LETTER KAF WITH RING + +006AC +ARABIC LETTER KAF WITH DOT ABOVE + +006AD +ARABIC LETTER NG + +006AE +ARABIC LETTER KAF WITH THREE DOTS BELOW + +006AF +ARABIC LETTER GAF + +006B0 +ARABIC LETTER GAF WITH RING + +006B1 +ARABIC LETTER NGOEH + +006B2 +ARABIC LETTER GAF WITH TWO DOTS BELOW + +006B3 +ARABIC LETTER GUEH + +006B4 +ARABIC LETTER GAF WITH THREE DOTS ABOVE + +006B5 +ARABIC LETTER LAM WITH SMALL V + +006B6 +ARABIC LETTER LAM WITH DOT ABOVE + +006B7 +ARABIC LETTER LAM WITH THREE DOTS ABOVE + +006B8 +ARABIC LETTER LAM WITH THREE DOTS BELOW + +006B9 +ARABIC LETTER NOON WITH DOT BELOW + +006BA +ARABIC LETTER NOON GHUNNA + +006BB +ARABIC LETTER RNOON + +006BC +ARABIC LETTER NOON WITH RING + +006BD +ARABIC LETTER NOON WITH THREE DOTS ABOVE + +006BE +ARABIC LETTER HEH DOACHASHMEE + +006BF +ARABIC LETTER TCHEH WITH DOT ABOVE + +006C0 +ARABIC LETTER HEH WITH YEH ABOVE + +006C1 +ARABIC LETTER HEH GOAL + +006C2 +ARABIC LETTER HEH GOAL WITH HAMZA ABOVE + +006C3 +ARABIC LETTER TEH MARBUTA GOAL + +006C4 +ARABIC LETTER WAW WITH RING + +006C5 +ARABIC LETTER KIRGHIZ OE + +006C6 +ARABIC LETTER OE + +006C7 +ARABIC LETTER U + +006C8 +ARABIC LETTER YU + +006C9 +ARABIC LETTER KIRGHIZ YU + +006CA +ARABIC LETTER WAW WITH TWO DOTS ABOVE + +006CB +ARABIC LETTER VE + +006CC +ARABIC LETTER FARSI YEH + +006CD +ARABIC LETTER YEH WITH TAIL + +006CE +ARABIC LETTER YEH WITH SMALL V + +006CF +ARABIC LETTER WAW WITH DOT ABOVE + +006D0 +ARABIC LETTER E + +006D1 +ARABIC LETTER YEH WITH THREE DOTS BELOW + +006D2 +ARABIC LETTER YEH BARREE + +006D3 +ARABIC LETTER YEH BARREE WITH HAMZA ABOVE + +006D4 +ARABIC FULL STOP + +006D5 +ARABIC LETTER AE + +006D6 +ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA + +006D7 +ARABIC SMALL HIGH LIGATURE QAF WITH LAM WITH ALEF MAKSURA + +006D8 +ARABIC SMALL HIGH MEEM INITIAL FORM + +006D9 +ARABIC SMALL HIGH LAM ALEF + +006DA +ARABIC SMALL HIGH JEEM + +006DB +ARABIC SMALL HIGH THREE DOTS + +006DC +ARABIC SMALL HIGH SEEN + +006DD +ARABIC END OF AYAH + +006DE +ARABIC START OF RUB EL HIZB + +006DF +ARABIC SMALL HIGH ROUNDED ZERO + +006E0 +ARABIC SMALL HIGH UPRIGHT RECTANGULAR ZERO + +006E1 +ARABIC SMALL HIGH DOTLESS HEAD OF KHAH + +006E2 +ARABIC SMALL HIGH MEEM ISOLATED FORM + +006E3 +ARABIC SMALL LOW SEEN + +006E4 +ARABIC SMALL HIGH MADDA + +006E5 +ARABIC SMALL WAW + +006E6 +ARABIC SMALL YEH + +006E7 +ARABIC SMALL HIGH YEH + +006E8 +ARABIC SMALL HIGH NOON + +006E9 +ARABIC PLACE OF SAJDAH + +006EA +ARABIC EMPTY CENTRE LOW STOP + +006EB +ARABIC EMPTY CENTRE HIGH STOP + +006EC +ARABIC ROUNDED HIGH STOP WITH FILLED CENTRE + +006ED +ARABIC SMALL LOW MEEM + +006EE +ARABIC LETTER DAL WITH INVERTED V + +006EF +ARABIC LETTER REH WITH INVERTED V + +006F0 +EXTENDED ARABIC-INDIC DIGIT ZERO + +006F1 +EXTENDED ARABIC-INDIC DIGIT ONE + +006F2 +EXTENDED ARABIC-INDIC DIGIT TWO + +006F3 +EXTENDED ARABIC-INDIC DIGIT THREE + +006F4 +EXTENDED ARABIC-INDIC DIGIT FOUR + +006F5 +EXTENDED ARABIC-INDIC DIGIT FIVE + +006F6 +EXTENDED ARABIC-INDIC DIGIT SIX + +006F7 +EXTENDED ARABIC-INDIC DIGIT SEVEN + +006F8 +EXTENDED ARABIC-INDIC DIGIT EIGHT + +006F9 +EXTENDED ARABIC-INDIC DIGIT NINE + +006FA +ARABIC LETTER SHEEN WITH DOT BELOW + +006FB +ARABIC LETTER DAD WITH DOT BELOW + +006FC +ARABIC LETTER GHAIN WITH DOT BELOW + +006FD +ARABIC SIGN SINDHI AMPERSAND + +006FE +ARABIC SIGN SINDHI POSTPOSITION MEN + +006FF +ARABIC LETTER HEH WITH INVERTED V + +00700 +SYRIAC END OF PARAGRAPH + +00701 +SYRIAC SUPRALINEAR FULL STOP + +00702 +SYRIAC SUBLINEAR FULL STOP + +00703 +SYRIAC SUPRALINEAR COLON + +00704 +SYRIAC SUBLINEAR COLON + +00705 +SYRIAC HORIZONTAL COLON + +00706 +SYRIAC COLON SKEWED LEFT + +00707 +SYRIAC COLON SKEWED RIGHT + +00708 +SYRIAC SUPRALINEAR COLON SKEWED LEFT + +00709 +SYRIAC SUBLINEAR COLON SKEWED LEFT + +00709 +SYRIAC SUBLINEAR COLON SKEWED RIGHT + +0070A +SYRIAC CONTRACTION + +0070B +SYRIAC HARKLEAN OBELUS + +0070C +SYRIAC HARKLEAN METOBELUS + +0070D +SYRIAC HARKLEAN ASTERISCUS + +0070F +SYRIAC ABBREVIATION MARK + +00710 +SYRIAC LETTER ALAPH + +00711 +SYRIAC LETTER SUPERSCRIPT ALAPH + +00712 +SYRIAC LETTER BETH + +00713 +SYRIAC LETTER GAMAL + +00714 +SYRIAC LETTER GAMAL GARSHUNI + +00715 +SYRIAC LETTER DALATH + +00716 +SYRIAC LETTER DOTLESS DALATH RISH + +00717 +SYRIAC LETTER HE + +00718 +SYRIAC LETTER WAW + +00719 +SYRIAC LETTER ZAIN + +0071A +SYRIAC LETTER HETH + +0071B +SYRIAC LETTER TETH + +0071C +SYRIAC LETTER TETH GARSHUNI + +0071D +SYRIAC LETTER YUDH + +0071E +SYRIAC LETTER YUDH HE + +0071F +SYRIAC LETTER KAPH + +00720 +SYRIAC LETTER LAMADH + +00721 +SYRIAC LETTER MIM + +00722 +SYRIAC LETTER NUN + +00723 +SYRIAC LETTER SEMKATH + +00724 +SYRIAC LETTER FINAL SEMKATH + +00725 +SYRIAC LETTER E + +00726 +SYRIAC LETTER PE + +00727 +SYRIAC LETTER REVERSED PE + +00728 +SYRIAC LETTER SADHE + +00729 +SYRIAC LETTER QAPH + +0072A +SYRIAC LETTER RISH + +0072B +SYRIAC LETTER SHIN + +0072C +SYRIAC LETTER TAW + +0072D +SYRIAC LETTER PERSIAN BHETH + +0072E +SYRIAC LETTER PERSIAN GHAMAL + +0072F +SYRIAC LETTER PERSIAN DHALATH + +00730 +SYRIAC PTHAHA ABOVE + +00731 +SYRIAC PTHAHA BELOW + +00732 +SYRIAC PTHAHA DOTTED + +00733 +SYRIAC ZQAPHA ABOVE + +00734 +SYRIAC ZQAPHA BELOW + +00735 +SYRIAC ZQAPHA DOTTED + +00736 +SYRIAC RBASA ABOVE + +00737 +SYRIAC RBASA BELOW + +00738 +SYRIAC DOTTED ZLAMA HORIZONTAL + +00739 +SYRIAC DOTTED ZLAMA ANGULAR + +0073A +SYRIAC HBASA ABOVE + +0073B +SYRIAC HBASA BELOW + +0073C +SYRIAC HBASA-ESASA DOTTED + +0073D +SYRIAC ESASA ABOVE + +0073E +SYRIAC ESASA BELOW + +0073F +SYRIAC RWAHA + +00740 +SYRIAC FEMININE DOT + +00741 +SYRIAC QUSHSHAYA + +00742 +SYRIAC RUKKAKHA + +00743 +SYRIAC TWO VERTICAL DOTS ABOVE + +00744 +SYRIAC TWO VERTICAL DOTS BELOW + +00745 +SYRIAC THREE DOTS ABOVE + +00746 +SYRIAC THREE DOTS BELOW + +00747 +SYRIAC OBLIQUE LINE ABOVE + +00748 +SYRIAC OBLIQUE LINE BELOW + +00749 +SYRIAC MUSIC + +0074A +SYRIAC BARREKH + +0074D +SYRIAC LETTER SOGDIAN ZHAIN + +0074E +SYRIAC LETTER SOGDIAN KHAPH + +0074F +SYRIAC LETTER SOGDIAN FE + +00750 +ARABIC LETTER BEH WITH THREE DOTS HORIZONTALLY BELOW + +00751 +ARABIC LETTER BEH WITH DOT BELOW AND THREE DOTS ABOVE + +00752 +ARABIC LETTER BEH WITH THREE DOTS POINTING UPWARDS BELOW + +00753 +ARABIC LETTER BEH WITH THREE DOTS POINTING UPWARDS BELOW AND TWO DOTS ABOVE + +00754 +ARABIC LETTER BEH WITH TWO DOTS BELOW AND DOT ABOVE + +00755 +ARABIC LETTER BEH WITH INVERTED SMALL V BELOW + +00756 +ARABIC LETTER BEH WITH SMALL V + +00757 +ARABIC LETTER HAH WITH TWO DOTS ABOVE + +00758 +ARABIC LETTER HAH WITH THREE DOTS POINTING UPWARDS BELOW + +00759 +ARABIC LETTER DAL WITH TWO DOTS VERTICALLY BELOW AND SMALL TAH + +0075A +ARABIC LETTER DAL WITH INVERTED SMALL V BELOW + +0075B +ARABIC LETTER REH WITH STROKE + +0075C +ARABIC LETTER SEEN WITH FOUR DOTS ABOVE + +0075D +ARABIC LETTER AIN WITH TWO DOTS ABOVE + +0075E +ARABIC LETTER AIN WITH THREE DOTS POINTING DOWNWARDS ABOVE + +0075F +ARABIC LETTER AIN WITH TWO DOTS VERTICALLY ABOVE + +00760 +ARABIC LETTER FEH WITH TWO DOTS BELOW + +00761 +ARABIC LETTER FEH WITH THREE DOTS POINTING UPWARDS BELOW + +00762 +ARABIC LETTER KEHEH WITH DOT ABOVE + +00763 +ARABIC LETTER KEHEH WITH THREE DOTS ABOVE + +00764 +ARABIC LETTER KEHEH WITH THREE DOTS POINTING UPWARDS BELOW + +00765 +ARABIC LETTER MEEM WITH DOT ABOVE + +00766 +ARABIC LETTER MEEM WITH DOT BELOW + +00767 +ARABIC LETTER NOON WITH TWO DOTS BELOW + +00768 +ARABIC LETTER NOON WITH SMALL TAH + +00769 +ARABIC LETTER NOON WITH SMALL V + +0076A +ARABIC LETTER LAM WITH BAR + +0076B +ARABIC LETTER REH WITH TWO DOTS VERTICALLY ABOVE + +0076C +ARABIC LETTER REH WITH HAMZA ABOVE + +0076D +ARABIC LETTER SEEN WITH TWO DOTS VERTICALLY ABOVE + +0076E +ARABIC LETTER HAH WITH SMALL ARABIC LETTER TAH BELOW + +0076F +ARABIC LETTER HAH WITH SMALL ARABIC LETTER TAH AND TWO DOTS + +00770 +ARABIC LETTER SEEN WITH SMALL ARABIC LETTER TAH AND TWO DOTS + +00771 +ARABIC LETTER REH WITH SMALL ARABIC LETTER TAH AND TWO DOTS + +00772 +ARABIC LETTER HAH WITH SMALL ARABIC LETTER TAH ABOVE + +00773 +ARABIC LETTER ALEF WITH EXTENDED ARABIC-INDIC DIGIT TWO ABOVE + +00774 +ARABIC LETTER ALEF WITH EXTENDED ARABIC-INDIC DIGIT THREE ABOVE + +00775 +ARABIC LETTER FARSI YEH WITH EXTENDED ARABIC-INDIC DIGIT TWO ABOVE + +00776 +ARABIC LETTER FARSI YEH WITH EXTENDED ARABIC-INDIC DIGIT THREE ABOVE + +00777 +ARABIC LETTER FARSI YEH WITH EXTENDED ARABIC-INDIC DIGIT FOUR BELOW + +00778 +ARABIC LETTER WAW WITH EXTENDED ARABIC-INDIC DIGIT TWO ABOVE + +00779 +ARABIC LETTER WAW WITH EXTENDED ARABIC-INDIC DIGIT THREE ABOVE + +0077A +ARABIC LETTER YEH BARREE WITH EXTENDED ARABIC-INDIC DIGIT TWO ABOVE + +0077B +ARABIC LETTER YEH BARREE WITH EXTENDED ARABIC-INDIC DIGIT THREE ABOVE + +0077C +ARABIC LETTER HAH WITH EXTENDED ARABIC-INDIC DIGIT FOUR BELOW + +0077D +ARABIC LETTER SEEN WITH EXTENDED ARABIC-INDIC DIGIT FOUR ABOVE + +0077E +ARABIC LETTER SEEN WITH INVERTED V + +0077F +ARABIC LETTER KAF WITH TWO DOTS ABOVE + +00780 +THAANA LETTER HAA + +00781 +THAANA LETTER SHAVIYANI + +00782 +THAANA LETTER NOONU + +00783 +THAANA LETTER RAA + +00784 +THAANA LETTER BAA + +00785 +THAANA LETTER LHAVIYANI + +00786 +THAANA LETTER KAAFU + +00787 +THAANA LETTER ALIFU + +00788 +THAANA LETTER VAAVU + +00789 +THAANA LETTER MEEMU + +0078A +THAANA LETTER FAAFU + +0078B +THAANA LETTER DHAALU + +0078C +THAANA LETTER THAA + +0078D +THAANA LETTER LAAMU + +0078E +THAANA LETTER GAAFU + +0078F +THAANA LETTER GNAVIYANI + +00790 +THAANA LETTER SEENU + +00791 +THAANA LETTER DAVIYANI + +00792 +THAANA LETTER ZAVIYANI + +00793 +THAANA LETTER TAVIYANI + +00794 +THAANA LETTER YAA + +00795 +THAANA LETTER PAVIYANI + +00796 +THAANA LETTER JAVIYANI + +00797 +THAANA LETTER CHAVIYANI + +00798 +THAANA LETTER TTAA + +00799 +THAANA LETTER HHAA + +0079A +THAANA LETTER KHAA + +0079B +THAANA LETTER THAALU + +0079C +THAANA LETTER ZAA + +0079D +THAANA LETTER SHEENU + +0079E +THAANA LETTER SAADHU + +0079F +THAANA LETTER DAADHU + +007A0 +THAANA LETTER TO + +007A1 +THAANA LETTER ZO + +007A2 +THAANA LETTER AINU + +007A3 +THAANA LETTER GHAINU + +007A4 +THAANA LETTER QAAFU + +007A5 +THAANA LETTER WAAVU + +007A6 +THAANA ABAFILI + +007A7 +THAANA AABAAFILI + +007A8 +THAANA IBIFILI + +007A9 +THAANA EEBEEFILI + +007AA +THAANA UBUFILI + +007AB +THAANA OOBOOFILI + +007AC +THAANA EBEFILI + +007AD +THAANA EYBEYFILI + +007AE +THAANA OBOFILI + +007AF +THAANA OABOAFILI + +007B0 +THAANA SUKUN + +007B1 +THAANA LETTER NAA + +007C0 +NKO DIGIT ZERO + +007C1 +NKO DIGIT ONE + +007C2 +NKO DIGIT TWO + +007C3 +NKO DIGIT THREE + +007C4 +NKO DIGIT FOUR + +007C5 +NKO DIGIT FIVE + +007C6 +NKO DIGIT SIX + +007C7 +NKO DIGIT SEVEN + +007C8 +NKO DIGIT EIGHT + +007C9 +NKO DIGIT NINE + +007CA +NKO LETTER A + +007CB +NKO LETTER EE + +007CC +NKO LETTER I + +007CD +NKO LETTER E + +007CE +NKO LETTER U + +007CF +NKO LETTER OO + +007D0 +NKO LETTER O + +007D1 +NKO LETTER DAGBASINNA + +007D2 +NKO LETTER N + +007D3 +NKO LETTER BA + +007D4 +NKO LETTER PA + +007D5 +NKO LETTER TA + +007D6 +NKO LETTER JA + +007D7 +NKO LETTER CHA + +007D8 +NKO LETTER DA + +007D9 +NKO LETTER RA + +007DA +NKO LETTER RRA + +007DB +NKO LETTER SA + +007DC +NKO LETTER GBA + +007DD +NKO LETTER FA + +007DE +NKO LETTER KA + +007DF +NKO LETTER LA + +007E0 +NKO LETTER NA WOLOSO + +007E1 +NKO LETTER MA + +007E2 +NKO LETTER NYA + +007E3 +NKO LETTER NA + +007E4 +NKO LETTER HA + +007E5 +NKO LETTER WA + +007E6 +NKO LETTER YA + +007E7 +NKO LETTER NYA WOLOSO + +007E8 +NKO LETTER JONA JA + +007E9 +NKO LETTER JONA CHA + +007EA +NKO LETTER JONA RA + +007EB +NKO COMBINING SHORT HIGH TONE + +007EC +NKO COMBINING SHORT LOW TONE + +007ED +NKO COMBINING SHORT RISING TONE + +007EE +NKO COMBINING LONG DESCENDING TONE + +007EF +NKO COMBINING LONG HIGH TONE + +007F0 +NKO COMBINING LONG LOW TONE + +007F1 +NKO COMBINING LONG RISING TONE + +007F2 +NKO COMBINING NASALIZATION MARK + +007F3 +NKO COMBINING DOUBLE DOT ABOVE + +007F4 +NKO HIGH TONE APOSTROPHE + +007F5 +NKO LOW TONE APOSTROPHE + +007F6 +NKO SYMBOL OO DENNEN + +007F7 +NKO SYMBOL GBAKURUNEN + +007F8 +NKO COMMA + +007F9 +NKO EXCLAMATION MARK + +007FA +NKO LAJANYALAN + +007FD +NKO DANTAYALAN + +007FE +NKO DOROME SIGN + +007FF +NKO TAMAN SIGN + +00800 +SAMARITAN LETTER ALAF + +00801 +SAMARITAN LETTER BIT + +00802 +SAMARITAN LETTER GAMAN + +00803 +SAMARITAN LETTER DALAT + +00804 +SAMARITAN LETTER IY + +00805 +SAMARITAN LETTER BAA + +00806 +SAMARITAN LETTER ZEN + +00807 +SAMARITAN LETTER IT + +00808 +SAMARITAN LETTER TIT + +00809 +SAMARITAN LETTER YUT + +0080A +SAMARITAN LETTER KAAF + +0080B +SAMARITAN LETTER LABAT + +0080C +SAMARITAN LETTER MIM + +0080D +SAMARITAN LETTER NUN + +0080E +SAMARITAN LETTER SINGAAT + +0080F +SAMARITAN LETTER IN + +00810 +SAMARITAN LETTER FI + +00811 +SAMARITAN LETTER TSAADIY + +00812 +SAMARITAN LETTER QUF + +00813 +SAMARITAN LETTER RISH + +00814 +SAMARITAN LETTER SHAN + +00815 +SAMARITAN LETTER TAAF + +00816 +SAMARITAN MARK IN + +00817 +SAMARITAN MARK IN-ALAF + +00818 +SAMARITAN MARK OCCLUSION + +00819 +SAMARITAN MARK DAGESH + +0081A +SAMARITAN MODIFIER LETTER EPENTHETIC YUT + +0081B +SAMARITAN MARK EPENTHETIC YUT + +0081C +SAMARITAN VOWEL SIGN LONG E + +0081D +SAMARITAN VOWEL SIGN E + +0081E +SAMARITAN VOWEL SIGN OVERLONG AA + +0081F +SAMARITAN VOWEL SIGN LONG AA + +00820 +SAMARITAN VOWEL SIGN AA + +00821 +SAMARITAN VOWEL SIGN OVERLONG A + +00822 +SAMARITAN VOWEL SIGN LONG A + +00823 +SAMARITAN VOWEL SIGN A + +00824 +SAMARITAN MODIFIER LETTER SHORT A + +00825 +SAMARITAN VOWEL SIGN SHORT A + +00826 +SAMARITAN VOWEL SIGN LONG U + +00827 +SAMARITAN VOWEL SIGN U + +00828 +SAMARITAN MODIFIER LETTER I + +00829 +SAMARITAN VOWEL SIGN LONG I + +0082A +SAMARITAN VOWEL SIGN I + +0082B +SAMARITAN VOWEL SIGN O + +0082C +SAMARITAN VOWEL SIGN SUKUN + +0082D +SAMARITAN MARK NEQUDAA + +00830 +SAMARITAN PUNCTUATION NEQUDAA + +00831 +SAMARITAN PUNCTUATION AFSAAQ + +00832 +SAMARITAN PUNCTUATION ANGED + +00833 +SAMARITAN PUNCTUATION BAU + +00834 +SAMARITAN PUNCTUATION ATMAAU + +00835 +SAMARITAN PUNCTUATION SHIYYAALAA + +00836 +SAMARITAN ABBREVIATION MARK + +00837 +SAMARITAN PUNCTUATION MELODIC QITSA + +00838 +SAMARITAN PUNCTUATION ZIQAA + +00839 +SAMARITAN PUNCTUATION QITSA + +0083A +SAMARITAN PUNCTUATION ZAEF + +0083B +SAMARITAN PUNCTUATION TURU + +0083C +SAMARITAN PUNCTUATION ARKAANU + +0083D +SAMARITAN PUNCTUATION SOF MASHFAAT + +0083E +SAMARITAN PUNCTUATION ANNAAU + +00840 +MANDAIC LETTER HALQA + +00841 +MANDAIC LETTER AB + +00842 +MANDAIC LETTER AG + +00843 +MANDAIC LETTER AD + +00844 +MANDAIC LETTER AH + +00845 +MANDAIC LETTER USHENNA + +00846 +MANDAIC LETTER AZ + +00847 +MANDAIC LETTER IT + +00848 +MANDAIC LETTER ATT + +00849 +MANDAIC LETTER AKSA + +0084A +MANDAIC LETTER AK + +0084B +MANDAIC LETTER AL + +0084C +MANDAIC LETTER AM + +0084D +MANDAIC LETTER AN + +0084E +MANDAIC LETTER AS + +0084F +MANDAIC LETTER IN + +00850 +MANDAIC LETTER AP + +00851 +MANDAIC LETTER ASZ + +00852 +MANDAIC LETTER AQ + +00853 +MANDAIC LETTER AR + +00854 +MANDAIC LETTER ASH + +00855 +MANDAIC LETTER AT + +00856 +MANDAIC LETTER DUSHENNA + +00857 +MANDAIC LETTER KAD + +00858 +MANDAIC LETTER AIN + +00859 +MANDAIC AFFRICATION MARK + +0085A +MANDAIC VOCALIZATION MARK + +0085B +MANDAIC GEMINATION MARK + +0085E +MANDAIC PUNCTUATION + +00860 +SYRIAC LETTER MALAYALAM NGA + +00861 +SYRIAC LETTER MALAYALAM JA + +00862 +SYRIAC LETTER MALAYALAM NYA + +00863 +SYRIAC LETTER MALAYALAM TTA + +00864 +SYRIAC LETTER MALAYALAM NNA + +00865 +SYRIAC LETTER MALAYALAM NNNA + +00866 +SYRIAC LETTER MALAYALAM BHA + +00867 +SYRIAC LETTER MALAYALAM RA + +00868 +SYRIAC LETTER MALAYALAM LLA + +00869 +SYRIAC LETTER MALAYALAM LLLA + +0086A +SYRIAC LETTER MALAYALAM SSA + +00870 +ARABIC LETTER ALEF WITH ATTACHED FATHA + +00871 +ARABIC LETTER ALEF WITH ATTACHED TOP RIGHT FATHA + +00872 +ARABIC LETTER ALEF WITH RIGHT MIDDLE STROKE + +00873 +ARABIC LETTER ALEF WITH LEFT MIDDLE STROKE + +00874 +ARABIC LETTER ALEF WITH ATTACHED KASRA + +00875 +ARABIC LETTER ALEF WITH ATTACHED BOTTOM RIGHT KASRA + +00876 +ARABIC LETTER ALEF WITH ATTACHED ROUND DOT ABOVE + +00877 +ARABIC LETTER ALEF WITH ATTACHED RIGHT ROUND DOT + +00878 +ARABIC LETTER ALEF WITH ATTACHED LEFT ROUND DOT + +00879 +ARABIC LETTER ALEF WITH ATTACHED ROUND DOT BELOW + +0087A +ARABIC LETTER ALEF WITH DOT ABOVE + +0087B +ARABIC LETTER ALEF WITH ATTACHED TOP RIGHT FATHA AND DOT ABOVE + +0087C +ARABIC LETTER ALEF WITH RIGHT MIDDLE STROKE AND DOT ABOVE + +0087D +ARABIC LETTER ALEF WITH ATTACHED BOTTOM RIGHT KASRA AND DOT ABOVE + +0087E +ARABIC LETTER ALEF WITH ATTACHED TOP RIGHT FATHA AND LEFT RING + +0087F +ARABIC LETTER ALEF WITH RIGHT MIDDLE STROKE AND LEFT RING + +00880 +ARABIC LETTER ALEF WITH ATTACHED BOTTOM RIGHT KASRA AND LEFT RING + +00881 +ARABIC LETTER ALEF WITH ATTACHED RIGHT HAMZA + +00882 +ARABIC LETTER ALEF WITH ATTACHED LEFT HAMZA + +00883 +ARABIC TATWEEL WITH OVERSTRUCK HAMZA + +00884 +ARABIC TATWEEL WITH OVERSTRUCK WAW + +00885 +ARABIC TATWEEL WITH TWO DOTS BELOW + +00886 +ARABIC LETTER THIN YEH + +00887 +ARABIC BASELINE ROUND DOT + +00888 +ARABIC RAISED ROUND DOT + +00889 +ARABIC LETTER NOON WITH INVERTED SMALL V + +0088A +ARABIC LETTER HAH WITH INVERTED SMALL V BELOW + +0088B +ARABIC LETTER TAH WITH DOT BELOW + +0088C +ARABIC LETTER TAH WITH THREE DOTS BELOW + +0088D +ARABIC LETTER KEHEH WITH TWO DOTS VERTICALLY BELOW + +0088E +ARABIC VERTICAL TAIL + +0088F +ARABIC LETTER NOON WITH RING ABOVE + +00890 +ARABIC POUND MARK ABOVE + +00891 +ARABIC PIASTRE MARK ABOVE + +00897 +ARABIC PEPET + +00898 +ARABIC SMALL HIGH WORD AL-JUZ + +00899 +ARABIC SMALL LOW WORD ISHMAAM + +0089A +ARABIC SMALL LOW WORD IMAALA + +0089B +ARABIC SMALL LOW WORD TASHEEL + +0089C +ARABIC MADDA WAAJIB + +0089D +ARABIC SUPERSCRIPT ALEF MOKHASSAS + +0089E +ARABIC DOUBLED MADDA + +0089F +ARABIC HALF MADDA OVER MADDA + +008A0 +ARABIC LETTER BEH WITH SMALL V BELOW + +008A1 +ARABIC LETTER BEH WITH HAMZA ABOVE + +008A2 +ARABIC LETTER JEEM WITH TWO DOTS ABOVE + +008A3 +ARABIC LETTER TAH WITH TWO DOTS ABOVE + +008A4 +ARABIC LETTER FEH WITH DOT BELOW AND THREE DOTS ABOVE + +008A5 +ARABIC LETTER QAF WITH DOT BELOW + +008A6 +ARABIC LETTER LAM WITH DOUBLE BAR + +008A7 +ARABIC LETTER MEEM WITH THREE DOTS ABOVE + +008A8 +ARABIC LETTER YEH WITH TWO DOTS BELOW AND HAMZA ABOVE + +008A9 +ARABIC LETTER YEH WITH TWO DOTS BELOW AND DOT ABOVE + +008AA +ARABIC LETTER REH WITH LOOP + +008AB +ARABIC LETTER WAW WITH DOT WITHIN + +008AC +ARABIC LETTER ROHINGYA YEH + +008AD +ARABIC LETTER LOW ALEF + +008AE +ARABIC LETTER DAL WITH THREE DOTS BELOW + +008AF +ARABIC LETTER SAD WITH THREE DOTS BELOW + +008B0 +ARABIC LETTER GAF WITH INVERTED STROKE + +008B1 +ARABIC LETTER STRAIGHT WAW + +008B2 +ARABIC LETTER ZAIN WITH INVERTED V ABOVE + +008B3 +ARABIC LETTER AIN WITH THREE DOTS BELOW + +008B4 +ARABIC LETTER KAF WITH DOT BELOW + +008B5 +ARABIC LETTER QAF WITH DOT BELOW AND NO DOTS ABOVE + +008B6 +ARABIC LETTER BEH WITH SMALL MEEM ABOVE + +008B7 +ARABIC LETTER PEH WITH SMALL MEEM ABOVE + +008B8 +ARABIC LETTER TEH WITH SMALL TEH ABOVE + +008B9 +ARABIC LETTER REH WITH SMALL NOON ABOVE + +008BA +ARABIC LETTER YEH WITH TWO DOTS BELOW AND SMALL NOON ABOVE + +008BB +ARABIC LETTER AFRICAN FEH + +008BC +ARABIC LETTER AFRICAN QAF + +008BD +ARABIC LETTER AFRICAN NOON + +008BE +ARABIC LETTER PEH WITH SMALL V + +008BF +ARABIC LETTER TEH WITH SMALL V + +008C0 +ARABIC LETTER TTEH WITH SMALL V + +008C1 +ARABIC LETTER TCHEH WITH SMALL V + +008C2 +ARABIC LETTER KEHEH WITH SMALL V + +008C3 +ARABIC LETTER GHAIN WITH THREE DOTS ABOVE + +008C4 +ARABIC LETTER AFRICAN QAF WITH THREE DOTS ABOVE + +008C5 +ARABIC LETTER JEEM WITH THREE DOTS ABOVE + +008C6 +ARABIC LETTER JEEM WITH THREE DOTS BELOW + +008C7 +ARABIC LETTER LAM WITH SMALL ARABIC LETTER TAH ABOVE + +008C8 +ARABIC LETTER GRAF + +008C9 +ARABIC SMALL FARSI YEH + +008CA +ARABIC SMALL HIGH FARSI YEH + +008CB +ARABIC SMALL HIGH YEH BARREE WITH TWO DOTS BELOW + +008CC +ARABIC SMALL HIGH WORD SAH + +008CD +ARABIC SMALL HIGH ZAH + +008CE +ARABIC LARGE ROUND DOT ABOVE + +008CF +ARABIC LARGE ROUND DOT BELOW + +008D0 +ARABIC SUKUN BELOW + +008D1 +ARABIC LARGE CIRCLE BELOW + +008D2 +ARABIC LARGE ROUND DOT INSIDE CIRCLE BELOW + +008D3 +ARABIC SMALL LOW WAW + +008D4 +ARABIC SMALL HIGH WORD AR-RUB + +008D5 +ARABIC SMALL HIGH SAD + +008D6 +ARABIC SMALL HIGH AIN + +008D7 +ARABIC SMALL HIGH QAF + +008D8 +ARABIC SMALL HIGH NOON WITH KASRA + +008D9 +ARABIC SMALL LOW NOON WITH KASRA + +008DA +ARABIC SMALL HIGH WORD ATH-THALATHA + +008DB +ARABIC SMALL HIGH WORD AS-SAJDA + +008DC +ARABIC SMALL HIGH WORD AN-NISF + +008DD +ARABIC SMALL HIGH WORD SAKTA + +008DE +ARABIC SMALL HIGH WORD QIF + +008DF +ARABIC SMALL HIGH WORD WAQFA + +008E0 +ARABIC SMALL HIGH FOOTNOTE MARKER + +008E1 +ARABIC SMALL HIGH SIGN SAFHA + +008E2 +ARABIC DISPUTED END OF AYAH + +008E3 +ARABIC TURNED DAMMA BELOW + +008E4 +ARABIC CURLY FATHA + +008E5 +ARABIC CURLY DAMMA + +008E6 +ARABIC CURLY KASRA + +008E7 +ARABIC CURLY FATHATAN + +008E8 +ARABIC CURLY DAMMATAN + +008E9 +ARABIC CURLY KASRATAN + +008EA +ARABIC TONE ONE DOT ABOVE + +008EB +ARABIC TONE TWO DOTS ABOVE + +008EC +ARABIC TONE LOOP ABOVE + +008ED +ARABIC TONE ONE DOT BELOW + +008EE +ARABIC TONE TWO DOTS BELOW + +008EF +ARABIC TONE LOOP BELOW + +008F0 +ARABIC OPEN FATHATAN + +008F1 +ARABIC OPEN DAMMATAN + +008F2 +ARABIC OPEN KASRATAN + +008F3 +ARABIC SMALL HIGH WAW + +008F4 +ARABIC FATHA WITH RING + +008F5 +ARABIC FATHA WITH DOT ABOVE + +008F6 +ARABIC KASRA WITH DOT BELOW + +008F7 +ARABIC LEFT ARROWHEAD ABOVE + +008F8 +ARABIC RIGHT ARROWHEAD ABOVE + +008F9 +ARABIC LEFT ARROWHEAD BELOW + +008FA +ARABIC RIGHT ARROWHEAD BELOW + +008FB +ARABIC DOUBLE RIGHT ARROWHEAD ABOVE + +008FC +ARABIC DOUBLE RIGHT ARROWHEAD ABOVE WITH DOT + +008FD +ARABIC RIGHT ARROWHEAD ABOVE WITH DOT + +008FE +ARABIC DAMMA WITH DOT + +008FF +ARABIC MARK SIDEWAYS NOON GHUNNA + +00900 +DEVANAGARI SIGN INVERTED CANDRABINDU + +00901 +DEVANAGARI SIGN CANDRABINDU + +00902 +DEVANAGARI SIGN ANUSVARA + +00903 +DEVANAGARI SIGN VISARGA + +00904 +DEVANAGARI LETTER SHORT A + +00905 +DEVANAGARI LETTER A + +00906 +DEVANAGARI LETTER AA + +00907 +DEVANAGARI LETTER I + +00908 +DEVANAGARI LETTER II + +00909 +DEVANAGARI LETTER U + +0090A +DEVANAGARI LETTER UU + +0090B +DEVANAGARI LETTER VOCALIC R + +0090C +DEVANAGARI LETTER VOCALIC L + +0090D +DEVANAGARI LETTER CANDRA E + +0090E +DEVANAGARI LETTER SHORT E + +0090F +DEVANAGARI LETTER E + +00910 +DEVANAGARI LETTER AI + +00911 +DEVANAGARI LETTER CANDRA O + +00912 +DEVANAGARI LETTER SHORT O + +00913 +DEVANAGARI LETTER O + +00914 +DEVANAGARI LETTER AU + +00915 +DEVANAGARI LETTER KA + +00916 +DEVANAGARI LETTER KHA + +00917 +DEVANAGARI LETTER GA + +00918 +DEVANAGARI LETTER GHA + +00919 +DEVANAGARI LETTER NGA + +0091A +DEVANAGARI LETTER CA + +0091B +DEVANAGARI LETTER CHA + +0091C +DEVANAGARI LETTER JA + +0091D +DEVANAGARI LETTER JHA + +0091E +DEVANAGARI LETTER NYA + +0091F +DEVANAGARI LETTER TTA + +00920 +DEVANAGARI LETTER TTHA + +00921 +DEVANAGARI LETTER DDA + +00922 +DEVANAGARI LETTER DDHA + +00923 +DEVANAGARI LETTER NNA + +00924 +DEVANAGARI LETTER TA + +00925 +DEVANAGARI LETTER THA + +00926 +DEVANAGARI LETTER DA + +00927 +DEVANAGARI LETTER DHA + +00928 +DEVANAGARI LETTER NA + +00929 +DEVANAGARI LETTER NNNA + +0092A +DEVANAGARI LETTER PA + +0092B +DEVANAGARI LETTER PHA + +0092C +DEVANAGARI LETTER BA + +0092D +DEVANAGARI LETTER BHA + +0092E +DEVANAGARI LETTER MA + +0092F +DEVANAGARI LETTER YA + +00930 +DEVANAGARI LETTER RA + +00931 +DEVANAGARI LETTER RRA + +00932 +DEVANAGARI LETTER LA + +00933 +DEVANAGARI LETTER LLA + +00934 +DEVANAGARI LETTER LLLA + +00935 +DEVANAGARI LETTER VA + +00936 +DEVANAGARI LETTER SHA + +00937 +DEVANAGARI LETTER SSA + +00938 +DEVANAGARI LETTER SA + +00939 +DEVANAGARI LETTER HA + +0093A +DEVANAGARI VOWEL SIGN OE + +0093B +DEVANAGARI VOWEL SIGN OOE + +0093C +DEVANAGARI SIGN NUKTA + +0093D +DEVANAGARI SIGN AVAGRAHA + +0093E +DEVANAGARI VOWEL SIGN AA + +0093F +DEVANAGARI VOWEL SIGN I + +00940 +DEVANAGARI VOWEL SIGN II + +00941 +DEVANAGARI VOWEL SIGN U + +00942 +DEVANAGARI VOWEL SIGN UU + +00943 +DEVANAGARI VOWEL SIGN VOCALIC R + +00944 +DEVANAGARI VOWEL SIGN VOCALIC RR + +00945 +DEVANAGARI VOWEL SIGN CANDRA E + +00946 +DEVANAGARI VOWEL SIGN SHORT E + +00947 +DEVANAGARI VOWEL SIGN E + +00948 +DEVANAGARI VOWEL SIGN AI + +00949 +DEVANAGARI VOWEL SIGN CANDRA O + +0094A +DEVANAGARI VOWEL SIGN SHORT O + +0094B +DEVANAGARI VOWEL SIGN O + +0094C +DEVANAGARI VOWEL SIGN AU + +0094D +DEVANAGARI SIGN VIRAMA + +0094E +DEVANAGARI VOWEL SIGN PRISHTHAMATRA E + +0094F +DEVANAGARI VOWEL SIGN AW + +00950 +DEVANAGARI OM + +00951 +DEVANAGARI STRESS SIGN UDATTA + +00952 +DEVANAGARI STRESS SIGN ANUDATTA + +00953 +DEVANAGARI GRAVE ACCENT + +00954 +DEVANAGARI ACUTE ACCENT + +00955 +DEVANAGARI VOWEL SIGN CANDRA LONG E + +00956 +DEVANAGARI VOWEL SIGN UE + +00957 +DEVANAGARI VOWEL SIGN UUE + +00958 +DEVANAGARI LETTER QA + +00959 +DEVANAGARI LETTER KHHA + +0095A +DEVANAGARI LETTER GHHA + +0095B +DEVANAGARI LETTER ZA + +0095C +DEVANAGARI LETTER DDDHA + +0095D +DEVANAGARI LETTER RHA + +0095E +DEVANAGARI LETTER FA + +0095F +DEVANAGARI LETTER YYA + +00960 +DEVANAGARI LETTER VOCALIC RR + +00961 +DEVANAGARI LETTER VOCALIC LL + +00962 +DEVANAGARI VOWEL SIGN VOCALIC L + +00963 +DEVANAGARI VOWEL SIGN VOCALIC LL + +00964 +DEVANAGARI DANDA + +00965 +DEVANAGARI DOUBLE DANDA + +00966 +DEVANAGARI DIGIT ZERO + +00967 +DEVANAGARI DIGIT ONE + +00968 +DEVANAGARI DIGIT TWO + +00969 +DEVANAGARI DIGIT THREE + +0096A +DEVANAGARI DIGIT FOUR + +0096B +DEVANAGARI DIGIT FIVE + +0096C +DEVANAGARI DIGIT SIX + +0096D +DEVANAGARI DIGIT SEVEN + +0096E +DEVANAGARI DIGIT EIGHT + +0096F +DEVANAGARI DIGIT NINE + +00970 +DEVANAGARI ABBREVIATION SIGN + +00971 +DEVANAGARI SIGN HIGH SPACING DOT + +00972 +DEVANAGARI LETTER CANDRA A + +00973 +DEVANAGARI LETTER OE + +00974 +DEVANAGARI LETTER OOE + +00975 +DEVANAGARI LETTER AW + +00976 +DEVANAGARI LETTER UE + +00977 +DEVANAGARI LETTER UUE + +00978 +DEVANAGARI LETTER MARWARI DDA + +00979 +DEVANAGARI LETTER ZHA + +0097A +DEVANAGARI LETTER HEAVY YA + +0097B +DEVANAGARI LETTER GGA + +0097C +DEVANAGARI LETTER JJA + +0097D +DEVANAGARI LETTER GLOTTAL STOP + +0097E +DEVANAGARI LETTER DDDA + +0097F +DEVANAGARI LETTER BBA + +00980 +BENGALI ANJI + +00981 +BENGALI SIGN CANDRABINDU + +00982 +BENGALI SIGN ANUSVARA + +00983 +BENGALI SIGN VISARGA + +00985 +BENGALI LETTER A + +00986 +BENGALI LETTER AA + +00987 +BENGALI LETTER I + +00988 +BENGALI LETTER II + +00989 +BENGALI LETTER U + +0098A +BENGALI LETTER UU + +0098B +BENGALI LETTER VOCALIC R + +0098C +BENGALI LETTER VOCALIC L + +0098F +BENGALI LETTER E + +00990 +BENGALI LETTER AI + +00993 +BENGALI LETTER O + +00994 +BENGALI LETTER AU + +00995 +BENGALI LETTER KA + +00996 +BENGALI LETTER KHA + +00997 +BENGALI LETTER GA + +00998 +BENGALI LETTER GHA + +00999 +BENGALI LETTER NGA + +0099A +BENGALI LETTER CA + +0099B +BENGALI LETTER CHA + +0099C +BENGALI LETTER JA + +0099D +BENGALI LETTER JHA + +0099E +BENGALI LETTER NYA + +0099F +BENGALI LETTER TTA + +009A0 +BENGALI LETTER TTHA + +009A1 +BENGALI LETTER DDA + +009A2 +BENGALI LETTER DDHA + +009A3 +BENGALI LETTER NNA + +009A4 +BENGALI LETTER TA + +009A5 +BENGALI LETTER THA + +009A6 +BENGALI LETTER DA + +009A7 +BENGALI LETTER DHA + +009A8 +BENGALI LETTER NA + +009AA +BENGALI LETTER PA + +009AB +BENGALI LETTER PHA + +009AC +BENGALI LETTER BA + +009AD +BENGALI LETTER BHA + +009AE +BENGALI LETTER MA + +009AF +BENGALI LETTER YA + +009B0 +BENGALI LETTER RA + +009B2 +BENGALI LETTER LA + +009B6 +BENGALI LETTER SHA + +009B7 +BENGALI LETTER SSA + +009B8 +BENGALI LETTER SA + +009B9 +BENGALI LETTER HA + +009BC +BENGALI SIGN NUKTA + +009BD +BENGALI SIGN AVAGRAHA + +009BE +BENGALI VOWEL SIGN AA + +009BF +BENGALI VOWEL SIGN I + +009C0 +BENGALI VOWEL SIGN II + +009C1 +BENGALI VOWEL SIGN U + +009C2 +BENGALI VOWEL SIGN UU + +009C3 +BENGALI VOWEL SIGN VOCALIC R + +009C4 +BENGALI VOWEL SIGN VOCALIC RR + +009C7 +BENGALI VOWEL SIGN E + +009C8 +BENGALI VOWEL SIGN AI + +009CB +BENGALI VOWEL SIGN O + +009CC +BENGALI VOWEL SIGN AU + +009CD +BENGALI SIGN VIRAMA + +009CE +BENGALI LETTER KHANDA TA + +009D7 +BENGALI AU LENGTH MARK + +009DC +BENGALI LETTER RRA + +009DD +BENGALI LETTER RHA + +009DF +BENGALI LETTER YYA + +009E0 +BENGALI LETTER VOCALIC RR + +009E1 +BENGALI LETTER VOCALIC LL + +009E2 +BENGALI VOWEL SIGN VOCALIC L + +009E3 +BENGALI VOWEL SIGN VOCALIC LL + +009E6 +BENGALI DIGIT ZERO + +009E7 +BENGALI DIGIT ONE + +009E8 +BENGALI DIGIT TWO + +009E9 +BENGALI DIGIT THREE + +009EA +BENGALI DIGIT FOUR + +009EB +BENGALI DIGIT FIVE + +009EC +BENGALI DIGIT SIX + +009ED +BENGALI DIGIT SEVEN + +009EE +BENGALI DIGIT EIGHT + +009EF +BENGALI DIGIT NINE + +009F0 +BENGALI LETTER RA WITH MIDDLE DIAGONAL + +009F1 +BENGALI LETTER RA WITH LOWER DIAGONAL + +009F2 +BENGALI RUPEE MARK + +009F3 +BENGALI RUPEE SIGN + +009F4 +BENGALI CURRENCY NUMERATOR ONE + +009F5 +BENGALI CURRENCY NUMERATOR TWO + +009F6 +BENGALI CURRENCY NUMERATOR THREE + +009F7 +BENGALI CURRENCY NUMERATOR FOUR + +009F8 +BENGALI CURRENCY NUMERATOR ONE LESS THAN THE DENOMINATOR + +009F9 +BENGALI CURRENCY DENOMINATOR SIXTEEN + +009FA +BENGALI ISSHAR + +009FB +BENGALI GANDA MARK + +009FC +BENGALI LETTER VEDIC ANUSVARA + +009FD +BENGALI ABBREVIATION SIGN + +009FE +BENGALI SANDHI MARK + +00A01 +GURMUKHI SIGN ADAK BINDI + +00A02 +GURMUKHI SIGN BINDI + +00A03 +GURMUKHI SIGN VISARGA + +00A05 +GURMUKHI LETTER A + +00A06 +GURMUKHI LETTER AA + +00A07 +GURMUKHI LETTER I + +00A08 +GURMUKHI LETTER II + +00A09 +GURMUKHI LETTER U + +00A0A +GURMUKHI LETTER UU + +00A0F +GURMUKHI LETTER EE + +00A10 +GURMUKHI LETTER AI + +00A13 +GURMUKHI LETTER OO + +00A14 +GURMUKHI LETTER AU + +00A15 +GURMUKHI LETTER KA + +00A16 +GURMUKHI LETTER KHA + +00A17 +GURMUKHI LETTER GA + +00A18 +GURMUKHI LETTER GHA + +00A19 +GURMUKHI LETTER NGA + +00A1A +GURMUKHI LETTER CA + +00A1B +GURMUKHI LETTER CHA + +00A1C +GURMUKHI LETTER JA + +00A1D +GURMUKHI LETTER JHA + +00A1E +GURMUKHI LETTER NYA + +00A1F +GURMUKHI LETTER TTA + +00A20 +GURMUKHI LETTER TTHA + +00A21 +GURMUKHI LETTER DDA + +00A22 +GURMUKHI LETTER DDHA + +00A23 +GURMUKHI LETTER NNA + +00A24 +GURMUKHI LETTER TA + +00A25 +GURMUKHI LETTER THA + +00A26 +GURMUKHI LETTER DA + +00A27 +GURMUKHI LETTER DHA + +00A28 +GURMUKHI LETTER NA + +00A2A +GURMUKHI LETTER PA + +00A2B +GURMUKHI LETTER PHA + +00A2C +GURMUKHI LETTER BA + +00A2D +GURMUKHI LETTER BHA + +00A2E +GURMUKHI LETTER MA + +00A2F +GURMUKHI LETTER YA + +00A30 +GURMUKHI LETTER RA + +00A32 +GURMUKHI LETTER LA + +00A33 +GURMUKHI LETTER LLA + +00A35 +GURMUKHI LETTER VA + +00A36 +GURMUKHI LETTER SHA + +00A38 +GURMUKHI LETTER SA + +00A39 +GURMUKHI LETTER HA + +00A3C +GURMUKHI SIGN NUKTA + +00A3E +GURMUKHI VOWEL SIGN AA + +00A3F +GURMUKHI VOWEL SIGN I + +00A40 +GURMUKHI VOWEL SIGN II + +00A41 +GURMUKHI VOWEL SIGN U + +00A42 +GURMUKHI VOWEL SIGN UU + +00A47 +GURMUKHI VOWEL SIGN EE + +00A48 +GURMUKHI VOWEL SIGN AI + +00A4B +GURMUKHI VOWEL SIGN OO + +00A4C +GURMUKHI VOWEL SIGN AU + +00A4D +GURMUKHI SIGN VIRAMA + +00A51 +GURMUKHI SIGN UDAAT + +00A59 +GURMUKHI LETTER KHHA + +00A5A +GURMUKHI LETTER GHHA + +00A5B +GURMUKHI LETTER ZA + +00A5C +GURMUKHI LETTER RRA + +00A5E +GURMUKHI LETTER FA + +00A66 +GURMUKHI DIGIT ZERO + +00A67 +GURMUKHI DIGIT ONE + +00A68 +GURMUKHI DIGIT TWO + +00A69 +GURMUKHI DIGIT THREE + +00A6A +GURMUKHI DIGIT FOUR + +00A6B +GURMUKHI DIGIT FIVE + +00A6C +GURMUKHI DIGIT SIX + +00A6D +GURMUKHI DIGIT SEVEN + +00A6E +GURMUKHI DIGIT EIGHT + +00A6F +GURMUKHI DIGIT NINE + +00A70 +GURMUKHI TIPPI + +00A71 +GURMUKHI ADDAK + +00A72 +GURMUKHI IRI + +00A73 +GURMUKHI URA + +00A74 +GURMUKHI EK ONKAR + +00A75 +GURMUKHI SIGN YAKASH + +00A76 +GURMUKHI ABBREVIATION SIGN + +00A81 +GUJARATI SIGN CANDRABINDU + +00A82 +GUJARATI SIGN ANUSVARA + +00A83 +GUJARATI SIGN VISARGA + +00A85 +GUJARATI LETTER A + +00A86 +GUJARATI LETTER AA + +00A87 +GUJARATI LETTER I + +00A88 +GUJARATI LETTER II + +00A89 +GUJARATI LETTER U + +00A8A +GUJARATI LETTER UU + +00A8B +GUJARATI LETTER VOCALIC R + +00A8C +GUJARATI LETTER VOCALIC L + +00A8D +GUJARATI VOWEL CANDRA E + +00A8F +GUJARATI LETTER E + +00A90 +GUJARATI LETTER AI + +00A91 +GUJARATI VOWEL CANDRA O + +00A93 +GUJARATI LETTER O + +00A94 +GUJARATI LETTER AU + +00A95 +GUJARATI LETTER KA + +00A96 +GUJARATI LETTER KHA + +00A97 +GUJARATI LETTER GA + +00A98 +GUJARATI LETTER GHA + +00A99 +GUJARATI LETTER NGA + +00A9A +GUJARATI LETTER CA + +00A9B +GUJARATI LETTER CHA + +00A9C +GUJARATI LETTER JA + +00A9D +GUJARATI LETTER JHA + +00A9E +GUJARATI LETTER NYA + +00A9F +GUJARATI LETTER TTA + +00AA0 +GUJARATI LETTER TTHA + +00AA1 +GUJARATI LETTER DDA + +00AA2 +GUJARATI LETTER DDHA + +00AA3 +GUJARATI LETTER NNA + +00AA4 +GUJARATI LETTER TA + +00AA5 +GUJARATI LETTER THA + +00AA6 +GUJARATI LETTER DA + +00AA7 +GUJARATI LETTER DHA + +00AA8 +GUJARATI LETTER NA + +00AAA +GUJARATI LETTER PA + +00AAB +GUJARATI LETTER PHA + +00AAC +GUJARATI LETTER BA + +00AAD +GUJARATI LETTER BHA + +00AAE +GUJARATI LETTER MA + +00AAF +GUJARATI LETTER YA + +00AB0 +GUJARATI LETTER RA + +00AB2 +GUJARATI LETTER LA + +00AB3 +GUJARATI LETTER LLA + +00AB5 +GUJARATI LETTER VA + +00AB6 +GUJARATI LETTER SHA + +00AB7 +GUJARATI LETTER SSA + +00AB8 +GUJARATI LETTER SA + +00AB9 +GUJARATI LETTER HA + +00ABC +GUJARATI SIGN NUKTA + +00ABD +GUJARATI SIGN AVAGRAHA + +00ABE +GUJARATI VOWEL SIGN AA + +00ABF +GUJARATI VOWEL SIGN I + +00AC0 +GUJARATI VOWEL SIGN II + +00AC1 +GUJARATI VOWEL SIGN U + +00AC2 +GUJARATI VOWEL SIGN UU + +00AC3 +GUJARATI VOWEL SIGN VOCALIC R + +00AC4 +GUJARATI VOWEL SIGN VOCALIC RR + +00AC5 +GUJARATI VOWEL SIGN CANDRA E + +00AC7 +GUJARATI VOWEL SIGN E + +00AC8 +GUJARATI VOWEL SIGN AI + +00AC9 +GUJARATI VOWEL SIGN CANDRA O + +00ACB +GUJARATI VOWEL SIGN O + +00ACC +GUJARATI VOWEL SIGN AU + +00ACD +GUJARATI SIGN VIRAMA + +00AD0 +GUJARATI OM + +00AE0 +GUJARATI LETTER VOCALIC RR + +00AE1 +GUJARATI LETTER VOCALIC LL + +00AE2 +GUJARATI VOWEL SIGN VOCALIC L + +00AE3 +GUJARATI VOWEL SIGN VOCALIC LL + +00AE6 +GUJARATI DIGIT ZERO + +00AE7 +GUJARATI DIGIT ONE + +00AE8 +GUJARATI DIGIT TWO + +00AE9 +GUJARATI DIGIT THREE + +00AEA +GUJARATI DIGIT FOUR + +00AEB +GUJARATI DIGIT FIVE + +00AEC +GUJARATI DIGIT SIX + +00AED +GUJARATI DIGIT SEVEN + +00AEE +GUJARATI DIGIT EIGHT + +00AEF +GUJARATI DIGIT NINE + +00AF0 +GUJARATI ABBREVIATION SIGN + +00AF1 +GUJARATI RUPEE SIGN + +00AF9 +GUJARATI LETTER ZHA + +00AFA +GUJARATI SIGN SUKUN + +00AFB +GUJARATI SIGN SHADDA + +00AFC +GUJARATI SIGN MADDAH + +00AFD +GUJARATI SIGN THREE-DOT NUKTA ABOVE + +00AFE +GUJARATI SIGN CIRCLE NUKTA ABOVE + +00AFF +GUJARATI SIGN TWO-CIRCLE NUKTA ABOVE + +00B01 +ORIYA SIGN CANDRABINDU + +00B02 +ORIYA SIGN ANUSVARA + +00B03 +ORIYA SIGN VISARGA + +00B05 +ORIYA LETTER A + +00B06 +ORIYA LETTER AA + +00B07 +ORIYA LETTER I + +00B08 +ORIYA LETTER II + +00B09 +ORIYA LETTER U + +00B0A +ORIYA LETTER UU + +00B0B +ORIYA LETTER VOCALIC R + +00B0C +ORIYA LETTER VOCALIC L + +00B0F +ORIYA LETTER E + +00B10 +ORIYA LETTER AI + +00B13 +ORIYA LETTER O + +00B14 +ORIYA LETTER AU + +00B15 +ORIYA LETTER KA + +00B16 +ORIYA LETTER KHA + +00B17 +ORIYA LETTER GA + +00B18 +ORIYA LETTER GHA + +00B19 +ORIYA LETTER NGA + +00B1A +ORIYA LETTER CA + +00B1B +ORIYA LETTER CHA + +00B1C +ORIYA LETTER JA + +00B1D +ORIYA LETTER JHA + +00B1E +ORIYA LETTER NYA + +00B1F +ORIYA LETTER TTA + +00B20 +ORIYA LETTER TTHA + +00B21 +ORIYA LETTER DDA + +00B22 +ORIYA LETTER DDHA + +00B23 +ORIYA LETTER NNA + +00B24 +ORIYA LETTER TA + +00B25 +ORIYA LETTER THA + +00B26 +ORIYA LETTER DA + +00B27 +ORIYA LETTER DHA + +00B28 +ORIYA LETTER NA + +00B2A +ORIYA LETTER PA + +00B2B +ORIYA LETTER PHA + +00B2C +ORIYA LETTER BA + +00B2D +ORIYA LETTER BHA + +00B2E +ORIYA LETTER MA + +00B2F +ORIYA LETTER YA + +00B30 +ORIYA LETTER RA + +00B32 +ORIYA LETTER LA + +00B33 +ORIYA LETTER LLA + +00B35 +ORIYA LETTER VA + +00B36 +ORIYA LETTER SHA + +00B37 +ORIYA LETTER SSA + +00B38 +ORIYA LETTER SA + +00B39 +ORIYA LETTER HA + +00B3C +ORIYA SIGN NUKTA + +00B3D +ORIYA SIGN AVAGRAHA + +00B3E +ORIYA VOWEL SIGN AA + +00B3F +ORIYA VOWEL SIGN I + +00B40 +ORIYA VOWEL SIGN II + +00B41 +ORIYA VOWEL SIGN U + +00B42 +ORIYA VOWEL SIGN UU + +00B43 +ORIYA VOWEL SIGN VOCALIC R + +00B44 +ORIYA VOWEL SIGN VOCALIC RR + +00B47 +ORIYA VOWEL SIGN E + +00B48 +ORIYA VOWEL SIGN AI + +00B4B +ORIYA VOWEL SIGN O + +00B4C +ORIYA VOWEL SIGN AU + +00B4D +ORIYA SIGN VIRAMA + +00B55 +ORIYA SIGN OVERLINE + +00B56 +ORIYA AI LENGTH MARK + +00B57 +ORIYA AU LENGTH MARK + +00B5C +ORIYA LETTER RRA + +00B5D +ORIYA LETTER RHA + +00B5F +ORIYA LETTER YYA + +00B60 +ORIYA LETTER VOCALIC RR + +00B61 +ORIYA LETTER VOCALIC LL + +00B62 +ORIYA VOWEL SIGN VOCALIC L + +00B63 +ORIYA VOWEL SIGN VOCALIC LL + +00B66 +ORIYA DIGIT ZERO + +00B67 +ORIYA DIGIT ONE + +00B68 +ORIYA DIGIT TWO + +00B69 +ORIYA DIGIT THREE + +00B6A +ORIYA DIGIT FOUR + +00B6B +ORIYA DIGIT FIVE + +00B6C +ORIYA DIGIT SIX + +00B6D +ORIYA DIGIT SEVEN + +00B6E +ORIYA DIGIT EIGHT + +00B6F +ORIYA DIGIT NINE + +00B70 +ORIYA ISSHAR + +00B71 +ORIYA LETTER WA + +00B72 +ORIYA FRACTION ONE QUARTER + +00B73 +ORIYA FRACTION ONE HALF + +00B74 +ORIYA FRACTION THREE QUARTERS + +00B75 +ORIYA FRACTION ONE SIXTEENTH + +00B76 +ORIYA FRACTION ONE EIGHTH + +00B77 +ORIYA FRACTION THREE SIXTEENTHS + +00B82 +TAMIL SIGN ANUSVARA + +00B83 +TAMIL SIGN VISARGA + +00B85 +TAMIL LETTER A + +00B86 +TAMIL LETTER AA + +00B87 +TAMIL LETTER I + +00B88 +TAMIL LETTER II + +00B89 +TAMIL LETTER U + +00B8A +TAMIL LETTER UU + +00B8E +TAMIL LETTER E + +00B8F +TAMIL LETTER EE + +00B90 +TAMIL LETTER AI + +00B92 +TAMIL LETTER O + +00B93 +TAMIL LETTER OO + +00B94 +TAMIL LETTER AU + +00B95 +TAMIL LETTER KA + +00B99 +TAMIL LETTER NGA + +00B9A +TAMIL LETTER CA + +00B9C +TAMIL LETTER JA + +00B9E +TAMIL LETTER NYA + +00B9F +TAMIL LETTER TTA + +00BA3 +TAMIL LETTER NNA + +00BA4 +TAMIL LETTER TA + +00BA8 +TAMIL LETTER NA + +00BA9 +TAMIL LETTER NNNA + +00BAA +TAMIL LETTER PA + +00BAE +TAMIL LETTER MA + +00BAF +TAMIL LETTER YA + +00BB0 +TAMIL LETTER RA + +00BB1 +TAMIL LETTER RRA + +00BB2 +TAMIL LETTER LA + +00BB3 +TAMIL LETTER LLA + +00BB4 +TAMIL LETTER LLLA + +00BB5 +TAMIL LETTER VA + +00BB6 +TAMIL LETTER SHA + +00BB7 +TAMIL LETTER SSA + +00BB8 +TAMIL LETTER SA + +00BB9 +TAMIL LETTER HA + +00BBE +TAMIL VOWEL SIGN AA + +00BBF +TAMIL VOWEL SIGN I + +00BC0 +TAMIL VOWEL SIGN II + +00BC1 +TAMIL VOWEL SIGN U + +00BC2 +TAMIL VOWEL SIGN UU + +00BC6 +TAMIL VOWEL SIGN E + +00BC7 +TAMIL VOWEL SIGN EE + +00BC8 +TAMIL VOWEL SIGN AI + +00BCA +TAMIL VOWEL SIGN O + +00BCB +TAMIL VOWEL SIGN OO + +00BCC +TAMIL VOWEL SIGN AU + +00BCD +TAMIL SIGN VIRAMA + +00BD0 +TAMIL OM + +00BD7 +TAMIL AU LENGTH MARK + +00BE6 +TAMIL DIGIT ZERO + +00BE7 +TAMIL DIGIT ONE + +00BE8 +TAMIL DIGIT TWO + +00BE9 +TAMIL DIGIT THREE + +00BEA +TAMIL DIGIT FOUR + +00BEB +TAMIL DIGIT FIVE + +00BEC +TAMIL DIGIT SIX + +00BED +TAMIL DIGIT SEVEN + +00BEE +TAMIL DIGIT EIGHT + +00BEF +TAMIL DIGIT NINE + +00BF0 +TAMIL NUMBER TEN + +00BF1 +TAMIL NUMBER ONE HUNDRED + +00BF2 +TAMIL NUMBER ONE THOUSAND + +00BF3 +TAMIL DAY SIGN + +00BF4 +TAMIL MONTH SIGN + +00BF5 +TAMIL YEAR SIGN + +00BF6 +TAMIL DEBIT SIGN + +00BF7 +TAMIL CREDIT SIGN + +00BF8 +TAMIL AS ABOVE SIGN + +00BF9 +TAMIL RUPEE SIGN + +00BFA +TAMIL NUMBER SIGN + +00C00 +TELUGU SIGN COMBINING CANDRABINDU ABOVE + +00C01 +TELUGU SIGN CANDRABINDU + +00C02 +TELUGU SIGN ANUSVARA + +00C03 +TELUGU SIGN VISARGA + +00C04 +TELUGU SIGN COMBINING ANUSVARA ABOVE + +00C05 +TELUGU LETTER A + +00C06 +TELUGU LETTER AA + +00C07 +TELUGU LETTER I + +00C08 +TELUGU LETTER II + +00C09 +TELUGU LETTER U + +00C0A +TELUGU LETTER UU + +00C0B +TELUGU LETTER VOCALIC R + +00C0C +TELUGU LETTER VOCALIC L + +00C0E +TELUGU LETTER E + +00C0F +TELUGU LETTER EE + +00C10 +TELUGU LETTER AI + +00C12 +TELUGU LETTER O + +00C13 +TELUGU LETTER OO + +00C14 +TELUGU LETTER AU + +00C15 +TELUGU LETTER KA + +00C16 +TELUGU LETTER KHA + +00C17 +TELUGU LETTER GA + +00C18 +TELUGU LETTER GHA + +00C19 +TELUGU LETTER NGA + +00C1A +TELUGU LETTER CA + +00C1B +TELUGU LETTER CHA + +00C1C +TELUGU LETTER JA + +00C1D +TELUGU LETTER JHA + +00C1E +TELUGU LETTER NYA + +00C1F +TELUGU LETTER TTA + +00C20 +TELUGU LETTER TTHA + +00C21 +TELUGU LETTER DDA + +00C22 +TELUGU LETTER DDHA + +00C23 +TELUGU LETTER NNA + +00C24 +TELUGU LETTER TA + +00C25 +TELUGU LETTER THA + +00C26 +TELUGU LETTER DA + +00C27 +TELUGU LETTER DHA + +00C28 +TELUGU LETTER NA + +00C2A +TELUGU LETTER PA + +00C2B +TELUGU LETTER PHA + +00C2C +TELUGU LETTER BA + +00C2D +TELUGU LETTER BHA + +00C2E +TELUGU LETTER MA + +00C2F +TELUGU LETTER YA + +00C30 +TELUGU LETTER RA + +00C31 +TELUGU LETTER RRA + +00C32 +TELUGU LETTER LA + +00C33 +TELUGU LETTER LLA + +00C34 +TELUGU LETTER LLLA + +00C35 +TELUGU LETTER VA + +00C36 +TELUGU LETTER SHA + +00C37 +TELUGU LETTER SSA + +00C38 +TELUGU LETTER SA + +00C39 +TELUGU LETTER HA + +00C3C +TELUGU SIGN NUKTA + +00C3D +TELUGU SIGN AVAGRAHA + +00C3E +TELUGU VOWEL SIGN AA + +00C3F +TELUGU VOWEL SIGN I + +00C40 +TELUGU VOWEL SIGN II + +00C41 +TELUGU VOWEL SIGN U + +00C42 +TELUGU VOWEL SIGN UU + +00C43 +TELUGU VOWEL SIGN VOCALIC R + +00C44 +TELUGU VOWEL SIGN VOCALIC RR + +00C46 +TELUGU VOWEL SIGN E + +00C47 +TELUGU VOWEL SIGN EE + +00C48 +TELUGU VOWEL SIGN AI + +00C4A +TELUGU VOWEL SIGN O + +00C4B +TELUGU VOWEL SIGN OO + +00C4C +TELUGU VOWEL SIGN AU + +00C4D +TELUGU SIGN VIRAMA + +00C55 +TELUGU LENGTH MARK + +00C56 +TELUGU AI LENGTH MARK + +00C58 +TELUGU LETTER TSA + +00C59 +TELUGU LETTER DZA + +00C5A +TELUGU LETTER RRRA + +00C5C +TELUGU ARCHAIC SHRII + +00C5D +TELUGU LETTER NAKAARA POLLU + +00C60 +TELUGU LETTER VOCALIC RR + +00C61 +TELUGU LETTER VOCALIC LL + +00C62 +TELUGU VOWEL SIGN VOCALIC L + +00C63 +TELUGU VOWEL SIGN VOCALIC LL + +00C66 +TELUGU DIGIT ZERO + +00C67 +TELUGU DIGIT ONE + +00C68 +TELUGU DIGIT TWO + +00C69 +TELUGU DIGIT THREE + +00C6A +TELUGU DIGIT FOUR + +00C6B +TELUGU DIGIT FIVE + +00C6C +TELUGU DIGIT SIX + +00C6D +TELUGU DIGIT SEVEN + +00C6E +TELUGU DIGIT EIGHT + +00C6F +TELUGU DIGIT NINE + +00C77 +TELUGU SIGN SIDDHAM + +00C78 +TELUGU FRACTION DIGIT ZERO FOR ODD POWERS OF FOUR + +00C79 +TELUGU FRACTION DIGIT ONE FOR ODD POWERS OF FOUR + +00C7A +TELUGU FRACTION DIGIT TWO FOR ODD POWERS OF FOUR + +00C7B +TELUGU FRACTION DIGIT THREE FOR ODD POWERS OF FOUR + +00C7C +TELUGU FRACTION DIGIT ONE FOR EVEN POWERS OF FOUR + +00C7D +TELUGU FRACTION DIGIT TWO FOR EVEN POWERS OF FOUR + +00C7E +TELUGU FRACTION DIGIT THREE FOR EVEN POWERS OF FOUR + +00C7F +TELUGU SIGN TUUMU + +00C80 +KANNADA SIGN SPACING CANDRABINDU + +00C81 +KANNADA SIGN CANDRABINDU + +00C82 +KANNADA SIGN ANUSVARA + +00C83 +KANNADA SIGN VISARGA + +00C84 +KANNADA SIGN SIDDHAM + +00C85 +KANNADA LETTER A + +00C86 +KANNADA LETTER AA + +00C87 +KANNADA LETTER I + +00C88 +KANNADA LETTER II + +00C89 +KANNADA LETTER U + +00C8A +KANNADA LETTER UU + +00C8B +KANNADA LETTER VOCALIC R + +00C8C +KANNADA LETTER VOCALIC L + +00C8E +KANNADA LETTER E + +00C8F +KANNADA LETTER EE + +00C90 +KANNADA LETTER AI + +00C92 +KANNADA LETTER O + +00C93 +KANNADA LETTER OO + +00C94 +KANNADA LETTER AU + +00C95 +KANNADA LETTER KA + +00C96 +KANNADA LETTER KHA + +00C97 +KANNADA LETTER GA + +00C98 +KANNADA LETTER GHA + +00C99 +KANNADA LETTER NGA + +00C9A +KANNADA LETTER CA + +00C9B +KANNADA LETTER CHA + +00C9C +KANNADA LETTER JA + +00C9D +KANNADA LETTER JHA + +00C9E +KANNADA LETTER NYA + +00C9F +KANNADA LETTER TTA + +00CA0 +KANNADA LETTER TTHA + +00CA1 +KANNADA LETTER DDA + +00CA2 +KANNADA LETTER DDHA + +00CA3 +KANNADA LETTER NNA + +00CA4 +KANNADA LETTER TA + +00CA5 +KANNADA LETTER THA + +00CA6 +KANNADA LETTER DA + +00CA7 +KANNADA LETTER DHA + +00CA8 +KANNADA LETTER NA + +00CAA +KANNADA LETTER PA + +00CAB +KANNADA LETTER PHA + +00CAC +KANNADA LETTER BA + +00CAD +KANNADA LETTER BHA + +00CAE +KANNADA LETTER MA + +00CAF +KANNADA LETTER YA + +00CB0 +KANNADA LETTER RA + +00CB1 +KANNADA LETTER RRA + +00CB2 +KANNADA LETTER LA + +00CB3 +KANNADA LETTER LLA + +00CB5 +KANNADA LETTER VA + +00CB6 +KANNADA LETTER SHA + +00CB7 +KANNADA LETTER SSA + +00CB8 +KANNADA LETTER SA + +00CB9 +KANNADA LETTER HA + +00CBC +KANNADA SIGN NUKTA + +00CBD +KANNADA SIGN AVAGRAHA + +00CBE +KANNADA VOWEL SIGN AA + +00CBF +KANNADA VOWEL SIGN I + +00CC0 +KANNADA VOWEL SIGN II + +00CC1 +KANNADA VOWEL SIGN U + +00CC2 +KANNADA VOWEL SIGN UU + +00CC3 +KANNADA VOWEL SIGN VOCALIC R + +00CC4 +KANNADA VOWEL SIGN VOCALIC RR + +00CC6 +KANNADA VOWEL SIGN E + +00CC7 +KANNADA VOWEL SIGN EE + +00CC8 +KANNADA VOWEL SIGN AI + +00CCA +KANNADA VOWEL SIGN O + +00CCB +KANNADA VOWEL SIGN OO + +00CCC +KANNADA VOWEL SIGN AU + +00CCD +KANNADA SIGN VIRAMA + +00CD5 +KANNADA LENGTH MARK + +00CD6 +KANNADA AI LENGTH MARK + +00CDC +KANNADA ARCHAIC SHRII + +00CDD +KANNADA LETTER NAKAARA POLLU + +00CDE +KANNADA LETTER LLLA + +00CDE +KANNADA LETTER FA + +00CE0 +KANNADA LETTER VOCALIC RR + +00CE1 +KANNADA LETTER VOCALIC LL + +00CE2 +KANNADA VOWEL SIGN VOCALIC L + +00CE3 +KANNADA VOWEL SIGN VOCALIC LL + +00CE6 +KANNADA DIGIT ZERO + +00CE7 +KANNADA DIGIT ONE + +00CE8 +KANNADA DIGIT TWO + +00CE9 +KANNADA DIGIT THREE + +00CEA +KANNADA DIGIT FOUR + +00CEB +KANNADA DIGIT FIVE + +00CEC +KANNADA DIGIT SIX + +00CED +KANNADA DIGIT SEVEN + +00CEE +KANNADA DIGIT EIGHT + +00CEF +KANNADA DIGIT NINE + +00CF1 +KANNADA SIGN JIHVAMULIYA + +00CF2 +KANNADA SIGN UPADHMANIYA + +00CF3 +KANNADA SIGN COMBINING ANUSVARA ABOVE RIGHT + +00D00 +MALAYALAM SIGN COMBINING ANUSVARA ABOVE + +00D01 +MALAYALAM SIGN CANDRABINDU + +00D02 +MALAYALAM SIGN ANUSVARA + +00D03 +MALAYALAM SIGN VISARGA + +00D04 +MALAYALAM LETTER VEDIC ANUSVARA + +00D05 +MALAYALAM LETTER A + +00D06 +MALAYALAM LETTER AA + +00D07 +MALAYALAM LETTER I + +00D08 +MALAYALAM LETTER II + +00D09 +MALAYALAM LETTER U + +00D0A +MALAYALAM LETTER UU + +00D0B +MALAYALAM LETTER VOCALIC R + +00D0C +MALAYALAM LETTER VOCALIC L + +00D0E +MALAYALAM LETTER E + +00D0F +MALAYALAM LETTER EE + +00D10 +MALAYALAM LETTER AI + +00D12 +MALAYALAM LETTER O + +00D13 +MALAYALAM LETTER OO + +00D14 +MALAYALAM LETTER AU + +00D15 +MALAYALAM LETTER KA + +00D16 +MALAYALAM LETTER KHA + +00D17 +MALAYALAM LETTER GA + +00D18 +MALAYALAM LETTER GHA + +00D19 +MALAYALAM LETTER NGA + +00D1A +MALAYALAM LETTER CA + +00D1B +MALAYALAM LETTER CHA + +00D1C +MALAYALAM LETTER JA + +00D1D +MALAYALAM LETTER JHA + +00D1E +MALAYALAM LETTER NYA + +00D1F +MALAYALAM LETTER TTA + +00D20 +MALAYALAM LETTER TTHA + +00D21 +MALAYALAM LETTER DDA + +00D22 +MALAYALAM LETTER DDHA + +00D23 +MALAYALAM LETTER NNA + +00D24 +MALAYALAM LETTER TA + +00D25 +MALAYALAM LETTER THA + +00D26 +MALAYALAM LETTER DA + +00D27 +MALAYALAM LETTER DHA + +00D28 +MALAYALAM LETTER NA + +00D29 +MALAYALAM LETTER NNNA + +00D2A +MALAYALAM LETTER PA + +00D2B +MALAYALAM LETTER PHA + +00D2C +MALAYALAM LETTER BA + +00D2D +MALAYALAM LETTER BHA + +00D2E +MALAYALAM LETTER MA + +00D2F +MALAYALAM LETTER YA + +00D30 +MALAYALAM LETTER RA + +00D31 +MALAYALAM LETTER RRA + +00D32 +MALAYALAM LETTER LA + +00D33 +MALAYALAM LETTER LLA + +00D34 +MALAYALAM LETTER LLLA + +00D35 +MALAYALAM LETTER VA + +00D36 +MALAYALAM LETTER SHA + +00D37 +MALAYALAM LETTER SSA + +00D38 +MALAYALAM LETTER SA + +00D39 +MALAYALAM LETTER HA + +00D3A +MALAYALAM LETTER TTTA + +00D3B +MALAYALAM SIGN VERTICAL BAR VIRAMA + +00D3C +MALAYALAM SIGN CIRCULAR VIRAMA + +00D3D +MALAYALAM SIGN AVAGRAHA + +00D3E +MALAYALAM VOWEL SIGN AA + +00D3F +MALAYALAM VOWEL SIGN I + +00D40 +MALAYALAM VOWEL SIGN II + +00D41 +MALAYALAM VOWEL SIGN U + +00D42 +MALAYALAM VOWEL SIGN UU + +00D43 +MALAYALAM VOWEL SIGN VOCALIC R + +00D44 +MALAYALAM VOWEL SIGN VOCALIC RR + +00D46 +MALAYALAM VOWEL SIGN E + +00D47 +MALAYALAM VOWEL SIGN EE + +00D48 +MALAYALAM VOWEL SIGN AI + +00D4A +MALAYALAM VOWEL SIGN O + +00D4B +MALAYALAM VOWEL SIGN OO + +00D4C +MALAYALAM VOWEL SIGN AU + +00D4D +MALAYALAM SIGN VIRAMA + +00D4E +MALAYALAM LETTER DOT REPH + +00D4F +MALAYALAM SIGN PARA + +00D54 +MALAYALAM LETTER CHILLU M + +00D55 +MALAYALAM LETTER CHILLU Y + +00D56 +MALAYALAM LETTER CHILLU LLL + +00D57 +MALAYALAM AU LENGTH MARK + +00D58 +MALAYALAM FRACTION ONE ONE-HUNDRED-AND-SIXTIETH + +00D59 +MALAYALAM FRACTION ONE FORTIETH + +00D5A +MALAYALAM FRACTION THREE EIGHTIETHS + +00D5B +MALAYALAM FRACTION ONE TWENTIETH + +00D5C +MALAYALAM FRACTION ONE TENTH + +00D5D +MALAYALAM FRACTION THREE TWENTIETHS + +00D5E +MALAYALAM FRACTION ONE FIFTH + +00D5F +MALAYALAM LETTER ARCHAIC II + +00D60 +MALAYALAM LETTER VOCALIC RR + +00D61 +MALAYALAM LETTER VOCALIC LL + +00D62 +MALAYALAM VOWEL SIGN VOCALIC L + +00D63 +MALAYALAM VOWEL SIGN VOCALIC LL + +00D66 +MALAYALAM DIGIT ZERO + +00D67 +MALAYALAM DIGIT ONE + +00D68 +MALAYALAM DIGIT TWO + +00D69 +MALAYALAM DIGIT THREE + +00D6A +MALAYALAM DIGIT FOUR + +00D6B +MALAYALAM DIGIT FIVE + +00D6C +MALAYALAM DIGIT SIX + +00D6D +MALAYALAM DIGIT SEVEN + +00D6E +MALAYALAM DIGIT EIGHT + +00D6F +MALAYALAM DIGIT NINE + +00D70 +MALAYALAM NUMBER TEN + +00D71 +MALAYALAM NUMBER ONE HUNDRED + +00D72 +MALAYALAM NUMBER ONE THOUSAND + +00D73 +MALAYALAM FRACTION ONE QUARTER + +00D74 +MALAYALAM FRACTION ONE HALF + +00D75 +MALAYALAM FRACTION THREE QUARTERS + +00D76 +MALAYALAM FRACTION ONE SIXTEENTH + +00D77 +MALAYALAM FRACTION ONE EIGHTH + +00D78 +MALAYALAM FRACTION THREE SIXTEENTHS + +00D79 +MALAYALAM DATE MARK + +00D7A +MALAYALAM LETTER CHILLU NN + +00D7B +MALAYALAM LETTER CHILLU N + +00D7C +MALAYALAM LETTER CHILLU RR + +00D7D +MALAYALAM LETTER CHILLU L + +00D7E +MALAYALAM LETTER CHILLU LL + +00D7F +MALAYALAM LETTER CHILLU K + +00D81 +SINHALA SIGN CANDRABINDU + +00D82 +SINHALA SIGN ANUSVARAYA + +00D83 +SINHALA SIGN VISARGAYA + +00D85 +SINHALA LETTER AYANNA + +00D86 +SINHALA LETTER AAYANNA + +00D87 +SINHALA LETTER AEYANNA + +00D88 +SINHALA LETTER AEEYANNA + +00D89 +SINHALA LETTER IYANNA + +00D8A +SINHALA LETTER IIYANNA + +00D8B +SINHALA LETTER UYANNA + +00D8C +SINHALA LETTER UUYANNA + +00D8D +SINHALA LETTER IRUYANNA + +00D8E +SINHALA LETTER IRUUYANNA + +00D8F +SINHALA LETTER ILUYANNA + +00D90 +SINHALA LETTER ILUUYANNA + +00D91 +SINHALA LETTER EYANNA + +00D92 +SINHALA LETTER EEYANNA + +00D93 +SINHALA LETTER AIYANNA + +00D94 +SINHALA LETTER OYANNA + +00D95 +SINHALA LETTER OOYANNA + +00D96 +SINHALA LETTER AUYANNA + +00D9A +SINHALA LETTER ALPAPRAANA KAYANNA + +00D9B +SINHALA LETTER MAHAAPRAANA KAYANNA + +00D9C +SINHALA LETTER ALPAPRAANA GAYANNA + +00D9D +SINHALA LETTER MAHAAPRAANA GAYANNA + +00D9E +SINHALA LETTER KANTAJA NAASIKYAYA + +00D9F +SINHALA LETTER SANYAKA GAYANNA + +00DA0 +SINHALA LETTER ALPAPRAANA CAYANNA + +00DA1 +SINHALA LETTER MAHAAPRAANA CAYANNA + +00DA2 +SINHALA LETTER ALPAPRAANA JAYANNA + +00DA3 +SINHALA LETTER MAHAAPRAANA JAYANNA + +00DA4 +SINHALA LETTER TAALUJA NAASIKYAYA + +00DA5 +SINHALA LETTER TAALUJA SANYOOGA NAAKSIKYAYA + +00DA6 +SINHALA LETTER SANYAKA JAYANNA + +00DA7 +SINHALA LETTER ALPAPRAANA TTAYANNA + +00DA8 +SINHALA LETTER MAHAAPRAANA TTAYANNA + +00DA9 +SINHALA LETTER ALPAPRAANA DDAYANNA + +00DAA +SINHALA LETTER MAHAAPRAANA DDAYANNA + +00DAB +SINHALA LETTER MUURDHAJA NAYANNA + +00DAC +SINHALA LETTER SANYAKA DDAYANNA + +00DAD +SINHALA LETTER ALPAPRAANA TAYANNA + +00DAE +SINHALA LETTER MAHAAPRAANA TAYANNA + +00DAF +SINHALA LETTER ALPAPRAANA DAYANNA + +00DB0 +SINHALA LETTER MAHAAPRAANA DAYANNA + +00DB1 +SINHALA LETTER DANTAJA NAYANNA + +00DB3 +SINHALA LETTER SANYAKA DAYANNA + +00DB4 +SINHALA LETTER ALPAPRAANA PAYANNA + +00DB5 +SINHALA LETTER MAHAAPRAANA PAYANNA + +00DB6 +SINHALA LETTER ALPAPRAANA BAYANNA + +00DB7 +SINHALA LETTER MAHAAPRAANA BAYANNA + +00DB8 +SINHALA LETTER MAYANNA + +00DB9 +SINHALA LETTER AMBA BAYANNA + +00DBA +SINHALA LETTER YAYANNA + +00DBB +SINHALA LETTER RAYANNA + +00DBD +SINHALA LETTER DANTAJA LAYANNA + +00DC0 +SINHALA LETTER VAYANNA + +00DC1 +SINHALA LETTER TAALUJA SAYANNA + +00DC2 +SINHALA LETTER MUURDHAJA SAYANNA + +00DC3 +SINHALA LETTER DANTAJA SAYANNA + +00DC4 +SINHALA LETTER HAYANNA + +00DC5 +SINHALA LETTER MUURDHAJA LAYANNA + +00DC6 +SINHALA LETTER FAYANNA + +00DCA +SINHALA SIGN AL-LAKUNA + +00DCF +SINHALA VOWEL SIGN AELA-PILLA + +00DD0 +SINHALA VOWEL SIGN KETTI AEDA-PILLA + +00DD1 +SINHALA VOWEL SIGN DIGA AEDA-PILLA + +00DD2 +SINHALA VOWEL SIGN KETTI IS-PILLA + +00DD3 +SINHALA VOWEL SIGN DIGA IS-PILLA + +00DD4 +SINHALA VOWEL SIGN KETTI PAA-PILLA + +00DD6 +SINHALA VOWEL SIGN DIGA PAA-PILLA + +00DD8 +SINHALA VOWEL SIGN GAETTA-PILLA + +00DD9 +SINHALA VOWEL SIGN KOMBUVA + +00DDA +SINHALA VOWEL SIGN DIGA KOMBUVA + +00DDB +SINHALA VOWEL SIGN KOMBU DEKA + +00DDC +SINHALA VOWEL SIGN KOMBUVA HAA AELA-PILLA + +00DDD +SINHALA VOWEL SIGN KOMBUVA HAA DIGA AELA-PILLA + +00DDE +SINHALA VOWEL SIGN KOMBUVA HAA GAYANUKITTA + +00DDF +SINHALA VOWEL SIGN GAYANUKITTA + +00DE6 +SINHALA LITH DIGIT ZERO + +00DE7 +SINHALA LITH DIGIT ONE + +00DE8 +SINHALA LITH DIGIT TWO + +00DE9 +SINHALA LITH DIGIT THREE + +00DEA +SINHALA LITH DIGIT FOUR + +00DEB +SINHALA LITH DIGIT FIVE + +00DEC +SINHALA LITH DIGIT SIX + +00DED +SINHALA LITH DIGIT SEVEN + +00DEE +SINHALA LITH DIGIT EIGHT + +00DEF +SINHALA LITH DIGIT NINE + +00DF2 +SINHALA VOWEL SIGN DIGA GAETTA-PILLA + +00DF3 +SINHALA VOWEL SIGN DIGA GAYANUKITTA + +00DF4 +SINHALA PUNCTUATION KUNDDALIYA + +00E01 +THAI CHARACTER KO KAI + +00E02 +THAI CHARACTER KHO KHAI + +00E03 +THAI CHARACTER KHO KHUAT + +00E04 +THAI CHARACTER KHO KHWAI + +00E05 +THAI CHARACTER KHO KHON + +00E06 +THAI CHARACTER KHO RAKHANG + +00E07 +THAI CHARACTER NGO NGU + +00E08 +THAI CHARACTER CHO CHAN + +00E09 +THAI CHARACTER CHO CHING + +00E0A +THAI CHARACTER CHO CHANG + +00E0B +THAI CHARACTER SO SO + +00E0C +THAI CHARACTER CHO CHOE + +00E0D +THAI CHARACTER YO YING + +00E0E +THAI CHARACTER DO CHADA + +00E0F +THAI CHARACTER TO PATAK + +00E10 +THAI CHARACTER THO THAN + +00E11 +THAI CHARACTER THO NANGMONTHO + +00E12 +THAI CHARACTER THO PHUTHAO + +00E13 +THAI CHARACTER NO NEN + +00E14 +THAI CHARACTER DO DEK + +00E15 +THAI CHARACTER TO TAO + +00E16 +THAI CHARACTER THO THUNG + +00E17 +THAI CHARACTER THO THAHAN + +00E18 +THAI CHARACTER THO THONG + +00E19 +THAI CHARACTER NO NU + +00E1A +THAI CHARACTER BO BAIMAI + +00E1B +THAI CHARACTER PO PLA + +00E1C +THAI CHARACTER PHO PHUNG + +00E1D +THAI CHARACTER FO FA + +00E1E +THAI CHARACTER PHO PHAN + +00E1F +THAI CHARACTER FO FAN + +00E20 +THAI CHARACTER PHO SAMPHAO + +00E21 +THAI CHARACTER MO MA + +00E22 +THAI CHARACTER YO YAK + +00E23 +THAI CHARACTER RO RUA + +00E24 +THAI CHARACTER RU + +00E25 +THAI CHARACTER LO LING + +00E26 +THAI CHARACTER LU + +00E27 +THAI CHARACTER WO WAEN + +00E28 +THAI CHARACTER SO SALA + +00E29 +THAI CHARACTER SO RUSI + +00E2A +THAI CHARACTER SO SUA + +00E2B +THAI CHARACTER HO HIP + +00E2C +THAI CHARACTER LO CHULA + +00E2D +THAI CHARACTER O ANG + +00E2E +THAI CHARACTER HO NOKHUK + +00E2F +THAI CHARACTER PAIYANNOI + +00E30 +THAI CHARACTER SARA A + +00E31 +THAI CHARACTER MAI HAN-AKAT + +00E32 +THAI CHARACTER SARA AA + +00E33 +THAI CHARACTER SARA AM + +00E34 +THAI CHARACTER SARA I + +00E35 +THAI CHARACTER SARA II + +00E36 +THAI CHARACTER SARA UE + +00E37 +THAI CHARACTER SARA UEE + +00E38 +THAI CHARACTER SARA U + +00E39 +THAI CHARACTER SARA UU + +00E3A +THAI CHARACTER PHINTHU + +00E3F +THAI CURRENCY SYMBOL BAHT + +00E40 +THAI CHARACTER SARA E + +00E41 +THAI CHARACTER SARA AE + +00E42 +THAI CHARACTER SARA O + +00E43 +THAI CHARACTER SARA AI MAIMUAN + +00E44 +THAI CHARACTER SARA AI MAIMALAI + +00E45 +THAI CHARACTER LAKKHANGYAO + +00E46 +THAI CHARACTER MAIYAMOK + +00E47 +THAI CHARACTER MAITAIKHU + +00E48 +THAI CHARACTER MAI EK + +00E49 +THAI CHARACTER MAI THO + +00E4A +THAI CHARACTER MAI TRI + +00E4B +THAI CHARACTER MAI CHATTAWA + +00E4C +THAI CHARACTER THANTHAKHAT + +00E4D +THAI CHARACTER NIKHAHIT + +00E4E +THAI CHARACTER YAMAKKAN + +00E4F +THAI CHARACTER FONGMAN + +00E50 +THAI DIGIT ZERO + +00E51 +THAI DIGIT ONE + +00E52 +THAI DIGIT TWO + +00E53 +THAI DIGIT THREE + +00E54 +THAI DIGIT FOUR + +00E55 +THAI DIGIT FIVE + +00E56 +THAI DIGIT SIX + +00E57 +THAI DIGIT SEVEN + +00E58 +THAI DIGIT EIGHT + +00E59 +THAI DIGIT NINE + +00E5A +THAI CHARACTER ANGKHANKHU + +00E5B +THAI CHARACTER KHOMUT + +00E81 +LAO LETTER KO + +00E82 +LAO LETTER KHO SUNG + +00E84 +LAO LETTER KHO TAM + +00E86 +LAO LETTER PALI GHA + +00E87 +LAO LETTER NGO + +00E88 +LAO LETTER CO + +00E89 +LAO LETTER PALI CHA + +00E8A +LAO LETTER SO TAM + +00E8C +LAO LETTER PALI JHA + +00E8D +LAO LETTER NYO + +00E8E +LAO LETTER PALI NYA + +00E8F +LAO LETTER PALI TTA + +00E90 +LAO LETTER PALI TTHA + +00E91 +LAO LETTER PALI DDA + +00E92 +LAO LETTER PALI DDHA + +00E93 +LAO LETTER PALI NNA + +00E94 +LAO LETTER DO + +00E95 +LAO LETTER TO + +00E96 +LAO LETTER THO SUNG + +00E97 +LAO LETTER THO TAM + +00E98 +LAO LETTER PALI DHA + +00E99 +LAO LETTER NO + +00E9A +LAO LETTER BO + +00E9B +LAO LETTER PO + +00E9C +LAO LETTER PHO SUNG + +00E9D +LAO LETTER FO FON + +00E9D +LAO LETTER FO TAM + +00E9E +LAO LETTER PHO TAM + +00E9F +LAO LETTER FO FAY + +00E9F +LAO LETTER FO SUNG + +00EA0 +LAO LETTER PALI BHA + +00EA1 +LAO LETTER MO + +00EA2 +LAO LETTER YO + +00EA3 +LAO LETTER RO + +00EA3 +LAO LETTER LO LING + +00EA5 +LAO LETTER LO + +00EA5 +LAO LETTER LO LOOT + +00EA7 +LAO LETTER WO + +00EA8 +LAO LETTER SANSKRIT SHA + +00EA9 +LAO LETTER SANSKRIT SSA + +00EAA +LAO LETTER SO SUNG + +00EAB +LAO LETTER HO SUNG + +00EAC +LAO LETTER PALI LLA + +00EAD +LAO LETTER O + +00EAE +LAO LETTER HO TAM + +00EAF +LAO ELLIPSIS + +00EB0 +LAO VOWEL SIGN A + +00EB1 +LAO VOWEL SIGN MAI KAN + +00EB2 +LAO VOWEL SIGN AA + +00EB3 +LAO VOWEL SIGN AM + +00EB4 +LAO VOWEL SIGN I + +00EB5 +LAO VOWEL SIGN II + +00EB6 +LAO VOWEL SIGN Y + +00EB7 +LAO VOWEL SIGN YY + +00EB8 +LAO VOWEL SIGN U + +00EB9 +LAO VOWEL SIGN UU + +00EBA +LAO SIGN PALI VIRAMA + +00EBB +LAO VOWEL SIGN MAI KON + +00EBC +LAO SEMIVOWEL SIGN LO + +00EBD +LAO SEMIVOWEL SIGN NYO + +00EC0 +LAO VOWEL SIGN E + +00EC1 +LAO VOWEL SIGN EI + +00EC2 +LAO VOWEL SIGN O + +00EC3 +LAO VOWEL SIGN AY + +00EC4 +LAO VOWEL SIGN AI + +00EC6 +LAO KO LA + +00EC8 +LAO TONE MAI EK + +00EC9 +LAO TONE MAI THO + +00ECA +LAO TONE MAI TI + +00ECB +LAO TONE MAI CATAWA + +00ECC +LAO CANCELLATION MARK + +00ECD +LAO NIGGAHITA + +00ECE +LAO YAMAKKAN + +00ED0 +LAO DIGIT ZERO + +00ED1 +LAO DIGIT ONE + +00ED2 +LAO DIGIT TWO + +00ED3 +LAO DIGIT THREE + +00ED4 +LAO DIGIT FOUR + +00ED5 +LAO DIGIT FIVE + +00ED6 +LAO DIGIT SIX + +00ED7 +LAO DIGIT SEVEN + +00ED8 +LAO DIGIT EIGHT + +00ED9 +LAO DIGIT NINE + +00EDC +LAO HO NO + +00EDD +LAO HO MO + +00EDE +LAO LETTER KHMU GO + +00EDF +LAO LETTER KHMU NYO + +00F00 +TIBETAN SYLLABLE OM + +00F01 +TIBETAN MARK GTER YIG MGO TRUNCATED A + +00F02 +TIBETAN MARK GTER YIG MGO -UM RNAM BCAD MA + +00F03 +TIBETAN MARK GTER YIG MGO -UM GTER TSHEG MA + +00F04 +TIBETAN MARK INITIAL YIG MGO MDUN MA + +00F05 +TIBETAN MARK CLOSING YIG MGO SGAB MA + +00F06 +TIBETAN MARK CARET YIG MGO PHUR SHAD MA + +00F07 +TIBETAN MARK YIG MGO TSHEG SHAD MA + +00F08 +TIBETAN MARK SBRUL SHAD + +00F09 +TIBETAN MARK BSKUR YIG MGO + +00F0A +TIBETAN MARK BKA- SHOG YIG MGO + +00F0B +TIBETAN MARK INTERSYLLABIC TSHEG + +00F0C +TIBETAN MARK DELIMITER TSHEG BSTAR + +00F0D +TIBETAN MARK SHAD + +00F0E +TIBETAN MARK NYIS SHAD + +00F0F +TIBETAN MARK TSHEG SHAD + +00F10 +TIBETAN MARK NYIS TSHEG SHAD + +00F11 +TIBETAN MARK RIN CHEN SPUNGS SHAD + +00F12 +TIBETAN MARK RGYA GRAM SHAD + +00F13 +TIBETAN MARK CARET -DZUD RTAGS ME LONG CAN + +00F14 +TIBETAN MARK GTER TSHEG + +00F15 +TIBETAN LOGOTYPE SIGN CHAD RTAGS + +00F16 +TIBETAN LOGOTYPE SIGN LHAG RTAGS + +00F17 +TIBETAN ASTROLOGICAL SIGN SGRA GCAN -CHAR RTAGS + +00F18 +TIBETAN ASTROLOGICAL SIGN -KHYUD PA + +00F19 +TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS + +00F1A +TIBETAN SIGN RDEL DKAR GCIG + +00F1B +TIBETAN SIGN RDEL DKAR GNYIS + +00F1C +TIBETAN SIGN RDEL DKAR GSUM + +00F1D +TIBETAN SIGN RDEL NAG GCIG + +00F1E +TIBETAN SIGN RDEL NAG GNYIS + +00F1F +TIBETAN SIGN RDEL DKAR RDEL NAG + +00F20 +TIBETAN DIGIT ZERO + +00F21 +TIBETAN DIGIT ONE + +00F22 +TIBETAN DIGIT TWO + +00F23 +TIBETAN DIGIT THREE + +00F24 +TIBETAN DIGIT FOUR + +00F25 +TIBETAN DIGIT FIVE + +00F26 +TIBETAN DIGIT SIX + +00F27 +TIBETAN DIGIT SEVEN + +00F28 +TIBETAN DIGIT EIGHT + +00F29 +TIBETAN DIGIT NINE + +00F2A +TIBETAN DIGIT HALF ONE + +00F2B +TIBETAN DIGIT HALF TWO + +00F2C +TIBETAN DIGIT HALF THREE + +00F2D +TIBETAN DIGIT HALF FOUR + +00F2E +TIBETAN DIGIT HALF FIVE + +00F2F +TIBETAN DIGIT HALF SIX + +00F30 +TIBETAN DIGIT HALF SEVEN + +00F31 +TIBETAN DIGIT HALF EIGHT + +00F32 +TIBETAN DIGIT HALF NINE + +00F33 +TIBETAN DIGIT HALF ZERO + +00F34 +TIBETAN MARK BSDUS RTAGS + +00F35 +TIBETAN MARK NGAS BZUNG NYI ZLA + +00F36 +TIBETAN MARK CARET -DZUD RTAGS BZHI MIG CAN + +00F37 +TIBETAN MARK NGAS BZUNG SGOR RTAGS + +00F38 +TIBETAN MARK CHE MGO + +00F39 +TIBETAN MARK TSA -PHRU + +00F3A +TIBETAN MARK GUG RTAGS GYON + +00F3B +TIBETAN MARK GUG RTAGS GYAS + +00F3C +TIBETAN MARK ANG KHANG GYON + +00F3D +TIBETAN MARK ANG KHANG GYAS + +00F3E +TIBETAN SIGN YAR TSHES + +00F3F +TIBETAN SIGN MAR TSHES + +00F40 +TIBETAN LETTER KA + +00F41 +TIBETAN LETTER KHA + +00F42 +TIBETAN LETTER GA + +00F43 +TIBETAN LETTER GHA + +00F44 +TIBETAN LETTER NGA + +00F45 +TIBETAN LETTER CA + +00F46 +TIBETAN LETTER CHA + +00F47 +TIBETAN LETTER JA + +00F49 +TIBETAN LETTER NYA + +00F4A +TIBETAN LETTER TTA + +00F4B +TIBETAN LETTER TTHA + +00F4C +TIBETAN LETTER DDA + +00F4D +TIBETAN LETTER DDHA + +00F4E +TIBETAN LETTER NNA + +00F4F +TIBETAN LETTER TA + +00F50 +TIBETAN LETTER THA + +00F51 +TIBETAN LETTER DA + +00F52 +TIBETAN LETTER DHA + +00F53 +TIBETAN LETTER NA + +00F54 +TIBETAN LETTER PA + +00F55 +TIBETAN LETTER PHA + +00F56 +TIBETAN LETTER BA + +00F57 +TIBETAN LETTER BHA + +00F58 +TIBETAN LETTER MA + +00F59 +TIBETAN LETTER TSA + +00F5A +TIBETAN LETTER TSHA + +00F5B +TIBETAN LETTER DZA + +00F5C +TIBETAN LETTER DZHA + +00F5D +TIBETAN LETTER WA + +00F5E +TIBETAN LETTER ZHA + +00F5F +TIBETAN LETTER ZA + +00F60 +TIBETAN LETTER -A + +00F61 +TIBETAN LETTER YA + +00F62 +TIBETAN LETTER RA + +00F63 +TIBETAN LETTER LA + +00F64 +TIBETAN LETTER SHA + +00F65 +TIBETAN LETTER SSA + +00F66 +TIBETAN LETTER SA + +00F67 +TIBETAN LETTER HA + +00F68 +TIBETAN LETTER A + +00F69 +TIBETAN LETTER KSSA + +00F6A +TIBETAN LETTER FIXED-FORM RA + +00F6B +TIBETAN LETTER KKA + +00F6C +TIBETAN LETTER RRA + +00F71 +TIBETAN VOWEL SIGN AA + +00F72 +TIBETAN VOWEL SIGN I + +00F73 +TIBETAN VOWEL SIGN II + +00F74 +TIBETAN VOWEL SIGN U + +00F75 +TIBETAN VOWEL SIGN UU + +00F76 +TIBETAN VOWEL SIGN VOCALIC R + +00F77 +TIBETAN VOWEL SIGN VOCALIC RR + +00F78 +TIBETAN VOWEL SIGN VOCALIC L + +00F79 +TIBETAN VOWEL SIGN VOCALIC LL + +00F7A +TIBETAN VOWEL SIGN E + +00F7B +TIBETAN VOWEL SIGN EE + +00F7C +TIBETAN VOWEL SIGN O + +00F7D +TIBETAN VOWEL SIGN OO + +00F7E +TIBETAN SIGN RJES SU NGA RO + +00F7F +TIBETAN SIGN RNAM BCAD + +00F80 +TIBETAN VOWEL SIGN REVERSED I + +00F81 +TIBETAN VOWEL SIGN REVERSED II + +00F82 +TIBETAN SIGN NYI ZLA NAA DA + +00F83 +TIBETAN SIGN SNA LDAN + +00F84 +TIBETAN MARK HALANTA + +00F85 +TIBETAN MARK PALUTA + +00F86 +TIBETAN SIGN LCI RTAGS + +00F87 +TIBETAN SIGN YANG RTAGS + +00F88 +TIBETAN SIGN LCE TSA CAN + +00F89 +TIBETAN SIGN MCHU CAN + +00F8A +TIBETAN SIGN GRU CAN RGYINGS + +00F8B +TIBETAN SIGN GRU MED RGYINGS + +00F8C +TIBETAN SIGN INVERTED MCHU CAN + +00F8D +TIBETAN SUBJOINED SIGN LCE TSA CAN + +00F8E +TIBETAN SUBJOINED SIGN MCHU CAN + +00F8F +TIBETAN SUBJOINED SIGN INVERTED MCHU CAN + +00F90 +TIBETAN SUBJOINED LETTER KA + +00F91 +TIBETAN SUBJOINED LETTER KHA + +00F92 +TIBETAN SUBJOINED LETTER GA + +00F93 +TIBETAN SUBJOINED LETTER GHA + +00F94 +TIBETAN SUBJOINED LETTER NGA + +00F95 +TIBETAN SUBJOINED LETTER CA + +00F96 +TIBETAN SUBJOINED LETTER CHA + +00F97 +TIBETAN SUBJOINED LETTER JA + +00F99 +TIBETAN SUBJOINED LETTER NYA + +00F9A +TIBETAN SUBJOINED LETTER TTA + +00F9B +TIBETAN SUBJOINED LETTER TTHA + +00F9C +TIBETAN SUBJOINED LETTER DDA + +00F9D +TIBETAN SUBJOINED LETTER DDHA + +00F9E +TIBETAN SUBJOINED LETTER NNA + +00F9F +TIBETAN SUBJOINED LETTER TA + +00FA0 +TIBETAN SUBJOINED LETTER THA + +00FA1 +TIBETAN SUBJOINED LETTER DA + +00FA2 +TIBETAN SUBJOINED LETTER DHA + +00FA3 +TIBETAN SUBJOINED LETTER NA + +00FA4 +TIBETAN SUBJOINED LETTER PA + +00FA5 +TIBETAN SUBJOINED LETTER PHA + +00FA6 +TIBETAN SUBJOINED LETTER BA + +00FA7 +TIBETAN SUBJOINED LETTER BHA + +00FA8 +TIBETAN SUBJOINED LETTER MA + +00FA9 +TIBETAN SUBJOINED LETTER TSA + +00FAA +TIBETAN SUBJOINED LETTER TSHA + +00FAB +TIBETAN SUBJOINED LETTER DZA + +00FAC +TIBETAN SUBJOINED LETTER DZHA + +00FAD +TIBETAN SUBJOINED LETTER WA + +00FAE +TIBETAN SUBJOINED LETTER ZHA + +00FAF +TIBETAN SUBJOINED LETTER ZA + +00FB0 +TIBETAN SUBJOINED LETTER -A + +00FB1 +TIBETAN SUBJOINED LETTER YA + +00FB2 +TIBETAN SUBJOINED LETTER RA + +00FB3 +TIBETAN SUBJOINED LETTER LA + +00FB4 +TIBETAN SUBJOINED LETTER SHA + +00FB5 +TIBETAN SUBJOINED LETTER SSA + +00FB6 +TIBETAN SUBJOINED LETTER SA + +00FB7 +TIBETAN SUBJOINED LETTER HA + +00FB8 +TIBETAN SUBJOINED LETTER A + +00FB9 +TIBETAN SUBJOINED LETTER KSSA + +00FBA +TIBETAN SUBJOINED LETTER FIXED-FORM WA + +00FBB +TIBETAN SUBJOINED LETTER FIXED-FORM YA + +00FBC +TIBETAN SUBJOINED LETTER FIXED-FORM RA + +00FBE +TIBETAN KU RU KHA + +00FBF +TIBETAN KU RU KHA BZHI MIG CAN + +00FC0 +TIBETAN CANTILLATION SIGN HEAVY BEAT + +00FC1 +TIBETAN CANTILLATION SIGN LIGHT BEAT + +00FC2 +TIBETAN CANTILLATION SIGN CANG TE-U + +00FC3 +TIBETAN CANTILLATION SIGN SBUB -CHAL + +00FC4 +TIBETAN SYMBOL DRIL BU + +00FC5 +TIBETAN SYMBOL RDO RJE + +00FC6 +TIBETAN SYMBOL PADMA GDAN + +00FC7 +TIBETAN SYMBOL RDO RJE RGYA GRAM + +00FC8 +TIBETAN SYMBOL PHUR PA + +00FC9 +TIBETAN SYMBOL NOR BU + +00FCA +TIBETAN SYMBOL NOR BU NYIS -KHYIL + +00FCB +TIBETAN SYMBOL NOR BU GSUM -KHYIL + +00FCC +TIBETAN SYMBOL NOR BU BZHI -KHYIL + +00FCE +TIBETAN SIGN RDEL NAG RDEL DKAR + +00FCF +TIBETAN SIGN RDEL NAG GSUM + +00FD0 +TIBETAN MARK BKA- SHOG GI MGO RGYAN + +00FD0 +TIBETAN MARK BSKA- SHOG GI MGO RGYAN + +00FD1 +TIBETAN MARK MNYAM YIG GI MGO RGYAN + +00FD2 +TIBETAN MARK NYIS TSHEG + +00FD3 +TIBETAN MARK INITIAL BRDA RNYING YIG MGO MDUN MA + +00FD4 +TIBETAN MARK CLOSING BRDA RNYING YIG MGO SGAB MA + +00FD5 +RIGHT-FACING SVASTI SIGN + +00FD6 +LEFT-FACING SVASTI SIGN + +00FD7 +RIGHT-FACING SVASTI SIGN WITH DOTS + +00FD8 +LEFT-FACING SVASTI SIGN WITH DOTS + +00FD9 +TIBETAN MARK LEADING MCHAN RTAGS + +00FDA +TIBETAN MARK TRAILING MCHAN RTAGS + +01000 +MYANMAR LETTER KA + +01001 +MYANMAR LETTER KHA + +01002 +MYANMAR LETTER GA + +01003 +MYANMAR LETTER GHA + +01004 +MYANMAR LETTER NGA + +01005 +MYANMAR LETTER CA + +01006 +MYANMAR LETTER CHA + +01007 +MYANMAR LETTER JA + +01008 +MYANMAR LETTER JHA + +01009 +MYANMAR LETTER NYA + +0100A +MYANMAR LETTER NNYA + +0100B +MYANMAR LETTER TTA + +0100C +MYANMAR LETTER TTHA + +0100D +MYANMAR LETTER DDA + +0100E +MYANMAR LETTER DDHA + +0100F +MYANMAR LETTER NNA + +01010 +MYANMAR LETTER TA + +01011 +MYANMAR LETTER THA + +01012 +MYANMAR LETTER DA + +01013 +MYANMAR LETTER DHA + +01014 +MYANMAR LETTER NA + +01015 +MYANMAR LETTER PA + +01016 +MYANMAR LETTER PHA + +01017 +MYANMAR LETTER BA + +01018 +MYANMAR LETTER BHA + +01019 +MYANMAR LETTER MA + +0101A +MYANMAR LETTER YA + +0101B +MYANMAR LETTER RA + +0101C +MYANMAR LETTER LA + +0101D +MYANMAR LETTER WA + +0101E +MYANMAR LETTER SA + +0101F +MYANMAR LETTER HA + +01020 +MYANMAR LETTER LLA + +01021 +MYANMAR LETTER A + +01022 +MYANMAR LETTER SHAN A + +01023 +MYANMAR LETTER I + +01024 +MYANMAR LETTER II + +01025 +MYANMAR LETTER U + +01026 +MYANMAR LETTER UU + +01027 +MYANMAR LETTER E + +01028 +MYANMAR LETTER MON E + +01029 +MYANMAR LETTER O + +0102A +MYANMAR LETTER AU + +0102B +MYANMAR VOWEL SIGN TALL AA + +0102C +MYANMAR VOWEL SIGN AA + +0102D +MYANMAR VOWEL SIGN I + +0102E +MYANMAR VOWEL SIGN II + +0102F +MYANMAR VOWEL SIGN U + +01030 +MYANMAR VOWEL SIGN UU + +01031 +MYANMAR VOWEL SIGN E + +01032 +MYANMAR VOWEL SIGN AI + +01033 +MYANMAR VOWEL SIGN MON II + +01034 +MYANMAR VOWEL SIGN MON O + +01035 +MYANMAR VOWEL SIGN E ABOVE + +01036 +MYANMAR SIGN ANUSVARA + +01037 +MYANMAR SIGN DOT BELOW + +01038 +MYANMAR SIGN VISARGA + +01039 +MYANMAR SIGN VIRAMA + +0103A +MYANMAR SIGN ASAT + +0103B +MYANMAR CONSONANT SIGN MEDIAL YA + +0103C +MYANMAR CONSONANT SIGN MEDIAL RA + +0103D +MYANMAR CONSONANT SIGN MEDIAL WA + +0103E +MYANMAR CONSONANT SIGN MEDIAL HA + +0103F +MYANMAR LETTER GREAT SA + +01040 +MYANMAR DIGIT ZERO + +01041 +MYANMAR DIGIT ONE + +01042 +MYANMAR DIGIT TWO + +01043 +MYANMAR DIGIT THREE + +01044 +MYANMAR DIGIT FOUR + +01045 +MYANMAR DIGIT FIVE + +01046 +MYANMAR DIGIT SIX + +01047 +MYANMAR DIGIT SEVEN + +01048 +MYANMAR DIGIT EIGHT + +01049 +MYANMAR DIGIT NINE + +0104A +MYANMAR SIGN LITTLE SECTION + +0104B +MYANMAR SIGN SECTION + +0104C +MYANMAR SYMBOL LOCATIVE + +0104D +MYANMAR SYMBOL COMPLETED + +0104E +MYANMAR SYMBOL AFOREMENTIONED + +0104F +MYANMAR SYMBOL GENITIVE + +01050 +MYANMAR LETTER SHA + +01051 +MYANMAR LETTER SSA + +01052 +MYANMAR LETTER VOCALIC R + +01053 +MYANMAR LETTER VOCALIC RR + +01054 +MYANMAR LETTER VOCALIC L + +01055 +MYANMAR LETTER VOCALIC LL + +01056 +MYANMAR VOWEL SIGN VOCALIC R + +01057 +MYANMAR VOWEL SIGN VOCALIC RR + +01058 +MYANMAR VOWEL SIGN VOCALIC L + +01059 +MYANMAR VOWEL SIGN VOCALIC LL + +0105A +MYANMAR LETTER MON NGA + +0105B +MYANMAR LETTER MON JHA + +0105C +MYANMAR LETTER MON BBA + +0105D +MYANMAR LETTER MON BBE + +0105E +MYANMAR CONSONANT SIGN MON MEDIAL NA + +0105F +MYANMAR CONSONANT SIGN MON MEDIAL MA + +01060 +MYANMAR CONSONANT SIGN MON MEDIAL LA + +01061 +MYANMAR LETTER SGAW KAREN SHA + +01062 +MYANMAR VOWEL SIGN SGAW KAREN EU + +01063 +MYANMAR TONE MARK SGAW KAREN HATHI + +01064 +MYANMAR TONE MARK SGAW KAREN KE PHO + +01065 +MYANMAR LETTER WESTERN PWO KAREN THA + +01066 +MYANMAR LETTER WESTERN PWO KAREN PWA + +01067 +MYANMAR VOWEL SIGN WESTERN PWO KAREN EU + +01068 +MYANMAR VOWEL SIGN WESTERN PWO KAREN UE + +01069 +MYANMAR SIGN WESTERN PWO KAREN TONE-1 + +0106A +MYANMAR SIGN WESTERN PWO KAREN TONE-2 + +0106B +MYANMAR SIGN WESTERN PWO KAREN TONE-3 + +0106C +MYANMAR SIGN WESTERN PWO KAREN TONE-4 + +0106D +MYANMAR SIGN WESTERN PWO KAREN TONE-5 + +0106E +MYANMAR LETTER EASTERN PWO KAREN NNA + +0106F +MYANMAR LETTER EASTERN PWO KAREN YWA + +01070 +MYANMAR LETTER EASTERN PWO KAREN GHWA + +01071 +MYANMAR VOWEL SIGN GEBA KAREN I + +01072 +MYANMAR VOWEL SIGN KAYAH OE + +01073 +MYANMAR VOWEL SIGN KAYAH U + +01074 +MYANMAR VOWEL SIGN KAYAH EE + +01075 +MYANMAR LETTER SHAN KA + +01076 +MYANMAR LETTER SHAN KHA + +01077 +MYANMAR LETTER SHAN GA + +01078 +MYANMAR LETTER SHAN CA + +01079 +MYANMAR LETTER SHAN ZA + +0107A +MYANMAR LETTER SHAN NYA + +0107B +MYANMAR LETTER SHAN DA + +0107C +MYANMAR LETTER SHAN NA + +0107D +MYANMAR LETTER SHAN PHA + +0107E +MYANMAR LETTER SHAN FA + +0107F +MYANMAR LETTER SHAN BA + +01080 +MYANMAR LETTER SHAN THA + +01081 +MYANMAR LETTER SHAN HA + +01082 +MYANMAR CONSONANT SIGN SHAN MEDIAL WA + +01083 +MYANMAR VOWEL SIGN SHAN AA + +01084 +MYANMAR VOWEL SIGN SHAN E + +01085 +MYANMAR VOWEL SIGN SHAN E ABOVE + +01086 +MYANMAR VOWEL SIGN SHAN FINAL Y + +01087 +MYANMAR SIGN SHAN TONE-2 + +01088 +MYANMAR SIGN SHAN TONE-3 + +01089 +MYANMAR SIGN SHAN TONE-5 + +0108A +MYANMAR SIGN SHAN TONE-6 + +0108B +MYANMAR SIGN SHAN COUNCIL TONE-2 + +0108C +MYANMAR SIGN SHAN COUNCIL TONE-3 + +0108D +MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE + +0108E +MYANMAR LETTER RUMAI PALAUNG FA + +0108F +MYANMAR SIGN RUMAI PALAUNG TONE-5 + +01090 +MYANMAR SHAN DIGIT ZERO + +01091 +MYANMAR SHAN DIGIT ONE + +01092 +MYANMAR SHAN DIGIT TWO + +01093 +MYANMAR SHAN DIGIT THREE + +01094 +MYANMAR SHAN DIGIT FOUR + +01095 +MYANMAR SHAN DIGIT FIVE + +01096 +MYANMAR SHAN DIGIT SIX + +01097 +MYANMAR SHAN DIGIT SEVEN + +01098 +MYANMAR SHAN DIGIT EIGHT + +01099 +MYANMAR SHAN DIGIT NINE + +0109A +MYANMAR SIGN KHAMTI TONE-1 + +0109B +MYANMAR SIGN KHAMTI TONE-3 + +0109C +MYANMAR VOWEL SIGN AITON A + +0109D +MYANMAR VOWEL SIGN AITON AI + +0109E +MYANMAR SYMBOL SHAN ONE + +0109F +MYANMAR SYMBOL SHAN EXCLAMATION + +010A0 +GEORGIAN CAPITAL LETTER AN + +010A1 +GEORGIAN CAPITAL LETTER BAN + +010A2 +GEORGIAN CAPITAL LETTER GAN + +010A3 +GEORGIAN CAPITAL LETTER DON + +010A4 +GEORGIAN CAPITAL LETTER EN + +010A5 +GEORGIAN CAPITAL LETTER VIN + +010A6 +GEORGIAN CAPITAL LETTER ZEN + +010A7 +GEORGIAN CAPITAL LETTER TAN + +010A8 +GEORGIAN CAPITAL LETTER IN + +010A9 +GEORGIAN CAPITAL LETTER KAN + +010AA +GEORGIAN CAPITAL LETTER LAS + +010AB +GEORGIAN CAPITAL LETTER MAN + +010AC +GEORGIAN CAPITAL LETTER NAR + +010AD +GEORGIAN CAPITAL LETTER ON + +010AE +GEORGIAN CAPITAL LETTER PAR + +010AF +GEORGIAN CAPITAL LETTER ZHAR + +010B0 +GEORGIAN CAPITAL LETTER RAE + +010B1 +GEORGIAN CAPITAL LETTER SAN + +010B2 +GEORGIAN CAPITAL LETTER TAR + +010B3 +GEORGIAN CAPITAL LETTER UN + +010B4 +GEORGIAN CAPITAL LETTER PHAR + +010B5 +GEORGIAN CAPITAL LETTER KHAR + +010B6 +GEORGIAN CAPITAL LETTER GHAN + +010B7 +GEORGIAN CAPITAL LETTER QAR + +010B8 +GEORGIAN CAPITAL LETTER SHIN + +010B9 +GEORGIAN CAPITAL LETTER CHIN + +010BA +GEORGIAN CAPITAL LETTER CAN + +010BB +GEORGIAN CAPITAL LETTER JIL + +010BC +GEORGIAN CAPITAL LETTER CIL + +010BD +GEORGIAN CAPITAL LETTER CHAR + +010BE +GEORGIAN CAPITAL LETTER XAN + +010BF +GEORGIAN CAPITAL LETTER JHAN + +010C0 +GEORGIAN CAPITAL LETTER HAE + +010C1 +GEORGIAN CAPITAL LETTER HE + +010C2 +GEORGIAN CAPITAL LETTER HIE + +010C3 +GEORGIAN CAPITAL LETTER WE + +010C4 +GEORGIAN CAPITAL LETTER HAR + +010C5 +GEORGIAN CAPITAL LETTER HOE + +010C7 +GEORGIAN CAPITAL LETTER YN + +010CD +GEORGIAN CAPITAL LETTER AEN + +010D0 +GEORGIAN LETTER AN + +010D1 +GEORGIAN LETTER BAN + +010D2 +GEORGIAN LETTER GAN + +010D3 +GEORGIAN LETTER DON + +010D4 +GEORGIAN LETTER EN + +010D5 +GEORGIAN LETTER VIN + +010D6 +GEORGIAN LETTER ZEN + +010D7 +GEORGIAN LETTER TAN + +010D8 +GEORGIAN LETTER IN + +010D9 +GEORGIAN LETTER KAN + +010DA +GEORGIAN LETTER LAS + +010DB +GEORGIAN LETTER MAN + +010DC +GEORGIAN LETTER NAR + +010DD +GEORGIAN LETTER ON + +010DE +GEORGIAN LETTER PAR + +010DF +GEORGIAN LETTER ZHAR + +010E0 +GEORGIAN LETTER RAE + +010E1 +GEORGIAN LETTER SAN + +010E2 +GEORGIAN LETTER TAR + +010E3 +GEORGIAN LETTER UN + +010E4 +GEORGIAN LETTER PHAR + +010E5 +GEORGIAN LETTER KHAR + +010E6 +GEORGIAN LETTER GHAN + +010E7 +GEORGIAN LETTER QAR + +010E8 +GEORGIAN LETTER SHIN + +010E9 +GEORGIAN LETTER CHIN + +010EA +GEORGIAN LETTER CAN + +010EB +GEORGIAN LETTER JIL + +010EC +GEORGIAN LETTER CIL + +010ED +GEORGIAN LETTER CHAR + +010EE +GEORGIAN LETTER XAN + +010EF +GEORGIAN LETTER JHAN + +010F0 +GEORGIAN LETTER HAE + +010F1 +GEORGIAN LETTER HE + +010F2 +GEORGIAN LETTER HIE + +010F3 +GEORGIAN LETTER WE + +010F4 +GEORGIAN LETTER HAR + +010F5 +GEORGIAN LETTER HOE + +010F6 +GEORGIAN LETTER FI + +010F7 +GEORGIAN LETTER YN + +010F8 +GEORGIAN LETTER ELIFI + +010F9 +GEORGIAN LETTER TURNED GAN + +010FA +GEORGIAN LETTER AIN + +010FB +GEORGIAN PARAGRAPH SEPARATOR + +010FC +MODIFIER LETTER GEORGIAN NAR + +010FD +GEORGIAN LETTER AEN + +010FE +GEORGIAN LETTER HARD SIGN + +010FF +GEORGIAN LETTER LABIAL SIGN + +01100 +HANGUL CHOSEONG KIYEOK + +01101 +HANGUL CHOSEONG SSANGKIYEOK + +01102 +HANGUL CHOSEONG NIEUN + +01103 +HANGUL CHOSEONG TIKEUT + +01104 +HANGUL CHOSEONG SSANGTIKEUT + +01105 +HANGUL CHOSEONG RIEUL + +01106 +HANGUL CHOSEONG MIEUM + +01107 +HANGUL CHOSEONG PIEUP + +01108 +HANGUL CHOSEONG SSANGPIEUP + +01109 +HANGUL CHOSEONG SIOS + +0110A +HANGUL CHOSEONG SSANGSIOS + +0110B +HANGUL CHOSEONG IEUNG + +0110C +HANGUL CHOSEONG CIEUC + +0110D +HANGUL CHOSEONG SSANGCIEUC + +0110E +HANGUL CHOSEONG CHIEUCH + +0110F +HANGUL CHOSEONG KHIEUKH + +01110 +HANGUL CHOSEONG THIEUTH + +01111 +HANGUL CHOSEONG PHIEUPH + +01112 +HANGUL CHOSEONG HIEUH + +01113 +HANGUL CHOSEONG NIEUN-KIYEOK + +01114 +HANGUL CHOSEONG SSANGNIEUN + +01115 +HANGUL CHOSEONG NIEUN-TIKEUT + +01116 +HANGUL CHOSEONG NIEUN-PIEUP + +01117 +HANGUL CHOSEONG TIKEUT-KIYEOK + +01118 +HANGUL CHOSEONG RIEUL-NIEUN + +01119 +HANGUL CHOSEONG SSANGRIEUL + +0111A +HANGUL CHOSEONG RIEUL-HIEUH + +0111B +HANGUL CHOSEONG KAPYEOUNRIEUL + +0111C +HANGUL CHOSEONG MIEUM-PIEUP + +0111D +HANGUL CHOSEONG KAPYEOUNMIEUM + +0111E +HANGUL CHOSEONG PIEUP-KIYEOK + +0111F +HANGUL CHOSEONG PIEUP-NIEUN + +01120 +HANGUL CHOSEONG PIEUP-TIKEUT + +01121 +HANGUL CHOSEONG PIEUP-SIOS + +01122 +HANGUL CHOSEONG PIEUP-SIOS-KIYEOK + +01123 +HANGUL CHOSEONG PIEUP-SIOS-TIKEUT + +01124 +HANGUL CHOSEONG PIEUP-SIOS-PIEUP + +01125 +HANGUL CHOSEONG PIEUP-SSANGSIOS + +01126 +HANGUL CHOSEONG PIEUP-SIOS-CIEUC + +01127 +HANGUL CHOSEONG PIEUP-CIEUC + +01128 +HANGUL CHOSEONG PIEUP-CHIEUCH + +01129 +HANGUL CHOSEONG PIEUP-THIEUTH + +0112A +HANGUL CHOSEONG PIEUP-PHIEUPH + +0112B +HANGUL CHOSEONG KAPYEOUNPIEUP + +0112C +HANGUL CHOSEONG KAPYEOUNSSANGPIEUP + +0112D +HANGUL CHOSEONG SIOS-KIYEOK + +0112E +HANGUL CHOSEONG SIOS-NIEUN + +0112F +HANGUL CHOSEONG SIOS-TIKEUT + +01130 +HANGUL CHOSEONG SIOS-RIEUL + +01131 +HANGUL CHOSEONG SIOS-MIEUM + +01132 +HANGUL CHOSEONG SIOS-PIEUP + +01133 +HANGUL CHOSEONG SIOS-PIEUP-KIYEOK + +01134 +HANGUL CHOSEONG SIOS-SSANGSIOS + +01135 +HANGUL CHOSEONG SIOS-IEUNG + +01136 +HANGUL CHOSEONG SIOS-CIEUC + +01137 +HANGUL CHOSEONG SIOS-CHIEUCH + +01138 +HANGUL CHOSEONG SIOS-KHIEUKH + +01139 +HANGUL CHOSEONG SIOS-THIEUTH + +0113A +HANGUL CHOSEONG SIOS-PHIEUPH + +0113B +HANGUL CHOSEONG SIOS-HIEUH + +0113C +HANGUL CHOSEONG CHITUEUMSIOS + +0113D +HANGUL CHOSEONG CHITUEUMSSANGSIOS + +0113E +HANGUL CHOSEONG CEONGCHIEUMSIOS + +0113F +HANGUL CHOSEONG CEONGCHIEUMSSANGSIOS + +01140 +HANGUL CHOSEONG PANSIOS + +01141 +HANGUL CHOSEONG IEUNG-KIYEOK + +01142 +HANGUL CHOSEONG IEUNG-TIKEUT + +01143 +HANGUL CHOSEONG IEUNG-MIEUM + +01144 +HANGUL CHOSEONG IEUNG-PIEUP + +01145 +HANGUL CHOSEONG IEUNG-SIOS + +01146 +HANGUL CHOSEONG IEUNG-PANSIOS + +01147 +HANGUL CHOSEONG SSANGIEUNG + +01148 +HANGUL CHOSEONG IEUNG-CIEUC + +01149 +HANGUL CHOSEONG IEUNG-CHIEUCH + +0114A +HANGUL CHOSEONG IEUNG-THIEUTH + +0114B +HANGUL CHOSEONG IEUNG-PHIEUPH + +0114C +HANGUL CHOSEONG YESIEUNG + +0114D +HANGUL CHOSEONG CIEUC-IEUNG + +0114E +HANGUL CHOSEONG CHITUEUMCIEUC + +0114F +HANGUL CHOSEONG CHITUEUMSSANGCIEUC + +01150 +HANGUL CHOSEONG CEONGCHIEUMCIEUC + +01151 +HANGUL CHOSEONG CEONGCHIEUMSSANGCIEUC + +01152 +HANGUL CHOSEONG CHIEUCH-KHIEUKH + +01153 +HANGUL CHOSEONG CHIEUCH-HIEUH + +01154 +HANGUL CHOSEONG CHITUEUMCHIEUCH + +01155 +HANGUL CHOSEONG CEONGCHIEUMCHIEUCH + +01156 +HANGUL CHOSEONG PHIEUPH-PIEUP + +01157 +HANGUL CHOSEONG KAPYEOUNPHIEUPH + +01158 +HANGUL CHOSEONG SSANGHIEUH + +01159 +HANGUL CHOSEONG YEORINHIEUH + +0115A +HANGUL CHOSEONG KIYEOK-TIKEUT + +0115B +HANGUL CHOSEONG NIEUN-SIOS + +0115C +HANGUL CHOSEONG NIEUN-CIEUC + +0115D +HANGUL CHOSEONG NIEUN-HIEUH + +0115E +HANGUL CHOSEONG TIKEUT-RIEUL + +0115F +HANGUL CHOSEONG FILLER + +01160 +HANGUL JUNGSEONG FILLER + +01161 +HANGUL JUNGSEONG A + +01162 +HANGUL JUNGSEONG AE + +01163 +HANGUL JUNGSEONG YA + +01164 +HANGUL JUNGSEONG YAE + +01165 +HANGUL JUNGSEONG EO + +01166 +HANGUL JUNGSEONG E + +01167 +HANGUL JUNGSEONG YEO + +01168 +HANGUL JUNGSEONG YE + +01169 +HANGUL JUNGSEONG O + +0116A +HANGUL JUNGSEONG WA + +0116B +HANGUL JUNGSEONG WAE + +0116C +HANGUL JUNGSEONG OE + +0116D +HANGUL JUNGSEONG YO + +0116E +HANGUL JUNGSEONG U + +0116F +HANGUL JUNGSEONG WEO + +01170 +HANGUL JUNGSEONG WE + +01171 +HANGUL JUNGSEONG WI + +01172 +HANGUL JUNGSEONG YU + +01173 +HANGUL JUNGSEONG EU + +01174 +HANGUL JUNGSEONG YI + +01175 +HANGUL JUNGSEONG I + +01176 +HANGUL JUNGSEONG A-O + +01177 +HANGUL JUNGSEONG A-U + +01178 +HANGUL JUNGSEONG YA-O + +01179 +HANGUL JUNGSEONG YA-YO + +0117A +HANGUL JUNGSEONG EO-O + +0117B +HANGUL JUNGSEONG EO-U + +0117C +HANGUL JUNGSEONG EO-EU + +0117D +HANGUL JUNGSEONG YEO-O + +0117E +HANGUL JUNGSEONG YEO-U + +0117F +HANGUL JUNGSEONG O-EO + +01180 +HANGUL JUNGSEONG O-E + +01181 +HANGUL JUNGSEONG O-YE + +01182 +HANGUL JUNGSEONG O-O + +01183 +HANGUL JUNGSEONG O-U + +01184 +HANGUL JUNGSEONG YO-YA + +01185 +HANGUL JUNGSEONG YO-YAE + +01186 +HANGUL JUNGSEONG YO-YEO + +01187 +HANGUL JUNGSEONG YO-O + +01188 +HANGUL JUNGSEONG YO-I + +01189 +HANGUL JUNGSEONG U-A + +0118A +HANGUL JUNGSEONG U-AE + +0118B +HANGUL JUNGSEONG U-EO-EU + +0118C +HANGUL JUNGSEONG U-YE + +0118D +HANGUL JUNGSEONG U-U + +0118E +HANGUL JUNGSEONG YU-A + +0118F +HANGUL JUNGSEONG YU-EO + +01190 +HANGUL JUNGSEONG YU-E + +01191 +HANGUL JUNGSEONG YU-YEO + +01192 +HANGUL JUNGSEONG YU-YE + +01193 +HANGUL JUNGSEONG YU-U + +01194 +HANGUL JUNGSEONG YU-I + +01195 +HANGUL JUNGSEONG EU-U + +01196 +HANGUL JUNGSEONG EU-EU + +01197 +HANGUL JUNGSEONG YI-U + +01198 +HANGUL JUNGSEONG I-A + +01199 +HANGUL JUNGSEONG I-YA + +0119A +HANGUL JUNGSEONG I-O + +0119B +HANGUL JUNGSEONG I-U + +0119C +HANGUL JUNGSEONG I-EU + +0119D +HANGUL JUNGSEONG I-ARAEA + +0119E +HANGUL JUNGSEONG ARAEA + +0119F +HANGUL JUNGSEONG ARAEA-EO + +011A0 +HANGUL JUNGSEONG ARAEA-U + +011A1 +HANGUL JUNGSEONG ARAEA-I + +011A2 +HANGUL JUNGSEONG SSANGARAEA + +011A3 +HANGUL JUNGSEONG A-EU + +011A4 +HANGUL JUNGSEONG YA-U + +011A5 +HANGUL JUNGSEONG YEO-YA + +011A6 +HANGUL JUNGSEONG O-YA + +011A7 +HANGUL JUNGSEONG O-YAE + +011A8 +HANGUL JONGSEONG KIYEOK + +011A9 +HANGUL JONGSEONG SSANGKIYEOK + +011AA +HANGUL JONGSEONG KIYEOK-SIOS + +011AB +HANGUL JONGSEONG NIEUN + +011AC +HANGUL JONGSEONG NIEUN-CIEUC + +011AD +HANGUL JONGSEONG NIEUN-HIEUH + +011AE +HANGUL JONGSEONG TIKEUT + +011AF +HANGUL JONGSEONG RIEUL + +011B0 +HANGUL JONGSEONG RIEUL-KIYEOK + +011B1 +HANGUL JONGSEONG RIEUL-MIEUM + +011B2 +HANGUL JONGSEONG RIEUL-PIEUP + +011B3 +HANGUL JONGSEONG RIEUL-SIOS + +011B4 +HANGUL JONGSEONG RIEUL-THIEUTH + +011B5 +HANGUL JONGSEONG RIEUL-PHIEUPH + +011B6 +HANGUL JONGSEONG RIEUL-HIEUH + +011B7 +HANGUL JONGSEONG MIEUM + +011B8 +HANGUL JONGSEONG PIEUP + +011B9 +HANGUL JONGSEONG PIEUP-SIOS + +011BA +HANGUL JONGSEONG SIOS + +011BB +HANGUL JONGSEONG SSANGSIOS + +011BC +HANGUL JONGSEONG IEUNG + +011BD +HANGUL JONGSEONG CIEUC + +011BE +HANGUL JONGSEONG CHIEUCH + +011BF +HANGUL JONGSEONG KHIEUKH + +011C0 +HANGUL JONGSEONG THIEUTH + +011C1 +HANGUL JONGSEONG PHIEUPH + +011C2 +HANGUL JONGSEONG HIEUH + +011C3 +HANGUL JONGSEONG KIYEOK-RIEUL + +011C4 +HANGUL JONGSEONG KIYEOK-SIOS-KIYEOK + +011C5 +HANGUL JONGSEONG NIEUN-KIYEOK + +011C6 +HANGUL JONGSEONG NIEUN-TIKEUT + +011C7 +HANGUL JONGSEONG NIEUN-SIOS + +011C8 +HANGUL JONGSEONG NIEUN-PANSIOS + +011C9 +HANGUL JONGSEONG NIEUN-THIEUTH + +011CA +HANGUL JONGSEONG TIKEUT-KIYEOK + +011CB +HANGUL JONGSEONG TIKEUT-RIEUL + +011CC +HANGUL JONGSEONG RIEUL-KIYEOK-SIOS + +011CD +HANGUL JONGSEONG RIEUL-NIEUN + +011CE +HANGUL JONGSEONG RIEUL-TIKEUT + +011CF +HANGUL JONGSEONG RIEUL-TIKEUT-HIEUH + +011D0 +HANGUL JONGSEONG SSANGRIEUL + +011D1 +HANGUL JONGSEONG RIEUL-MIEUM-KIYEOK + +011D2 +HANGUL JONGSEONG RIEUL-MIEUM-SIOS + +011D3 +HANGUL JONGSEONG RIEUL-PIEUP-SIOS + +011D4 +HANGUL JONGSEONG RIEUL-PIEUP-HIEUH + +011D5 +HANGUL JONGSEONG RIEUL-KAPYEOUNPIEUP + +011D6 +HANGUL JONGSEONG RIEUL-SSANGSIOS + +011D7 +HANGUL JONGSEONG RIEUL-PANSIOS + +011D8 +HANGUL JONGSEONG RIEUL-KHIEUKH + +011D9 +HANGUL JONGSEONG RIEUL-YEORINHIEUH + +011DA +HANGUL JONGSEONG MIEUM-KIYEOK + +011DB +HANGUL JONGSEONG MIEUM-RIEUL + +011DC +HANGUL JONGSEONG MIEUM-PIEUP + +011DD +HANGUL JONGSEONG MIEUM-SIOS + +011DE +HANGUL JONGSEONG MIEUM-SSANGSIOS + +011DF +HANGUL JONGSEONG MIEUM-PANSIOS + +011E0 +HANGUL JONGSEONG MIEUM-CHIEUCH + +011E1 +HANGUL JONGSEONG MIEUM-HIEUH + +011E2 +HANGUL JONGSEONG KAPYEOUNMIEUM + +011E3 +HANGUL JONGSEONG PIEUP-RIEUL + +011E4 +HANGUL JONGSEONG PIEUP-PHIEUPH + +011E5 +HANGUL JONGSEONG PIEUP-HIEUH + +011E6 +HANGUL JONGSEONG KAPYEOUNPIEUP + +011E7 +HANGUL JONGSEONG SIOS-KIYEOK + +011E8 +HANGUL JONGSEONG SIOS-TIKEUT + +011E9 +HANGUL JONGSEONG SIOS-RIEUL + +011EA +HANGUL JONGSEONG SIOS-PIEUP + +011EB +HANGUL JONGSEONG PANSIOS + +011EC +HANGUL JONGSEONG YESIEUNG-KIYEOK + +011EC +HANGUL JONGSEONG IEUNG-KIYEOK + +011ED +HANGUL JONGSEONG YESIEUNG-SSANGKIYEOK + +011ED +HANGUL JONGSEONG IEUNG-SSANGKIYEOK + +011EE +HANGUL JONGSEONG SSANGYESIEUNG + +011EE +HANGUL JONGSEONG SSANGIEUNG + +011EF +HANGUL JONGSEONG YESIEUNG-KHIEUKH + +011EF +HANGUL JONGSEONG IEUNG-KHIEUKH + +011F0 +HANGUL JONGSEONG YESIEUNG + +011F1 +HANGUL JONGSEONG YESIEUNG-SIOS + +011F2 +HANGUL JONGSEONG YESIEUNG-PANSIOS + +011F3 +HANGUL JONGSEONG PHIEUPH-PIEUP + +011F4 +HANGUL JONGSEONG KAPYEOUNPHIEUPH + +011F5 +HANGUL JONGSEONG HIEUH-NIEUN + +011F6 +HANGUL JONGSEONG HIEUH-RIEUL + +011F7 +HANGUL JONGSEONG HIEUH-MIEUM + +011F8 +HANGUL JONGSEONG HIEUH-PIEUP + +011F9 +HANGUL JONGSEONG YEORINHIEUH + +011FA +HANGUL JONGSEONG KIYEOK-NIEUN + +011FB +HANGUL JONGSEONG KIYEOK-PIEUP + +011FC +HANGUL JONGSEONG KIYEOK-CHIEUCH + +011FD +HANGUL JONGSEONG KIYEOK-KHIEUKH + +011FE +HANGUL JONGSEONG KIYEOK-HIEUH + +011FF +HANGUL JONGSEONG SSANGNIEUN + +01200 +ETHIOPIC SYLLABLE HA + +01201 +ETHIOPIC SYLLABLE HU + +01202 +ETHIOPIC SYLLABLE HI + +01203 +ETHIOPIC SYLLABLE HAA + +01204 +ETHIOPIC SYLLABLE HEE + +01205 +ETHIOPIC SYLLABLE HE + +01206 +ETHIOPIC SYLLABLE HO + +01207 +ETHIOPIC SYLLABLE HOA + +01208 +ETHIOPIC SYLLABLE LA + +01209 +ETHIOPIC SYLLABLE LU + +0120A +ETHIOPIC SYLLABLE LI + +0120B +ETHIOPIC SYLLABLE LAA + +0120C +ETHIOPIC SYLLABLE LEE + +0120D +ETHIOPIC SYLLABLE LE + +0120E +ETHIOPIC SYLLABLE LO + +0120F +ETHIOPIC SYLLABLE LWA + +01210 +ETHIOPIC SYLLABLE HHA + +01211 +ETHIOPIC SYLLABLE HHU + +01212 +ETHIOPIC SYLLABLE HHI + +01213 +ETHIOPIC SYLLABLE HHAA + +01214 +ETHIOPIC SYLLABLE HHEE + +01215 +ETHIOPIC SYLLABLE HHE + +01216 +ETHIOPIC SYLLABLE HHO + +01217 +ETHIOPIC SYLLABLE HHWA + +01218 +ETHIOPIC SYLLABLE MA + +01219 +ETHIOPIC SYLLABLE MU + +0121A +ETHIOPIC SYLLABLE MI + +0121B +ETHIOPIC SYLLABLE MAA + +0121C +ETHIOPIC SYLLABLE MEE + +0121D +ETHIOPIC SYLLABLE ME + +0121E +ETHIOPIC SYLLABLE MO + +0121F +ETHIOPIC SYLLABLE MWA + +01220 +ETHIOPIC SYLLABLE SZA + +01221 +ETHIOPIC SYLLABLE SZU + +01222 +ETHIOPIC SYLLABLE SZI + +01223 +ETHIOPIC SYLLABLE SZAA + +01224 +ETHIOPIC SYLLABLE SZEE + +01225 +ETHIOPIC SYLLABLE SZE + +01226 +ETHIOPIC SYLLABLE SZO + +01227 +ETHIOPIC SYLLABLE SZWA + +01228 +ETHIOPIC SYLLABLE RA + +01229 +ETHIOPIC SYLLABLE RU + +0122A +ETHIOPIC SYLLABLE RI + +0122B +ETHIOPIC SYLLABLE RAA + +0122C +ETHIOPIC SYLLABLE REE + +0122D +ETHIOPIC SYLLABLE RE + +0122E +ETHIOPIC SYLLABLE RO + +0122F +ETHIOPIC SYLLABLE RWA + +01230 +ETHIOPIC SYLLABLE SA + +01231 +ETHIOPIC SYLLABLE SU + +01232 +ETHIOPIC SYLLABLE SI + +01233 +ETHIOPIC SYLLABLE SAA + +01234 +ETHIOPIC SYLLABLE SEE + +01235 +ETHIOPIC SYLLABLE SE + +01236 +ETHIOPIC SYLLABLE SO + +01237 +ETHIOPIC SYLLABLE SWA + +01238 +ETHIOPIC SYLLABLE SHA + +01239 +ETHIOPIC SYLLABLE SHU + +0123A +ETHIOPIC SYLLABLE SHI + +0123B +ETHIOPIC SYLLABLE SHAA + +0123C +ETHIOPIC SYLLABLE SHEE + +0123D +ETHIOPIC SYLLABLE SHE + +0123E +ETHIOPIC SYLLABLE SHO + +0123F +ETHIOPIC SYLLABLE SHWA + +01240 +ETHIOPIC SYLLABLE QA + +01241 +ETHIOPIC SYLLABLE QU + +01242 +ETHIOPIC SYLLABLE QI + +01243 +ETHIOPIC SYLLABLE QAA + +01244 +ETHIOPIC SYLLABLE QEE + +01245 +ETHIOPIC SYLLABLE QE + +01246 +ETHIOPIC SYLLABLE QO + +01247 +ETHIOPIC SYLLABLE QOA + +01248 +ETHIOPIC SYLLABLE QWA + +0124A +ETHIOPIC SYLLABLE QWI + +0124B +ETHIOPIC SYLLABLE QWAA + +0124C +ETHIOPIC SYLLABLE QWEE + +0124D +ETHIOPIC SYLLABLE QWE + +01250 +ETHIOPIC SYLLABLE QHA + +01251 +ETHIOPIC SYLLABLE QHU + +01252 +ETHIOPIC SYLLABLE QHI + +01253 +ETHIOPIC SYLLABLE QHAA + +01254 +ETHIOPIC SYLLABLE QHEE + +01255 +ETHIOPIC SYLLABLE QHE + +01256 +ETHIOPIC SYLLABLE QHO + +01258 +ETHIOPIC SYLLABLE QHWA + +0125A +ETHIOPIC SYLLABLE QHWI + +0125B +ETHIOPIC SYLLABLE QHWAA + +0125C +ETHIOPIC SYLLABLE QHWEE + +0125D +ETHIOPIC SYLLABLE QHWE + +01260 +ETHIOPIC SYLLABLE BA + +01261 +ETHIOPIC SYLLABLE BU + +01262 +ETHIOPIC SYLLABLE BI + +01263 +ETHIOPIC SYLLABLE BAA + +01264 +ETHIOPIC SYLLABLE BEE + +01265 +ETHIOPIC SYLLABLE BE + +01266 +ETHIOPIC SYLLABLE BO + +01267 +ETHIOPIC SYLLABLE BWA + +01268 +ETHIOPIC SYLLABLE VA + +01269 +ETHIOPIC SYLLABLE VU + +0126A +ETHIOPIC SYLLABLE VI + +0126B +ETHIOPIC SYLLABLE VAA + +0126C +ETHIOPIC SYLLABLE VEE + +0126D +ETHIOPIC SYLLABLE VE + +0126E +ETHIOPIC SYLLABLE VO + +0126F +ETHIOPIC SYLLABLE VWA + +01270 +ETHIOPIC SYLLABLE TA + +01271 +ETHIOPIC SYLLABLE TU + +01272 +ETHIOPIC SYLLABLE TI + +01273 +ETHIOPIC SYLLABLE TAA + +01274 +ETHIOPIC SYLLABLE TEE + +01275 +ETHIOPIC SYLLABLE TE + +01276 +ETHIOPIC SYLLABLE TO + +01277 +ETHIOPIC SYLLABLE TWA + +01278 +ETHIOPIC SYLLABLE CA + +01279 +ETHIOPIC SYLLABLE CU + +0127A +ETHIOPIC SYLLABLE CI + +0127B +ETHIOPIC SYLLABLE CAA + +0127C +ETHIOPIC SYLLABLE CEE + +0127D +ETHIOPIC SYLLABLE CE + +0127E +ETHIOPIC SYLLABLE CO + +0127F +ETHIOPIC SYLLABLE CWA + +01280 +ETHIOPIC SYLLABLE XA + +01281 +ETHIOPIC SYLLABLE XU + +01282 +ETHIOPIC SYLLABLE XI + +01283 +ETHIOPIC SYLLABLE XAA + +01284 +ETHIOPIC SYLLABLE XEE + +01285 +ETHIOPIC SYLLABLE XE + +01286 +ETHIOPIC SYLLABLE XO + +01287 +ETHIOPIC SYLLABLE XOA + +01288 +ETHIOPIC SYLLABLE XWA + +0128A +ETHIOPIC SYLLABLE XWI + +0128B +ETHIOPIC SYLLABLE XWAA + +0128C +ETHIOPIC SYLLABLE XWEE + +0128D +ETHIOPIC SYLLABLE XWE + +01290 +ETHIOPIC SYLLABLE NA + +01291 +ETHIOPIC SYLLABLE NU + +01292 +ETHIOPIC SYLLABLE NI + +01293 +ETHIOPIC SYLLABLE NAA + +01294 +ETHIOPIC SYLLABLE NEE + +01295 +ETHIOPIC SYLLABLE NE + +01296 +ETHIOPIC SYLLABLE NO + +01297 +ETHIOPIC SYLLABLE NWA + +01298 +ETHIOPIC SYLLABLE NYA + +01299 +ETHIOPIC SYLLABLE NYU + +0129A +ETHIOPIC SYLLABLE NYI + +0129B +ETHIOPIC SYLLABLE NYAA + +0129C +ETHIOPIC SYLLABLE NYEE + +0129D +ETHIOPIC SYLLABLE NYE + +0129E +ETHIOPIC SYLLABLE NYO + +0129F +ETHIOPIC SYLLABLE NYWA + +012A0 +ETHIOPIC SYLLABLE GLOTTAL A + +012A1 +ETHIOPIC SYLLABLE GLOTTAL U + +012A2 +ETHIOPIC SYLLABLE GLOTTAL I + +012A3 +ETHIOPIC SYLLABLE GLOTTAL AA + +012A4 +ETHIOPIC SYLLABLE GLOTTAL EE + +012A5 +ETHIOPIC SYLLABLE GLOTTAL E + +012A6 +ETHIOPIC SYLLABLE GLOTTAL O + +012A7 +ETHIOPIC SYLLABLE GLOTTAL WA + +012A8 +ETHIOPIC SYLLABLE KA + +012A9 +ETHIOPIC SYLLABLE KU + +012AA +ETHIOPIC SYLLABLE KI + +012AB +ETHIOPIC SYLLABLE KAA + +012AC +ETHIOPIC SYLLABLE KEE + +012AD +ETHIOPIC SYLLABLE KE + +012AE +ETHIOPIC SYLLABLE KO + +012AF +ETHIOPIC SYLLABLE KOA + +012B0 +ETHIOPIC SYLLABLE KWA + +012B2 +ETHIOPIC SYLLABLE KWI + +012B3 +ETHIOPIC SYLLABLE KWAA + +012B4 +ETHIOPIC SYLLABLE KWEE + +012B5 +ETHIOPIC SYLLABLE KWE + +012B8 +ETHIOPIC SYLLABLE KXA + +012B9 +ETHIOPIC SYLLABLE KXU + +012BA +ETHIOPIC SYLLABLE KXI + +012BB +ETHIOPIC SYLLABLE KXAA + +012BC +ETHIOPIC SYLLABLE KXEE + +012BD +ETHIOPIC SYLLABLE KXE + +012BE +ETHIOPIC SYLLABLE KXO + +012C0 +ETHIOPIC SYLLABLE KXWA + +012C2 +ETHIOPIC SYLLABLE KXWI + +012C3 +ETHIOPIC SYLLABLE KXWAA + +012C4 +ETHIOPIC SYLLABLE KXWEE + +012C5 +ETHIOPIC SYLLABLE KXWE + +012C8 +ETHIOPIC SYLLABLE WA + +012C9 +ETHIOPIC SYLLABLE WU + +012CA +ETHIOPIC SYLLABLE WI + +012CB +ETHIOPIC SYLLABLE WAA + +012CC +ETHIOPIC SYLLABLE WEE + +012CD +ETHIOPIC SYLLABLE WE + +012CE +ETHIOPIC SYLLABLE WO + +012CF +ETHIOPIC SYLLABLE WOA + +012D0 +ETHIOPIC SYLLABLE PHARYNGEAL A + +012D1 +ETHIOPIC SYLLABLE PHARYNGEAL U + +012D2 +ETHIOPIC SYLLABLE PHARYNGEAL I + +012D3 +ETHIOPIC SYLLABLE PHARYNGEAL AA + +012D4 +ETHIOPIC SYLLABLE PHARYNGEAL EE + +012D5 +ETHIOPIC SYLLABLE PHARYNGEAL E + +012D6 +ETHIOPIC SYLLABLE PHARYNGEAL O + +012D8 +ETHIOPIC SYLLABLE ZA + +012D9 +ETHIOPIC SYLLABLE ZU + +012DA +ETHIOPIC SYLLABLE ZI + +012DB +ETHIOPIC SYLLABLE ZAA + +012DC +ETHIOPIC SYLLABLE ZEE + +012DD +ETHIOPIC SYLLABLE ZE + +012DE +ETHIOPIC SYLLABLE ZO + +012DF +ETHIOPIC SYLLABLE ZWA + +012E0 +ETHIOPIC SYLLABLE ZHA + +012E1 +ETHIOPIC SYLLABLE ZHU + +012E2 +ETHIOPIC SYLLABLE ZHI + +012E3 +ETHIOPIC SYLLABLE ZHAA + +012E4 +ETHIOPIC SYLLABLE ZHEE + +012E5 +ETHIOPIC SYLLABLE ZHE + +012E6 +ETHIOPIC SYLLABLE ZHO + +012E7 +ETHIOPIC SYLLABLE ZHWA + +012E8 +ETHIOPIC SYLLABLE YA + +012E9 +ETHIOPIC SYLLABLE YU + +012EA +ETHIOPIC SYLLABLE YI + +012EB +ETHIOPIC SYLLABLE YAA + +012EC +ETHIOPIC SYLLABLE YEE + +012ED +ETHIOPIC SYLLABLE YE + +012EE +ETHIOPIC SYLLABLE YO + +012EF +ETHIOPIC SYLLABLE YOA + +012F0 +ETHIOPIC SYLLABLE DA + +012F1 +ETHIOPIC SYLLABLE DU + +012F2 +ETHIOPIC SYLLABLE DI + +012F3 +ETHIOPIC SYLLABLE DAA + +012F4 +ETHIOPIC SYLLABLE DEE + +012F5 +ETHIOPIC SYLLABLE DE + +012F6 +ETHIOPIC SYLLABLE DO + +012F7 +ETHIOPIC SYLLABLE DWA + +012F8 +ETHIOPIC SYLLABLE DDA + +012F9 +ETHIOPIC SYLLABLE DDU + +012FA +ETHIOPIC SYLLABLE DDI + +012FB +ETHIOPIC SYLLABLE DDAA + +012FC +ETHIOPIC SYLLABLE DDEE + +012FD +ETHIOPIC SYLLABLE DDE + +012FE +ETHIOPIC SYLLABLE DDO + +012FF +ETHIOPIC SYLLABLE DDWA + +01300 +ETHIOPIC SYLLABLE JA + +01301 +ETHIOPIC SYLLABLE JU + +01302 +ETHIOPIC SYLLABLE JI + +01303 +ETHIOPIC SYLLABLE JAA + +01304 +ETHIOPIC SYLLABLE JEE + +01305 +ETHIOPIC SYLLABLE JE + +01306 +ETHIOPIC SYLLABLE JO + +01307 +ETHIOPIC SYLLABLE JWA + +01308 +ETHIOPIC SYLLABLE GA + +01309 +ETHIOPIC SYLLABLE GU + +0130A +ETHIOPIC SYLLABLE GI + +0130B +ETHIOPIC SYLLABLE GAA + +0130C +ETHIOPIC SYLLABLE GEE + +0130D +ETHIOPIC SYLLABLE GE + +0130E +ETHIOPIC SYLLABLE GO + +0130F +ETHIOPIC SYLLABLE GOA + +01310 +ETHIOPIC SYLLABLE GWA + +01312 +ETHIOPIC SYLLABLE GWI + +01313 +ETHIOPIC SYLLABLE GWAA + +01314 +ETHIOPIC SYLLABLE GWEE + +01315 +ETHIOPIC SYLLABLE GWE + +01318 +ETHIOPIC SYLLABLE GGA + +01319 +ETHIOPIC SYLLABLE GGU + +0131A +ETHIOPIC SYLLABLE GGI + +0131B +ETHIOPIC SYLLABLE GGAA + +0131C +ETHIOPIC SYLLABLE GGEE + +0131D +ETHIOPIC SYLLABLE GGE + +0131E +ETHIOPIC SYLLABLE GGO + +0131F +ETHIOPIC SYLLABLE GGWAA + +01320 +ETHIOPIC SYLLABLE THA + +01321 +ETHIOPIC SYLLABLE THU + +01322 +ETHIOPIC SYLLABLE THI + +01323 +ETHIOPIC SYLLABLE THAA + +01324 +ETHIOPIC SYLLABLE THEE + +01325 +ETHIOPIC SYLLABLE THE + +01326 +ETHIOPIC SYLLABLE THO + +01327 +ETHIOPIC SYLLABLE THWA + +01328 +ETHIOPIC SYLLABLE CHA + +01329 +ETHIOPIC SYLLABLE CHU + +0132A +ETHIOPIC SYLLABLE CHI + +0132B +ETHIOPIC SYLLABLE CHAA + +0132C +ETHIOPIC SYLLABLE CHEE + +0132D +ETHIOPIC SYLLABLE CHE + +0132E +ETHIOPIC SYLLABLE CHO + +0132F +ETHIOPIC SYLLABLE CHWA + +01330 +ETHIOPIC SYLLABLE PHA + +01331 +ETHIOPIC SYLLABLE PHU + +01332 +ETHIOPIC SYLLABLE PHI + +01333 +ETHIOPIC SYLLABLE PHAA + +01334 +ETHIOPIC SYLLABLE PHEE + +01335 +ETHIOPIC SYLLABLE PHE + +01336 +ETHIOPIC SYLLABLE PHO + +01337 +ETHIOPIC SYLLABLE PHWA + +01338 +ETHIOPIC SYLLABLE TSA + +01339 +ETHIOPIC SYLLABLE TSU + +0133A +ETHIOPIC SYLLABLE TSI + +0133B +ETHIOPIC SYLLABLE TSAA + +0133C +ETHIOPIC SYLLABLE TSEE + +0133D +ETHIOPIC SYLLABLE TSE + +0133E +ETHIOPIC SYLLABLE TSO + +0133F +ETHIOPIC SYLLABLE TSWA + +01340 +ETHIOPIC SYLLABLE TZA + +01341 +ETHIOPIC SYLLABLE TZU + +01342 +ETHIOPIC SYLLABLE TZI + +01343 +ETHIOPIC SYLLABLE TZAA + +01344 +ETHIOPIC SYLLABLE TZEE + +01345 +ETHIOPIC SYLLABLE TZE + +01346 +ETHIOPIC SYLLABLE TZO + +01347 +ETHIOPIC SYLLABLE TZOA + +01348 +ETHIOPIC SYLLABLE FA + +01349 +ETHIOPIC SYLLABLE FU + +0134A +ETHIOPIC SYLLABLE FI + +0134B +ETHIOPIC SYLLABLE FAA + +0134C +ETHIOPIC SYLLABLE FEE + +0134D +ETHIOPIC SYLLABLE FE + +0134E +ETHIOPIC SYLLABLE FO + +0134F +ETHIOPIC SYLLABLE FWA + +01350 +ETHIOPIC SYLLABLE PA + +01351 +ETHIOPIC SYLLABLE PU + +01352 +ETHIOPIC SYLLABLE PI + +01353 +ETHIOPIC SYLLABLE PAA + +01354 +ETHIOPIC SYLLABLE PEE + +01355 +ETHIOPIC SYLLABLE PE + +01356 +ETHIOPIC SYLLABLE PO + +01357 +ETHIOPIC SYLLABLE PWA + +01358 +ETHIOPIC SYLLABLE RYA + +01359 +ETHIOPIC SYLLABLE MYA + +0135A +ETHIOPIC SYLLABLE FYA + +0135D +ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK + +0135E +ETHIOPIC COMBINING VOWEL LENGTH MARK + +0135F +ETHIOPIC COMBINING GEMINATION MARK + +01360 +ETHIOPIC SECTION MARK + +01361 +ETHIOPIC WORDSPACE + +01362 +ETHIOPIC FULL STOP + +01363 +ETHIOPIC COMMA + +01364 +ETHIOPIC SEMICOLON + +01365 +ETHIOPIC COLON + +01366 +ETHIOPIC PREFACE COLON + +01367 +ETHIOPIC QUESTION MARK + +01368 +ETHIOPIC PARAGRAPH SEPARATOR + +01369 +ETHIOPIC DIGIT ONE + +0136A +ETHIOPIC DIGIT TWO + +0136B +ETHIOPIC DIGIT THREE + +0136C +ETHIOPIC DIGIT FOUR + +0136D +ETHIOPIC DIGIT FIVE + +0136E +ETHIOPIC DIGIT SIX + +0136F +ETHIOPIC DIGIT SEVEN + +01370 +ETHIOPIC DIGIT EIGHT + +01371 +ETHIOPIC DIGIT NINE + +01372 +ETHIOPIC NUMBER TEN + +01373 +ETHIOPIC NUMBER TWENTY + +01374 +ETHIOPIC NUMBER THIRTY + +01375 +ETHIOPIC NUMBER FORTY + +01376 +ETHIOPIC NUMBER FIFTY + +01377 +ETHIOPIC NUMBER SIXTY + +01378 +ETHIOPIC NUMBER SEVENTY + +01379 +ETHIOPIC NUMBER EIGHTY + +0137A +ETHIOPIC NUMBER NINETY + +0137B +ETHIOPIC NUMBER HUNDRED + +0137C +ETHIOPIC NUMBER TEN THOUSAND + +01380 +ETHIOPIC SYLLABLE SEBATBEIT MWA + +01381 +ETHIOPIC SYLLABLE MWI + +01382 +ETHIOPIC SYLLABLE MWEE + +01383 +ETHIOPIC SYLLABLE MWE + +01384 +ETHIOPIC SYLLABLE SEBATBEIT BWA + +01385 +ETHIOPIC SYLLABLE BWI + +01386 +ETHIOPIC SYLLABLE BWEE + +01387 +ETHIOPIC SYLLABLE BWE + +01388 +ETHIOPIC SYLLABLE SEBATBEIT FWA + +01389 +ETHIOPIC SYLLABLE FWI + +0138A +ETHIOPIC SYLLABLE FWEE + +0138B +ETHIOPIC SYLLABLE FWE + +0138C +ETHIOPIC SYLLABLE SEBATBEIT PWA + +0138D +ETHIOPIC SYLLABLE PWI + +0138E +ETHIOPIC SYLLABLE PWEE + +0138F +ETHIOPIC SYLLABLE PWE + +01390 +ETHIOPIC TONAL MARK YIZET + +01391 +ETHIOPIC TONAL MARK DERET + +01392 +ETHIOPIC TONAL MARK RIKRIK + +01393 +ETHIOPIC TONAL MARK SHORT RIKRIK + +01394 +ETHIOPIC TONAL MARK DIFAT + +01395 +ETHIOPIC TONAL MARK KENAT + +01396 +ETHIOPIC TONAL MARK CHIRET + +01397 +ETHIOPIC TONAL MARK HIDET + +01398 +ETHIOPIC TONAL MARK DERET-HIDET + +01399 +ETHIOPIC TONAL MARK KURT + +013A0 +CHEROKEE LETTER A + +013A1 +CHEROKEE LETTER E + +013A2 +CHEROKEE LETTER I + +013A3 +CHEROKEE LETTER O + +013A4 +CHEROKEE LETTER U + +013A5 +CHEROKEE LETTER V + +013A6 +CHEROKEE LETTER GA + +013A7 +CHEROKEE LETTER KA + +013A8 +CHEROKEE LETTER GE + +013A9 +CHEROKEE LETTER GI + +013AA +CHEROKEE LETTER GO + +013AB +CHEROKEE LETTER GU + +013AC +CHEROKEE LETTER GV + +013AD +CHEROKEE LETTER HA + +013AE +CHEROKEE LETTER HE + +013AF +CHEROKEE LETTER HI + +013B0 +CHEROKEE LETTER HO + +013B1 +CHEROKEE LETTER HU + +013B2 +CHEROKEE LETTER HV + +013B3 +CHEROKEE LETTER LA + +013B4 +CHEROKEE LETTER LE + +013B5 +CHEROKEE LETTER LI + +013B6 +CHEROKEE LETTER LO + +013B7 +CHEROKEE LETTER LU + +013B8 +CHEROKEE LETTER LV + +013B9 +CHEROKEE LETTER MA + +013BA +CHEROKEE LETTER ME + +013BB +CHEROKEE LETTER MI + +013BC +CHEROKEE LETTER MO + +013BD +CHEROKEE LETTER MU + +013BE +CHEROKEE LETTER NA + +013BF +CHEROKEE LETTER HNA + +013C0 +CHEROKEE LETTER NAH + +013C1 +CHEROKEE LETTER NE + +013C2 +CHEROKEE LETTER NI + +013C3 +CHEROKEE LETTER NO + +013C4 +CHEROKEE LETTER NU + +013C5 +CHEROKEE LETTER NV + +013C6 +CHEROKEE LETTER QUA + +013C7 +CHEROKEE LETTER QUE + +013C8 +CHEROKEE LETTER QUI + +013C9 +CHEROKEE LETTER QUO + +013CA +CHEROKEE LETTER QUU + +013CB +CHEROKEE LETTER QUV + +013CC +CHEROKEE LETTER SA + +013CD +CHEROKEE LETTER S + +013CE +CHEROKEE LETTER SE + +013CF +CHEROKEE LETTER SI + +013D0 +CHEROKEE LETTER SO + +013D1 +CHEROKEE LETTER SU + +013D2 +CHEROKEE LETTER SV + +013D3 +CHEROKEE LETTER DA + +013D4 +CHEROKEE LETTER TA + +013D5 +CHEROKEE LETTER DE + +013D6 +CHEROKEE LETTER TE + +013D7 +CHEROKEE LETTER DI + +013D8 +CHEROKEE LETTER TI + +013D9 +CHEROKEE LETTER DO + +013DA +CHEROKEE LETTER DU + +013DB +CHEROKEE LETTER DV + +013DC +CHEROKEE LETTER DLA + +013DD +CHEROKEE LETTER TLA + +013DE +CHEROKEE LETTER TLE + +013DF +CHEROKEE LETTER TLI + +013E0 +CHEROKEE LETTER TLO + +013E1 +CHEROKEE LETTER TLU + +013E2 +CHEROKEE LETTER TLV + +013E3 +CHEROKEE LETTER TSA + +013E4 +CHEROKEE LETTER TSE + +013E5 +CHEROKEE LETTER TSI + +013E6 +CHEROKEE LETTER TSO + +013E7 +CHEROKEE LETTER TSU + +013E8 +CHEROKEE LETTER TSV + +013E9 +CHEROKEE LETTER WA + +013EA +CHEROKEE LETTER WE + +013EB +CHEROKEE LETTER WI + +013EC +CHEROKEE LETTER WO + +013ED +CHEROKEE LETTER WU + +013EE +CHEROKEE LETTER WV + +013EF +CHEROKEE LETTER YA + +013F0 +CHEROKEE LETTER YE + +013F1 +CHEROKEE LETTER YI + +013F2 +CHEROKEE LETTER YO + +013F3 +CHEROKEE LETTER YU + +013F4 +CHEROKEE LETTER YV + +013F5 +CHEROKEE LETTER MV + +013F8 +CHEROKEE SMALL LETTER YE + +013F9 +CHEROKEE SMALL LETTER YI + +013FA +CHEROKEE SMALL LETTER YO + +013FB +CHEROKEE SMALL LETTER YU + +013FC +CHEROKEE SMALL LETTER YV + +013FD +CHEROKEE SMALL LETTER MV + +01400 +CANADIAN SYLLABICS HYPHEN + +01401 +CANADIAN SYLLABICS E + +01402 +CANADIAN SYLLABICS AAI + +01403 +CANADIAN SYLLABICS I + +01404 +CANADIAN SYLLABICS II + +01405 +CANADIAN SYLLABICS O + +01406 +CANADIAN SYLLABICS OO + +01407 +CANADIAN SYLLABICS Y-CREE OO + +01408 +CANADIAN SYLLABICS CARRIER EE + +01409 +CANADIAN SYLLABICS CARRIER I + +0140A +CANADIAN SYLLABICS A + +0140B +CANADIAN SYLLABICS AA + +0140C +CANADIAN SYLLABICS WE + +0140D +CANADIAN SYLLABICS WEST-CREE WE + +0140E +CANADIAN SYLLABICS WI + +0140F +CANADIAN SYLLABICS WEST-CREE WI + +01410 +CANADIAN SYLLABICS WII + +01411 +CANADIAN SYLLABICS WEST-CREE WII + +01412 +CANADIAN SYLLABICS WO + +01413 +CANADIAN SYLLABICS WEST-CREE WO + +01414 +CANADIAN SYLLABICS WOO + +01415 +CANADIAN SYLLABICS WEST-CREE WOO + +01416 +CANADIAN SYLLABICS NASKAPI WOO + +01417 +CANADIAN SYLLABICS WA + +01418 +CANADIAN SYLLABICS WEST-CREE WA + +01419 +CANADIAN SYLLABICS WAA + +0141A +CANADIAN SYLLABICS WEST-CREE WAA + +0141B +CANADIAN SYLLABICS NASKAPI WAA + +0141C +CANADIAN SYLLABICS AI + +0141D +CANADIAN SYLLABICS Y-CREE W + +0141E +CANADIAN SYLLABICS GLOTTAL STOP + +0141F +CANADIAN SYLLABICS FINAL ACUTE + +01420 +CANADIAN SYLLABICS FINAL GRAVE + +01421 +CANADIAN SYLLABICS FINAL BOTTOM HALF RING + +01422 +CANADIAN SYLLABICS FINAL TOP HALF RING + +01423 +CANADIAN SYLLABICS FINAL RIGHT HALF RING + +01424 +CANADIAN SYLLABICS FINAL RING + +01425 +CANADIAN SYLLABICS FINAL DOUBLE ACUTE + +01426 +CANADIAN SYLLABICS FINAL DOUBLE SHORT VERTICAL STROKES + +01427 +CANADIAN SYLLABICS FINAL MIDDLE DOT + +01428 +CANADIAN SYLLABICS FINAL SHORT HORIZONTAL STROKE + +01429 +CANADIAN SYLLABICS FINAL PLUS + +0142A +CANADIAN SYLLABICS FINAL DOWN TACK + +0142B +CANADIAN SYLLABICS EN + +0142C +CANADIAN SYLLABICS IN + +0142D +CANADIAN SYLLABICS ON + +0142E +CANADIAN SYLLABICS AN + +0142F +CANADIAN SYLLABICS PE + +01430 +CANADIAN SYLLABICS PAAI + +01431 +CANADIAN SYLLABICS PI + +01432 +CANADIAN SYLLABICS PII + +01433 +CANADIAN SYLLABICS PO + +01434 +CANADIAN SYLLABICS POO + +01435 +CANADIAN SYLLABICS Y-CREE POO + +01436 +CANADIAN SYLLABICS CARRIER HEE + +01437 +CANADIAN SYLLABICS CARRIER HI + +01438 +CANADIAN SYLLABICS PA + +01439 +CANADIAN SYLLABICS PAA + +0143A +CANADIAN SYLLABICS PWE + +0143B +CANADIAN SYLLABICS WEST-CREE PWE + +0143C +CANADIAN SYLLABICS PWI + +0143D +CANADIAN SYLLABICS WEST-CREE PWI + +0143E +CANADIAN SYLLABICS PWII + +0143F +CANADIAN SYLLABICS WEST-CREE PWII + +01440 +CANADIAN SYLLABICS PWO + +01441 +CANADIAN SYLLABICS WEST-CREE PWO + +01442 +CANADIAN SYLLABICS PWOO + +01443 +CANADIAN SYLLABICS WEST-CREE PWOO + +01444 +CANADIAN SYLLABICS PWA + +01445 +CANADIAN SYLLABICS WEST-CREE PWA + +01446 +CANADIAN SYLLABICS PWAA + +01447 +CANADIAN SYLLABICS WEST-CREE PWAA + +01448 +CANADIAN SYLLABICS Y-CREE PWAA + +01449 +CANADIAN SYLLABICS P + +0144A +CANADIAN SYLLABICS WEST-CREE P + +0144B +CANADIAN SYLLABICS CARRIER H + +0144C +CANADIAN SYLLABICS TE + +0144D +CANADIAN SYLLABICS TAAI + +0144E +CANADIAN SYLLABICS TI + +0144F +CANADIAN SYLLABICS TII + +01450 +CANADIAN SYLLABICS TO + +01451 +CANADIAN SYLLABICS TOO + +01452 +CANADIAN SYLLABICS Y-CREE TOO + +01453 +CANADIAN SYLLABICS CARRIER DEE + +01454 +CANADIAN SYLLABICS CARRIER DI + +01455 +CANADIAN SYLLABICS TA + +01456 +CANADIAN SYLLABICS TAA + +01457 +CANADIAN SYLLABICS TWE + +01458 +CANADIAN SYLLABICS WEST-CREE TWE + +01459 +CANADIAN SYLLABICS TWI + +0145A +CANADIAN SYLLABICS WEST-CREE TWI + +0145B +CANADIAN SYLLABICS TWII + +0145C +CANADIAN SYLLABICS WEST-CREE TWII + +0145D +CANADIAN SYLLABICS TWO + +0145E +CANADIAN SYLLABICS WEST-CREE TWO + +0145F +CANADIAN SYLLABICS TWOO + +01460 +CANADIAN SYLLABICS WEST-CREE TWOO + +01461 +CANADIAN SYLLABICS TWA + +01462 +CANADIAN SYLLABICS WEST-CREE TWA + +01463 +CANADIAN SYLLABICS TWAA + +01464 +CANADIAN SYLLABICS WEST-CREE TWAA + +01465 +CANADIAN SYLLABICS NASKAPI TWAA + +01466 +CANADIAN SYLLABICS T + +01467 +CANADIAN SYLLABICS TTE + +01468 +CANADIAN SYLLABICS TTI + +01469 +CANADIAN SYLLABICS TTO + +0146A +CANADIAN SYLLABICS TTA + +0146B +CANADIAN SYLLABICS KE + +0146C +CANADIAN SYLLABICS KAAI + +0146D +CANADIAN SYLLABICS KI + +0146E +CANADIAN SYLLABICS KII + +0146F +CANADIAN SYLLABICS KO + +01470 +CANADIAN SYLLABICS KOO + +01471 +CANADIAN SYLLABICS Y-CREE KOO + +01472 +CANADIAN SYLLABICS KA + +01473 +CANADIAN SYLLABICS KAA + +01474 +CANADIAN SYLLABICS KWE + +01475 +CANADIAN SYLLABICS WEST-CREE KWE + +01476 +CANADIAN SYLLABICS KWI + +01477 +CANADIAN SYLLABICS WEST-CREE KWI + +01478 +CANADIAN SYLLABICS KWII + +01479 +CANADIAN SYLLABICS WEST-CREE KWII + +0147A +CANADIAN SYLLABICS KWO + +0147B +CANADIAN SYLLABICS WEST-CREE KWO + +0147C +CANADIAN SYLLABICS KWOO + +0147D +CANADIAN SYLLABICS WEST-CREE KWOO + +0147E +CANADIAN SYLLABICS KWA + +0147F +CANADIAN SYLLABICS WEST-CREE KWA + +01480 +CANADIAN SYLLABICS KWAA + +01481 +CANADIAN SYLLABICS WEST-CREE KWAA + +01482 +CANADIAN SYLLABICS NASKAPI KWAA + +01483 +CANADIAN SYLLABICS K + +01484 +CANADIAN SYLLABICS KW + +01485 +CANADIAN SYLLABICS SOUTH-SLAVEY KEH + +01486 +CANADIAN SYLLABICS SOUTH-SLAVEY KIH + +01487 +CANADIAN SYLLABICS SOUTH-SLAVEY KOH + +01488 +CANADIAN SYLLABICS SOUTH-SLAVEY KAH + +01489 +CANADIAN SYLLABICS CE + +0148A +CANADIAN SYLLABICS CAAI + +0148B +CANADIAN SYLLABICS CI + +0148C +CANADIAN SYLLABICS CII + +0148D +CANADIAN SYLLABICS CO + +0148E +CANADIAN SYLLABICS COO + +0148F +CANADIAN SYLLABICS Y-CREE COO + +01490 +CANADIAN SYLLABICS CA + +01491 +CANADIAN SYLLABICS CAA + +01492 +CANADIAN SYLLABICS CWE + +01493 +CANADIAN SYLLABICS WEST-CREE CWE + +01494 +CANADIAN SYLLABICS CWI + +01495 +CANADIAN SYLLABICS WEST-CREE CWI + +01496 +CANADIAN SYLLABICS CWII + +01497 +CANADIAN SYLLABICS WEST-CREE CWII + +01498 +CANADIAN SYLLABICS CWO + +01499 +CANADIAN SYLLABICS WEST-CREE CWO + +0149A +CANADIAN SYLLABICS CWOO + +0149B +CANADIAN SYLLABICS WEST-CREE CWOO + +0149C +CANADIAN SYLLABICS CWA + +0149D +CANADIAN SYLLABICS WEST-CREE CWA + +0149E +CANADIAN SYLLABICS CWAA + +0149F +CANADIAN SYLLABICS WEST-CREE CWAA + +014A0 +CANADIAN SYLLABICS NASKAPI CWAA + +014A1 +CANADIAN SYLLABICS C + +014A2 +CANADIAN SYLLABICS SAYISI TH + +014A3 +CANADIAN SYLLABICS ME + +014A4 +CANADIAN SYLLABICS MAAI + +014A5 +CANADIAN SYLLABICS MI + +014A6 +CANADIAN SYLLABICS MII + +014A7 +CANADIAN SYLLABICS MO + +014A8 +CANADIAN SYLLABICS MOO + +014A9 +CANADIAN SYLLABICS Y-CREE MOO + +014AA +CANADIAN SYLLABICS MA + +014AB +CANADIAN SYLLABICS MAA + +014AC +CANADIAN SYLLABICS MWE + +014AD +CANADIAN SYLLABICS WEST-CREE MWE + +014AE +CANADIAN SYLLABICS MWI + +014AF +CANADIAN SYLLABICS WEST-CREE MWI + +014B0 +CANADIAN SYLLABICS MWII + +014B1 +CANADIAN SYLLABICS WEST-CREE MWII + +014B2 +CANADIAN SYLLABICS MWO + +014B3 +CANADIAN SYLLABICS WEST-CREE MWO + +014B4 +CANADIAN SYLLABICS MWOO + +014B5 +CANADIAN SYLLABICS WEST-CREE MWOO + +014B6 +CANADIAN SYLLABICS MWA + +014B7 +CANADIAN SYLLABICS WEST-CREE MWA + +014B8 +CANADIAN SYLLABICS MWAA + +014B9 +CANADIAN SYLLABICS WEST-CREE MWAA + +014BA +CANADIAN SYLLABICS NASKAPI MWAA + +014BB +CANADIAN SYLLABICS M + +014BC +CANADIAN SYLLABICS WEST-CREE M + +014BD +CANADIAN SYLLABICS MH + +014BE +CANADIAN SYLLABICS ATHAPASCAN M + +014BF +CANADIAN SYLLABICS SAYISI M + +014C0 +CANADIAN SYLLABICS NE + +014C1 +CANADIAN SYLLABICS NAAI + +014C2 +CANADIAN SYLLABICS NI + +014C3 +CANADIAN SYLLABICS NII + +014C4 +CANADIAN SYLLABICS NO + +014C5 +CANADIAN SYLLABICS NOO + +014C6 +CANADIAN SYLLABICS Y-CREE NOO + +014C7 +CANADIAN SYLLABICS NA + +014C8 +CANADIAN SYLLABICS NAA + +014C9 +CANADIAN SYLLABICS NWE + +014CA +CANADIAN SYLLABICS WEST-CREE NWE + +014CB +CANADIAN SYLLABICS NWA + +014CC +CANADIAN SYLLABICS WEST-CREE NWA + +014CD +CANADIAN SYLLABICS NWAA + +014CE +CANADIAN SYLLABICS WEST-CREE NWAA + +014CF +CANADIAN SYLLABICS NASKAPI NWAA + +014D0 +CANADIAN SYLLABICS N + +014D1 +CANADIAN SYLLABICS CARRIER NG + +014D2 +CANADIAN SYLLABICS NH + +014D3 +CANADIAN SYLLABICS LE + +014D4 +CANADIAN SYLLABICS LAAI + +014D5 +CANADIAN SYLLABICS LI + +014D6 +CANADIAN SYLLABICS LII + +014D7 +CANADIAN SYLLABICS LO + +014D8 +CANADIAN SYLLABICS LOO + +014D9 +CANADIAN SYLLABICS Y-CREE LOO + +014DA +CANADIAN SYLLABICS LA + +014DB +CANADIAN SYLLABICS LAA + +014DC +CANADIAN SYLLABICS LWE + +014DD +CANADIAN SYLLABICS WEST-CREE LWE + +014DE +CANADIAN SYLLABICS LWI + +014DF +CANADIAN SYLLABICS WEST-CREE LWI + +014E0 +CANADIAN SYLLABICS LWII + +014E1 +CANADIAN SYLLABICS WEST-CREE LWII + +014E2 +CANADIAN SYLLABICS LWO + +014E3 +CANADIAN SYLLABICS WEST-CREE LWO + +014E4 +CANADIAN SYLLABICS LWOO + +014E5 +CANADIAN SYLLABICS WEST-CREE LWOO + +014E6 +CANADIAN SYLLABICS LWA + +014E7 +CANADIAN SYLLABICS WEST-CREE LWA + +014E8 +CANADIAN SYLLABICS LWAA + +014E9 +CANADIAN SYLLABICS WEST-CREE LWAA + +014EA +CANADIAN SYLLABICS L + +014EB +CANADIAN SYLLABICS WEST-CREE L + +014EC +CANADIAN SYLLABICS MEDIAL L + +014ED +CANADIAN SYLLABICS SE + +014EE +CANADIAN SYLLABICS SAAI + +014EF +CANADIAN SYLLABICS SI + +014F0 +CANADIAN SYLLABICS SII + +014F1 +CANADIAN SYLLABICS SO + +014F2 +CANADIAN SYLLABICS SOO + +014F3 +CANADIAN SYLLABICS Y-CREE SOO + +014F4 +CANADIAN SYLLABICS SA + +014F5 +CANADIAN SYLLABICS SAA + +014F6 +CANADIAN SYLLABICS SWE + +014F7 +CANADIAN SYLLABICS WEST-CREE SWE + +014F8 +CANADIAN SYLLABICS SWI + +014F9 +CANADIAN SYLLABICS WEST-CREE SWI + +014FA +CANADIAN SYLLABICS SWII + +014FB +CANADIAN SYLLABICS WEST-CREE SWII + +014FC +CANADIAN SYLLABICS SWO + +014FD +CANADIAN SYLLABICS WEST-CREE SWO + +014FE +CANADIAN SYLLABICS SWOO + +014FF +CANADIAN SYLLABICS WEST-CREE SWOO + +01500 +CANADIAN SYLLABICS SWA + +01501 +CANADIAN SYLLABICS WEST-CREE SWA + +01502 +CANADIAN SYLLABICS SWAA + +01503 +CANADIAN SYLLABICS WEST-CREE SWAA + +01504 +CANADIAN SYLLABICS NASKAPI SWAA + +01505 +CANADIAN SYLLABICS S + +01506 +CANADIAN SYLLABICS ATHAPASCAN S + +01507 +CANADIAN SYLLABICS SW + +01508 +CANADIAN SYLLABICS BLACKFOOT S + +01509 +CANADIAN SYLLABICS MOOSE-CREE SK + +0150A +CANADIAN SYLLABICS NASKAPI SKW + +0150B +CANADIAN SYLLABICS NASKAPI S-W + +0150C +CANADIAN SYLLABICS NASKAPI SPWA + +0150D +CANADIAN SYLLABICS NASKAPI STWA + +0150E +CANADIAN SYLLABICS NASKAPI SKWA + +0150F +CANADIAN SYLLABICS NASKAPI SCWA + +01510 +CANADIAN SYLLABICS SHE + +01511 +CANADIAN SYLLABICS SHI + +01512 +CANADIAN SYLLABICS SHII + +01513 +CANADIAN SYLLABICS SHO + +01514 +CANADIAN SYLLABICS SHOO + +01515 +CANADIAN SYLLABICS SHA + +01516 +CANADIAN SYLLABICS SHAA + +01517 +CANADIAN SYLLABICS SHWE + +01518 +CANADIAN SYLLABICS WEST-CREE SHWE + +01519 +CANADIAN SYLLABICS SHWI + +0151A +CANADIAN SYLLABICS WEST-CREE SHWI + +0151B +CANADIAN SYLLABICS SHWII + +0151C +CANADIAN SYLLABICS WEST-CREE SHWII + +0151D +CANADIAN SYLLABICS SHWO + +0151E +CANADIAN SYLLABICS WEST-CREE SHWO + +0151F +CANADIAN SYLLABICS SHWOO + +01520 +CANADIAN SYLLABICS WEST-CREE SHWOO + +01521 +CANADIAN SYLLABICS SHWA + +01522 +CANADIAN SYLLABICS WEST-CREE SHWA + +01523 +CANADIAN SYLLABICS SHWAA + +01524 +CANADIAN SYLLABICS WEST-CREE SHWAA + +01525 +CANADIAN SYLLABICS SH + +01526 +CANADIAN SYLLABICS YE + +01527 +CANADIAN SYLLABICS YAAI + +01528 +CANADIAN SYLLABICS YI + +01529 +CANADIAN SYLLABICS YII + +0152A +CANADIAN SYLLABICS YO + +0152B +CANADIAN SYLLABICS YOO + +0152C +CANADIAN SYLLABICS Y-CREE YOO + +0152D +CANADIAN SYLLABICS YA + +0152E +CANADIAN SYLLABICS YAA + +0152F +CANADIAN SYLLABICS YWE + +01530 +CANADIAN SYLLABICS WEST-CREE YWE + +01531 +CANADIAN SYLLABICS YWI + +01532 +CANADIAN SYLLABICS WEST-CREE YWI + +01533 +CANADIAN SYLLABICS YWII + +01534 +CANADIAN SYLLABICS WEST-CREE YWII + +01535 +CANADIAN SYLLABICS YWO + +01536 +CANADIAN SYLLABICS WEST-CREE YWO + +01537 +CANADIAN SYLLABICS YWOO + +01538 +CANADIAN SYLLABICS WEST-CREE YWOO + +01539 +CANADIAN SYLLABICS YWA + +0153A +CANADIAN SYLLABICS WEST-CREE YWA + +0153B +CANADIAN SYLLABICS YWAA + +0153C +CANADIAN SYLLABICS WEST-CREE YWAA + +0153D +CANADIAN SYLLABICS NASKAPI YWAA + +0153E +CANADIAN SYLLABICS Y + +0153F +CANADIAN SYLLABICS BIBLE-CREE Y + +01540 +CANADIAN SYLLABICS WEST-CREE Y + +01541 +CANADIAN SYLLABICS SAYISI YI + +01542 +CANADIAN SYLLABICS RE + +01543 +CANADIAN SYLLABICS R-CREE RE + +01544 +CANADIAN SYLLABICS WEST-CREE LE + +01545 +CANADIAN SYLLABICS RAAI + +01546 +CANADIAN SYLLABICS RI + +01547 +CANADIAN SYLLABICS RII + +01548 +CANADIAN SYLLABICS RO + +01549 +CANADIAN SYLLABICS ROO + +0154A +CANADIAN SYLLABICS WEST-CREE LO + +0154B +CANADIAN SYLLABICS RA + +0154C +CANADIAN SYLLABICS RAA + +0154D +CANADIAN SYLLABICS WEST-CREE LA + +0154E +CANADIAN SYLLABICS RWAA + +0154F +CANADIAN SYLLABICS WEST-CREE RWAA + +01550 +CANADIAN SYLLABICS R + +01551 +CANADIAN SYLLABICS WEST-CREE R + +01552 +CANADIAN SYLLABICS MEDIAL R + +01553 +CANADIAN SYLLABICS FE + +01554 +CANADIAN SYLLABICS FAAI + +01555 +CANADIAN SYLLABICS FI + +01556 +CANADIAN SYLLABICS FII + +01557 +CANADIAN SYLLABICS FO + +01558 +CANADIAN SYLLABICS FOO + +01559 +CANADIAN SYLLABICS FA + +0155A +CANADIAN SYLLABICS FAA + +0155B +CANADIAN SYLLABICS FWAA + +0155C +CANADIAN SYLLABICS WEST-CREE FWAA + +0155D +CANADIAN SYLLABICS F + +0155E +CANADIAN SYLLABICS THE + +0155F +CANADIAN SYLLABICS N-CREE THE + +01560 +CANADIAN SYLLABICS THI + +01561 +CANADIAN SYLLABICS N-CREE THI + +01562 +CANADIAN SYLLABICS THII + +01563 +CANADIAN SYLLABICS N-CREE THII + +01564 +CANADIAN SYLLABICS THO + +01565 +CANADIAN SYLLABICS THOO + +01566 +CANADIAN SYLLABICS THA + +01567 +CANADIAN SYLLABICS THAA + +01568 +CANADIAN SYLLABICS THWAA + +01569 +CANADIAN SYLLABICS WEST-CREE THWAA + +0156A +CANADIAN SYLLABICS TH + +0156B +CANADIAN SYLLABICS TTHE + +0156C +CANADIAN SYLLABICS TTHI + +0156D +CANADIAN SYLLABICS TTHO + +0156E +CANADIAN SYLLABICS TTHA + +0156F +CANADIAN SYLLABICS TTH + +01570 +CANADIAN SYLLABICS TYE + +01571 +CANADIAN SYLLABICS TYI + +01572 +CANADIAN SYLLABICS TYO + +01573 +CANADIAN SYLLABICS TYA + +01574 +CANADIAN SYLLABICS NUNAVIK HE + +01575 +CANADIAN SYLLABICS NUNAVIK HI + +01576 +CANADIAN SYLLABICS NUNAVIK HII + +01577 +CANADIAN SYLLABICS NUNAVIK HO + +01578 +CANADIAN SYLLABICS NUNAVIK HOO + +01579 +CANADIAN SYLLABICS NUNAVIK HA + +0157A +CANADIAN SYLLABICS NUNAVIK HAA + +0157B +CANADIAN SYLLABICS NUNAVIK H + +0157C +CANADIAN SYLLABICS NUNAVUT H + +0157D +CANADIAN SYLLABICS HK + +0157E +CANADIAN SYLLABICS QAAI + +0157F +CANADIAN SYLLABICS QI + +01580 +CANADIAN SYLLABICS QII + +01581 +CANADIAN SYLLABICS QO + +01582 +CANADIAN SYLLABICS QOO + +01583 +CANADIAN SYLLABICS QA + +01584 +CANADIAN SYLLABICS QAA + +01585 +CANADIAN SYLLABICS Q + +01586 +CANADIAN SYLLABICS TLHE + +01587 +CANADIAN SYLLABICS TLHI + +01588 +CANADIAN SYLLABICS TLHO + +01589 +CANADIAN SYLLABICS TLHA + +0158A +CANADIAN SYLLABICS WEST-CREE RE + +0158B +CANADIAN SYLLABICS WEST-CREE RI + +0158C +CANADIAN SYLLABICS WEST-CREE RO + +0158D +CANADIAN SYLLABICS WEST-CREE RA + +0158E +CANADIAN SYLLABICS NGAAI + +0158F +CANADIAN SYLLABICS NGI + +01590 +CANADIAN SYLLABICS NGII + +01591 +CANADIAN SYLLABICS NGO + +01592 +CANADIAN SYLLABICS NGOO + +01593 +CANADIAN SYLLABICS NGA + +01594 +CANADIAN SYLLABICS NGAA + +01595 +CANADIAN SYLLABICS NG + +01596 +CANADIAN SYLLABICS NNG + +01597 +CANADIAN SYLLABICS SAYISI SHE + +01598 +CANADIAN SYLLABICS SAYISI SHI + +01599 +CANADIAN SYLLABICS SAYISI SHO + +0159A +CANADIAN SYLLABICS SAYISI SHA + +0159B +CANADIAN SYLLABICS WOODS-CREE THE + +0159C +CANADIAN SYLLABICS WOODS-CREE THI + +0159D +CANADIAN SYLLABICS WOODS-CREE THO + +0159E +CANADIAN SYLLABICS WOODS-CREE THA + +0159F +CANADIAN SYLLABICS WOODS-CREE TH + +015A0 +CANADIAN SYLLABICS LHI + +015A1 +CANADIAN SYLLABICS LHII + +015A2 +CANADIAN SYLLABICS LHO + +015A3 +CANADIAN SYLLABICS LHOO + +015A4 +CANADIAN SYLLABICS LHA + +015A5 +CANADIAN SYLLABICS LHAA + +015A6 +CANADIAN SYLLABICS LH + +015A7 +CANADIAN SYLLABICS TH-CREE THE + +015A8 +CANADIAN SYLLABICS TH-CREE THI + +015A9 +CANADIAN SYLLABICS TH-CREE THII + +015AA +CANADIAN SYLLABICS TH-CREE THO + +015AB +CANADIAN SYLLABICS TH-CREE THOO + +015AC +CANADIAN SYLLABICS TH-CREE THA + +015AD +CANADIAN SYLLABICS TH-CREE THAA + +015AE +CANADIAN SYLLABICS TH-CREE TH + +015AF +CANADIAN SYLLABICS AIVILIK B + +015B0 +CANADIAN SYLLABICS BLACKFOOT E + +015B1 +CANADIAN SYLLABICS BLACKFOOT I + +015B2 +CANADIAN SYLLABICS BLACKFOOT O + +015B3 +CANADIAN SYLLABICS BLACKFOOT A + +015B4 +CANADIAN SYLLABICS BLACKFOOT WE + +015B5 +CANADIAN SYLLABICS BLACKFOOT WI + +015B6 +CANADIAN SYLLABICS BLACKFOOT WO + +015B7 +CANADIAN SYLLABICS BLACKFOOT WA + +015B8 +CANADIAN SYLLABICS BLACKFOOT NE + +015B9 +CANADIAN SYLLABICS BLACKFOOT NI + +015BA +CANADIAN SYLLABICS BLACKFOOT NO + +015BB +CANADIAN SYLLABICS BLACKFOOT NA + +015BC +CANADIAN SYLLABICS BLACKFOOT KE + +015BD +CANADIAN SYLLABICS BLACKFOOT KI + +015BE +CANADIAN SYLLABICS BLACKFOOT KO + +015BF +CANADIAN SYLLABICS BLACKFOOT KA + +015C0 +CANADIAN SYLLABICS SAYISI HE + +015C1 +CANADIAN SYLLABICS SAYISI HI + +015C2 +CANADIAN SYLLABICS SAYISI HO + +015C3 +CANADIAN SYLLABICS SAYISI HA + +015C4 +CANADIAN SYLLABICS CARRIER GHU + +015C5 +CANADIAN SYLLABICS CARRIER GHO + +015C6 +CANADIAN SYLLABICS CARRIER GHE + +015C7 +CANADIAN SYLLABICS CARRIER GHEE + +015C8 +CANADIAN SYLLABICS CARRIER GHI + +015C9 +CANADIAN SYLLABICS CARRIER GHA + +015CA +CANADIAN SYLLABICS CARRIER RU + +015CB +CANADIAN SYLLABICS CARRIER RO + +015CC +CANADIAN SYLLABICS CARRIER RE + +015CD +CANADIAN SYLLABICS CARRIER REE + +015CE +CANADIAN SYLLABICS CARRIER RI + +015CF +CANADIAN SYLLABICS CARRIER RA + +015D0 +CANADIAN SYLLABICS CARRIER WU + +015D1 +CANADIAN SYLLABICS CARRIER WO + +015D2 +CANADIAN SYLLABICS CARRIER WE + +015D3 +CANADIAN SYLLABICS CARRIER WEE + +015D4 +CANADIAN SYLLABICS CARRIER WI + +015D5 +CANADIAN SYLLABICS CARRIER WA + +015D6 +CANADIAN SYLLABICS CARRIER HWU + +015D7 +CANADIAN SYLLABICS CARRIER HWO + +015D8 +CANADIAN SYLLABICS CARRIER HWE + +015D9 +CANADIAN SYLLABICS CARRIER HWEE + +015DA +CANADIAN SYLLABICS CARRIER HWI + +015DB +CANADIAN SYLLABICS CARRIER HWA + +015DC +CANADIAN SYLLABICS CARRIER THU + +015DD +CANADIAN SYLLABICS CARRIER THO + +015DE +CANADIAN SYLLABICS CARRIER THE + +015DF +CANADIAN SYLLABICS CARRIER THEE + +015E0 +CANADIAN SYLLABICS CARRIER THI + +015E1 +CANADIAN SYLLABICS CARRIER THA + +015E2 +CANADIAN SYLLABICS CARRIER TTU + +015E3 +CANADIAN SYLLABICS CARRIER TTO + +015E4 +CANADIAN SYLLABICS CARRIER TTE + +015E5 +CANADIAN SYLLABICS CARRIER TTEE + +015E6 +CANADIAN SYLLABICS CARRIER TTI + +015E7 +CANADIAN SYLLABICS CARRIER TTA + +015E8 +CANADIAN SYLLABICS CARRIER PU + +015E9 +CANADIAN SYLLABICS CARRIER PO + +015EA +CANADIAN SYLLABICS CARRIER PE + +015EB +CANADIAN SYLLABICS CARRIER PEE + +015EC +CANADIAN SYLLABICS CARRIER PI + +015ED +CANADIAN SYLLABICS CARRIER PA + +015EE +CANADIAN SYLLABICS CARRIER P + +015EF +CANADIAN SYLLABICS CARRIER GU + +015F0 +CANADIAN SYLLABICS CARRIER GO + +015F1 +CANADIAN SYLLABICS CARRIER GE + +015F2 +CANADIAN SYLLABICS CARRIER GEE + +015F3 +CANADIAN SYLLABICS CARRIER GI + +015F4 +CANADIAN SYLLABICS CARRIER GA + +015F5 +CANADIAN SYLLABICS CARRIER KHU + +015F6 +CANADIAN SYLLABICS CARRIER KHO + +015F7 +CANADIAN SYLLABICS CARRIER KHE + +015F8 +CANADIAN SYLLABICS CARRIER KHEE + +015F9 +CANADIAN SYLLABICS CARRIER KHI + +015FA +CANADIAN SYLLABICS CARRIER KHA + +015FB +CANADIAN SYLLABICS CARRIER KKU + +015FC +CANADIAN SYLLABICS CARRIER KKO + +015FD +CANADIAN SYLLABICS CARRIER KKE + +015FE +CANADIAN SYLLABICS CARRIER KKEE + +015FF +CANADIAN SYLLABICS CARRIER KKI + +01600 +CANADIAN SYLLABICS CARRIER KKA + +01601 +CANADIAN SYLLABICS CARRIER KK + +01602 +CANADIAN SYLLABICS CARRIER NU + +01603 +CANADIAN SYLLABICS CARRIER NO + +01604 +CANADIAN SYLLABICS CARRIER NE + +01605 +CANADIAN SYLLABICS CARRIER NEE + +01606 +CANADIAN SYLLABICS CARRIER NI + +01607 +CANADIAN SYLLABICS CARRIER NA + +01608 +CANADIAN SYLLABICS CARRIER MU + +01609 +CANADIAN SYLLABICS CARRIER MO + +0160A +CANADIAN SYLLABICS CARRIER ME + +0160B +CANADIAN SYLLABICS CARRIER MEE + +0160C +CANADIAN SYLLABICS CARRIER MI + +0160D +CANADIAN SYLLABICS CARRIER MA + +0160E +CANADIAN SYLLABICS CARRIER YU + +0160F +CANADIAN SYLLABICS CARRIER YO + +01610 +CANADIAN SYLLABICS CARRIER YE + +01611 +CANADIAN SYLLABICS CARRIER YEE + +01612 +CANADIAN SYLLABICS CARRIER YI + +01613 +CANADIAN SYLLABICS CARRIER YA + +01614 +CANADIAN SYLLABICS CARRIER JU + +01615 +CANADIAN SYLLABICS SAYISI JU + +01616 +CANADIAN SYLLABICS CARRIER JO + +01617 +CANADIAN SYLLABICS CARRIER JE + +01618 +CANADIAN SYLLABICS CARRIER JEE + +01619 +CANADIAN SYLLABICS CARRIER JI + +0161A +CANADIAN SYLLABICS SAYISI JI + +0161B +CANADIAN SYLLABICS CARRIER JA + +0161C +CANADIAN SYLLABICS CARRIER JJU + +0161D +CANADIAN SYLLABICS CARRIER JJO + +0161E +CANADIAN SYLLABICS CARRIER JJE + +0161F +CANADIAN SYLLABICS CARRIER JJEE + +01620 +CANADIAN SYLLABICS CARRIER JJI + +01621 +CANADIAN SYLLABICS CARRIER JJA + +01622 +CANADIAN SYLLABICS CARRIER LU + +01623 +CANADIAN SYLLABICS CARRIER LO + +01624 +CANADIAN SYLLABICS CARRIER LE + +01625 +CANADIAN SYLLABICS CARRIER LEE + +01626 +CANADIAN SYLLABICS CARRIER LI + +01627 +CANADIAN SYLLABICS CARRIER LA + +01628 +CANADIAN SYLLABICS CARRIER DLU + +01629 +CANADIAN SYLLABICS CARRIER DLO + +0162A +CANADIAN SYLLABICS CARRIER DLE + +0162B +CANADIAN SYLLABICS CARRIER DLEE + +0162C +CANADIAN SYLLABICS CARRIER DLI + +0162D +CANADIAN SYLLABICS CARRIER DLA + +0162E +CANADIAN SYLLABICS CARRIER LHU + +0162F +CANADIAN SYLLABICS CARRIER LHO + +01630 +CANADIAN SYLLABICS CARRIER LHE + +01631 +CANADIAN SYLLABICS CARRIER LHEE + +01632 +CANADIAN SYLLABICS CARRIER LHI + +01633 +CANADIAN SYLLABICS CARRIER LHA + +01634 +CANADIAN SYLLABICS CARRIER TLHU + +01635 +CANADIAN SYLLABICS CARRIER TLHO + +01636 +CANADIAN SYLLABICS CARRIER TLHE + +01637 +CANADIAN SYLLABICS CARRIER TLHEE + +01638 +CANADIAN SYLLABICS CARRIER TLHI + +01639 +CANADIAN SYLLABICS CARRIER TLHA + +0163A +CANADIAN SYLLABICS CARRIER TLU + +0163B +CANADIAN SYLLABICS CARRIER TLO + +0163C +CANADIAN SYLLABICS CARRIER TLE + +0163D +CANADIAN SYLLABICS CARRIER TLEE + +0163E +CANADIAN SYLLABICS CARRIER TLI + +0163F +CANADIAN SYLLABICS CARRIER TLA + +01640 +CANADIAN SYLLABICS CARRIER ZU + +01641 +CANADIAN SYLLABICS CARRIER ZO + +01642 +CANADIAN SYLLABICS CARRIER ZE + +01643 +CANADIAN SYLLABICS CARRIER ZEE + +01644 +CANADIAN SYLLABICS CARRIER ZI + +01645 +CANADIAN SYLLABICS CARRIER ZA + +01646 +CANADIAN SYLLABICS CARRIER Z + +01647 +CANADIAN SYLLABICS CARRIER INITIAL Z + +01648 +CANADIAN SYLLABICS CARRIER DZU + +01649 +CANADIAN SYLLABICS CARRIER DZO + +0164A +CANADIAN SYLLABICS CARRIER DZE + +0164B +CANADIAN SYLLABICS CARRIER DZEE + +0164C +CANADIAN SYLLABICS CARRIER DZI + +0164D +CANADIAN SYLLABICS CARRIER DZA + +0164E +CANADIAN SYLLABICS CARRIER SU + +0164F +CANADIAN SYLLABICS CARRIER SO + +01650 +CANADIAN SYLLABICS CARRIER SE + +01651 +CANADIAN SYLLABICS CARRIER SEE + +01652 +CANADIAN SYLLABICS CARRIER SI + +01653 +CANADIAN SYLLABICS CARRIER SA + +01654 +CANADIAN SYLLABICS CARRIER SHU + +01655 +CANADIAN SYLLABICS CARRIER SHO + +01656 +CANADIAN SYLLABICS CARRIER SHE + +01657 +CANADIAN SYLLABICS CARRIER SHEE + +01658 +CANADIAN SYLLABICS CARRIER SHI + +01659 +CANADIAN SYLLABICS CARRIER SHA + +0165A +CANADIAN SYLLABICS CARRIER SH + +0165B +CANADIAN SYLLABICS CARRIER TSU + +0165C +CANADIAN SYLLABICS CARRIER TSO + +0165D +CANADIAN SYLLABICS CARRIER TSE + +0165E +CANADIAN SYLLABICS CARRIER TSEE + +0165F +CANADIAN SYLLABICS CARRIER TSI + +01660 +CANADIAN SYLLABICS CARRIER TSA + +01661 +CANADIAN SYLLABICS CARRIER CHU + +01662 +CANADIAN SYLLABICS CARRIER CHO + +01663 +CANADIAN SYLLABICS CARRIER CHE + +01664 +CANADIAN SYLLABICS CARRIER CHEE + +01665 +CANADIAN SYLLABICS CARRIER CHI + +01666 +CANADIAN SYLLABICS CARRIER CHA + +01667 +CANADIAN SYLLABICS CARRIER TTSU + +01668 +CANADIAN SYLLABICS CARRIER TTSO + +01669 +CANADIAN SYLLABICS CARRIER TTSE + +0166A +CANADIAN SYLLABICS CARRIER TTSEE + +0166B +CANADIAN SYLLABICS CARRIER TTSI + +0166C +CANADIAN SYLLABICS CARRIER TTSA + +0166D +CANADIAN SYLLABICS CHI SIGN + +0166E +CANADIAN SYLLABICS FULL STOP + +0166F +CANADIAN SYLLABICS QAI + +01670 +CANADIAN SYLLABICS NGAI + +01671 +CANADIAN SYLLABICS NNGI + +01672 +CANADIAN SYLLABICS NNGII + +01673 +CANADIAN SYLLABICS NNGO + +01674 +CANADIAN SYLLABICS NNGOO + +01675 +CANADIAN SYLLABICS NNGA + +01676 +CANADIAN SYLLABICS NNGAA + +01677 +CANADIAN SYLLABICS WOODS-CREE THWEE + +01678 +CANADIAN SYLLABICS WOODS-CREE THWI + +01679 +CANADIAN SYLLABICS WOODS-CREE THWII + +0167A +CANADIAN SYLLABICS WOODS-CREE THWO + +0167B +CANADIAN SYLLABICS WOODS-CREE THWOO + +0167C +CANADIAN SYLLABICS WOODS-CREE THWA + +0167D +CANADIAN SYLLABICS WOODS-CREE THWAA + +0167E +CANADIAN SYLLABICS WOODS-CREE FINAL TH + +0167F +CANADIAN SYLLABICS BLACKFOOT W + +01680 +OGHAM SPACE MARK + +01681 +OGHAM LETTER BEITH + +01682 +OGHAM LETTER LUIS + +01683 +OGHAM LETTER FEARN + +01684 +OGHAM LETTER SAIL + +01685 +OGHAM LETTER NION + +01686 +OGHAM LETTER UATH + +01687 +OGHAM LETTER DAIR + +01688 +OGHAM LETTER TINNE + +01689 +OGHAM LETTER COLL + +0168A +OGHAM LETTER CEIRT + +0168B +OGHAM LETTER MUIN + +0168C +OGHAM LETTER GORT + +0168D +OGHAM LETTER NGEADAL + +0168E +OGHAM LETTER STRAIF + +0168F +OGHAM LETTER RUIS + +01690 +OGHAM LETTER AILM + +01691 +OGHAM LETTER ONN + +01692 +OGHAM LETTER UR + +01693 +OGHAM LETTER EADHADH + +01694 +OGHAM LETTER IODHADH + +01695 +OGHAM LETTER EABHADH + +01696 +OGHAM LETTER OR + +01697 +OGHAM LETTER UILLEANN + +01698 +OGHAM LETTER IFIN + +01699 +OGHAM LETTER EAMHANCHOLL + +0169A +OGHAM LETTER PEITH + +0169B +OGHAM FEATHER MARK + +0169C +OGHAM REVERSED FEATHER MARK + +016A0 +RUNIC LETTER FEHU FEOH FE F + +016A1 +RUNIC LETTER V + +016A2 +RUNIC LETTER URUZ UR U + +016A3 +RUNIC LETTER YR + +016A4 +RUNIC LETTER Y + +016A5 +RUNIC LETTER W + +016A6 +RUNIC LETTER THURISAZ THURS THORN + +016A7 +RUNIC LETTER ETH + +016A8 +RUNIC LETTER ANSUZ A + +016A9 +RUNIC LETTER OS O + +016AA +RUNIC LETTER AC A + +016AB +RUNIC LETTER AESC + +016AC +RUNIC LETTER LONG-BRANCH-OSS O + +016AD +RUNIC LETTER SHORT-TWIG-OSS O + +016AE +RUNIC LETTER O + +016AF +RUNIC LETTER OE + +016B0 +RUNIC LETTER ON + +016B1 +RUNIC LETTER RAIDO RAD REID R + +016B2 +RUNIC LETTER KAUNA + +016B3 +RUNIC LETTER CEN + +016B4 +RUNIC LETTER KAUN K + +016B5 +RUNIC LETTER G + +016B6 +RUNIC LETTER ENG + +016B7 +RUNIC LETTER GEBO GYFU G + +016B8 +RUNIC LETTER GAR + +016B9 +RUNIC LETTER WUNJO WYNN W + +016BA +RUNIC LETTER HAGLAZ H + +016BB +RUNIC LETTER HAEGL H + +016BC +RUNIC LETTER LONG-BRANCH-HAGALL H + +016BD +RUNIC LETTER SHORT-TWIG-HAGALL H + +016BE +RUNIC LETTER NAUDIZ NYD NAUD N + +016BF +RUNIC LETTER SHORT-TWIG-NAUD N + +016C0 +RUNIC LETTER DOTTED-N + +016C1 +RUNIC LETTER ISAZ IS ISS I + +016C2 +RUNIC LETTER E + +016C3 +RUNIC LETTER JERAN J + +016C4 +RUNIC LETTER GER + +016C5 +RUNIC LETTER LONG-BRANCH-AR AE + +016C6 +RUNIC LETTER SHORT-TWIG-AR A + +016C7 +RUNIC LETTER IWAZ EOH + +016C8 +RUNIC LETTER PERTHO PEORTH P + +016C9 +RUNIC LETTER ALGIZ EOLHX + +016CA +RUNIC LETTER SOWILO S + +016CB +RUNIC LETTER SIGEL LONG-BRANCH-SOL S + +016CC +RUNIC LETTER SHORT-TWIG-SOL S + +016CD +RUNIC LETTER C + +016CE +RUNIC LETTER Z + +016CF +RUNIC LETTER TIWAZ TIR TYR T + +016D0 +RUNIC LETTER SHORT-TWIG-TYR T + +016D1 +RUNIC LETTER D + +016D2 +RUNIC LETTER BERKANAN BEORC BJARKAN B + +016D3 +RUNIC LETTER SHORT-TWIG-BJARKAN B + +016D4 +RUNIC LETTER DOTTED-P + +016D5 +RUNIC LETTER OPEN-P + +016D6 +RUNIC LETTER EHWAZ EH E + +016D7 +RUNIC LETTER MANNAZ MAN M + +016D8 +RUNIC LETTER LONG-BRANCH-MADR M + +016D9 +RUNIC LETTER SHORT-TWIG-MADR M + +016DA +RUNIC LETTER LAUKAZ LAGU LOGR L + +016DB +RUNIC LETTER DOTTED-L + +016DC +RUNIC LETTER INGWAZ + +016DD +RUNIC LETTER ING + +016DE +RUNIC LETTER DAGAZ DAEG D + +016DF +RUNIC LETTER OTHALAN ETHEL O + +016E0 +RUNIC LETTER EAR + +016E1 +RUNIC LETTER IOR + +016E2 +RUNIC LETTER CWEORTH + +016E3 +RUNIC LETTER CALC + +016E4 +RUNIC LETTER CEALC + +016E5 +RUNIC LETTER STAN + +016E6 +RUNIC LETTER LONG-BRANCH-YR + +016E7 +RUNIC LETTER SHORT-TWIG-YR + +016E8 +RUNIC LETTER ICELANDIC-YR + +016E9 +RUNIC LETTER Q + +016EA +RUNIC LETTER X + +016EB +RUNIC SINGLE PUNCTUATION + +016EC +RUNIC MULTIPLE PUNCTUATION + +016ED +RUNIC CROSS PUNCTUATION + +016EE +RUNIC ARLAUG SYMBOL + +016EF +RUNIC TVIMADUR SYMBOL + +016F0 +RUNIC BELGTHOR SYMBOL + +016F1 +RUNIC LETTER K + +016F2 +RUNIC LETTER SH + +016F3 +RUNIC LETTER OO + +016F4 +RUNIC LETTER FRANKS CASKET OS + +016F5 +RUNIC LETTER FRANKS CASKET IS + +016F6 +RUNIC LETTER FRANKS CASKET EH + +016F7 +RUNIC LETTER FRANKS CASKET AC + +016F8 +RUNIC LETTER FRANKS CASKET AESC + +01700 +TAGALOG LETTER A + +01701 +TAGALOG LETTER I + +01702 +TAGALOG LETTER U + +01703 +TAGALOG LETTER KA + +01704 +TAGALOG LETTER GA + +01705 +TAGALOG LETTER NGA + +01706 +TAGALOG LETTER TA + +01707 +TAGALOG LETTER DA + +01708 +TAGALOG LETTER NA + +01709 +TAGALOG LETTER PA + +0170A +TAGALOG LETTER BA + +0170B +TAGALOG LETTER MA + +0170C +TAGALOG LETTER YA + +0170D +TAGALOG LETTER RA + +0170E +TAGALOG LETTER LA + +0170F +TAGALOG LETTER WA + +01710 +TAGALOG LETTER SA + +01711 +TAGALOG LETTER HA + +01712 +TAGALOG VOWEL SIGN I + +01713 +TAGALOG VOWEL SIGN U + +01714 +TAGALOG SIGN VIRAMA + +01715 +TAGALOG SIGN PAMUDPOD + +0171F +TAGALOG LETTER ARCHAIC RA + +01720 +HANUNOO LETTER A + +01721 +HANUNOO LETTER I + +01722 +HANUNOO LETTER U + +01723 +HANUNOO LETTER KA + +01724 +HANUNOO LETTER GA + +01725 +HANUNOO LETTER NGA + +01726 +HANUNOO LETTER TA + +01727 +HANUNOO LETTER DA + +01728 +HANUNOO LETTER NA + +01729 +HANUNOO LETTER PA + +0172A +HANUNOO LETTER BA + +0172B +HANUNOO LETTER MA + +0172C +HANUNOO LETTER YA + +0172D +HANUNOO LETTER RA + +0172E +HANUNOO LETTER LA + +0172F +HANUNOO LETTER WA + +01730 +HANUNOO LETTER SA + +01731 +HANUNOO LETTER HA + +01732 +HANUNOO VOWEL SIGN I + +01733 +HANUNOO VOWEL SIGN U + +01734 +HANUNOO SIGN PAMUDPOD + +01735 +PHILIPPINE SINGLE PUNCTUATION + +01736 +PHILIPPINE DOUBLE PUNCTUATION + +01740 +BUHID LETTER A + +01741 +BUHID LETTER I + +01742 +BUHID LETTER U + +01743 +BUHID LETTER KA + +01744 +BUHID LETTER GA + +01745 +BUHID LETTER NGA + +01746 +BUHID LETTER TA + +01747 +BUHID LETTER DA + +01748 +BUHID LETTER NA + +01749 +BUHID LETTER PA + +0174A +BUHID LETTER BA + +0174B +BUHID LETTER MA + +0174C +BUHID LETTER YA + +0174D +BUHID LETTER RA + +0174E +BUHID LETTER LA + +0174F +BUHID LETTER WA + +01750 +BUHID LETTER SA + +01751 +BUHID LETTER HA + +01752 +BUHID VOWEL SIGN I + +01753 +BUHID VOWEL SIGN U + +01760 +TAGBANWA LETTER A + +01761 +TAGBANWA LETTER I + +01762 +TAGBANWA LETTER U + +01763 +TAGBANWA LETTER KA + +01764 +TAGBANWA LETTER GA + +01765 +TAGBANWA LETTER NGA + +01766 +TAGBANWA LETTER TA + +01767 +TAGBANWA LETTER DA + +01768 +TAGBANWA LETTER NA + +01769 +TAGBANWA LETTER PA + +0176A +TAGBANWA LETTER BA + +0176B +TAGBANWA LETTER MA + +0176C +TAGBANWA LETTER YA + +0176E +TAGBANWA LETTER LA + +0176F +TAGBANWA LETTER WA + +01770 +TAGBANWA LETTER SA + +01772 +TAGBANWA VOWEL SIGN I + +01773 +TAGBANWA VOWEL SIGN U + +01780 +KHMER LETTER KA + +01781 +KHMER LETTER KHA + +01782 +KHMER LETTER KO + +01783 +KHMER LETTER KHO + +01784 +KHMER LETTER NGO + +01785 +KHMER LETTER CA + +01786 +KHMER LETTER CHA + +01787 +KHMER LETTER CO + +01788 +KHMER LETTER CHO + +01789 +KHMER LETTER NYO + +0178A +KHMER LETTER DA + +0178B +KHMER LETTER TTHA + +0178C +KHMER LETTER DO + +0178D +KHMER LETTER TTHO + +0178E +KHMER LETTER NNO + +0178F +KHMER LETTER TA + +01790 +KHMER LETTER THA + +01791 +KHMER LETTER TO + +01792 +KHMER LETTER THO + +01793 +KHMER LETTER NO + +01794 +KHMER LETTER BA + +01795 +KHMER LETTER PHA + +01796 +KHMER LETTER PO + +01797 +KHMER LETTER PHO + +01798 +KHMER LETTER MO + +01799 +KHMER LETTER YO + +0179A +KHMER LETTER RO + +0179B +KHMER LETTER LO + +0179C +KHMER LETTER VO + +0179D +KHMER LETTER SHA + +0179E +KHMER LETTER SSO + +0179F +KHMER LETTER SA + +017A0 +KHMER LETTER HA + +017A1 +KHMER LETTER LA + +017A2 +KHMER LETTER QA + +017A3 +KHMER INDEPENDENT VOWEL QAQ + +017A4 +KHMER INDEPENDENT VOWEL QAA + +017A5 +KHMER INDEPENDENT VOWEL QI + +017A6 +KHMER INDEPENDENT VOWEL QII + +017A7 +KHMER INDEPENDENT VOWEL QU + +017A8 +KHMER INDEPENDENT VOWEL QUK + +017A9 +KHMER INDEPENDENT VOWEL QUU + +017AA +KHMER INDEPENDENT VOWEL QUUV + +017AB +KHMER INDEPENDENT VOWEL RY + +017AC +KHMER INDEPENDENT VOWEL RYY + +017AD +KHMER INDEPENDENT VOWEL LY + +017AE +KHMER INDEPENDENT VOWEL LYY + +017AF +KHMER INDEPENDENT VOWEL QE + +017B0 +KHMER INDEPENDENT VOWEL QAI + +017B1 +KHMER INDEPENDENT VOWEL QOO TYPE ONE + +017B2 +KHMER INDEPENDENT VOWEL QOO TYPE TWO + +017B3 +KHMER INDEPENDENT VOWEL QAU + +017B4 +KHMER VOWEL INHERENT AQ + +017B5 +KHMER VOWEL INHERENT AA + +017B6 +KHMER VOWEL SIGN AA + +017B7 +KHMER VOWEL SIGN I + +017B8 +KHMER VOWEL SIGN II + +017B9 +KHMER VOWEL SIGN Y + +017BA +KHMER VOWEL SIGN YY + +017BB +KHMER VOWEL SIGN U + +017BC +KHMER VOWEL SIGN UU + +017BD +KHMER VOWEL SIGN UA + +017BE +KHMER VOWEL SIGN OE + +017BF +KHMER VOWEL SIGN YA + +017C0 +KHMER VOWEL SIGN IE + +017C1 +KHMER VOWEL SIGN E + +017C2 +KHMER VOWEL SIGN AE + +017C3 +KHMER VOWEL SIGN AI + +017C4 +KHMER VOWEL SIGN OO + +017C5 +KHMER VOWEL SIGN AU + +017C6 +KHMER SIGN NIKAHIT + +017C7 +KHMER SIGN REAHMUK + +017C8 +KHMER SIGN YUUKALEAPINTU + +017C9 +KHMER SIGN MUUSIKATOAN + +017CA +KHMER SIGN TRIISAP + +017CB +KHMER SIGN BANTOC + +017CC +KHMER SIGN ROBAT + +017CD +KHMER SIGN TOANDAKHIAT + +017CE +KHMER SIGN KAKABAT + +017CF +KHMER SIGN AHSDA + +017D0 +KHMER SIGN SAMYOK SANNYA + +017D1 +KHMER SIGN VIRIAM + +017D2 +KHMER SIGN COENG + +017D3 +KHMER SIGN BATHAMASAT + +017D4 +KHMER SIGN KHAN + +017D5 +KHMER SIGN BARIYOOSAN + +017D6 +KHMER SIGN CAMNUC PII KUUH + +017D7 +KHMER SIGN LEK TOO + +017D8 +KHMER SIGN BEYYAL + +017D9 +KHMER SIGN PHNAEK MUAN + +017DA +KHMER SIGN KOOMUUT + +017DB +KHMER CURRENCY SYMBOL RIEL + +017DC +KHMER SIGN AVAKRAHASANYA + +017DD +KHMER SIGN ATTHACAN + +017E0 +KHMER DIGIT ZERO + +017E1 +KHMER DIGIT ONE + +017E2 +KHMER DIGIT TWO + +017E3 +KHMER DIGIT THREE + +017E4 +KHMER DIGIT FOUR + +017E5 +KHMER DIGIT FIVE + +017E6 +KHMER DIGIT SIX + +017E7 +KHMER DIGIT SEVEN + +017E8 +KHMER DIGIT EIGHT + +017E9 +KHMER DIGIT NINE + +017F0 +KHMER SYMBOL LEK ATTAK SON + +017F1 +KHMER SYMBOL LEK ATTAK MUOY + +017F2 +KHMER SYMBOL LEK ATTAK PII + +017F3 +KHMER SYMBOL LEK ATTAK BEI + +017F4 +KHMER SYMBOL LEK ATTAK BUON + +017F5 +KHMER SYMBOL LEK ATTAK PRAM + +017F6 +KHMER SYMBOL LEK ATTAK PRAM-MUOY + +017F7 +KHMER SYMBOL LEK ATTAK PRAM-PII + +017F8 +KHMER SYMBOL LEK ATTAK PRAM-BEI + +017F9 +KHMER SYMBOL LEK ATTAK PRAM-BUON + +01800 +MONGOLIAN BIRGA + +01801 +MONGOLIAN ELLIPSIS + +01802 +MONGOLIAN COMMA + +01803 +MONGOLIAN FULL STOP + +01804 +MONGOLIAN COLON + +01805 +MONGOLIAN FOUR DOTS + +01806 +MONGOLIAN TODO SOFT HYPHEN + +01807 +MONGOLIAN SIBE SYLLABLE BOUNDARY MARKER + +01808 +MONGOLIAN MANCHU COMMA + +01809 +MONGOLIAN MANCHU FULL STOP + +0180A +MONGOLIAN NIRUGU + +0180B +MONGOLIAN FREE VARIATION SELECTOR ONE + +0180B +FVS1 + +0180C +MONGOLIAN FREE VARIATION SELECTOR TWO + +0180C +FVS2 + +0180D +MONGOLIAN FREE VARIATION SELECTOR THREE + +0180D +FVS3 + +0180E +MONGOLIAN VOWEL SEPARATOR + +0180E +MVS + +0180F +MONGOLIAN FREE VARIATION SELECTOR FOUR + +0180F +FVS4 + +01810 +MONGOLIAN DIGIT ZERO + +01811 +MONGOLIAN DIGIT ONE + +01812 +MONGOLIAN DIGIT TWO + +01813 +MONGOLIAN DIGIT THREE + +01814 +MONGOLIAN DIGIT FOUR + +01815 +MONGOLIAN DIGIT FIVE + +01816 +MONGOLIAN DIGIT SIX + +01817 +MONGOLIAN DIGIT SEVEN + +01818 +MONGOLIAN DIGIT EIGHT + +01819 +MONGOLIAN DIGIT NINE + +01820 +MONGOLIAN LETTER A + +01821 +MONGOLIAN LETTER E + +01822 +MONGOLIAN LETTER I + +01823 +MONGOLIAN LETTER O + +01824 +MONGOLIAN LETTER U + +01825 +MONGOLIAN LETTER OE + +01826 +MONGOLIAN LETTER UE + +01827 +MONGOLIAN LETTER EE + +01828 +MONGOLIAN LETTER NA + +01829 +MONGOLIAN LETTER ANG + +0182A +MONGOLIAN LETTER BA + +0182B +MONGOLIAN LETTER PA + +0182C +MONGOLIAN LETTER QA + +0182D +MONGOLIAN LETTER GA + +0182E +MONGOLIAN LETTER MA + +0182F +MONGOLIAN LETTER LA + +01830 +MONGOLIAN LETTER SA + +01831 +MONGOLIAN LETTER SHA + +01832 +MONGOLIAN LETTER TA + +01833 +MONGOLIAN LETTER DA + +01834 +MONGOLIAN LETTER CHA + +01835 +MONGOLIAN LETTER JA + +01836 +MONGOLIAN LETTER YA + +01837 +MONGOLIAN LETTER RA + +01838 +MONGOLIAN LETTER WA + +01839 +MONGOLIAN LETTER FA + +0183A +MONGOLIAN LETTER KA + +0183B +MONGOLIAN LETTER KHA + +0183C +MONGOLIAN LETTER TSA + +0183D +MONGOLIAN LETTER ZA + +0183E +MONGOLIAN LETTER HAA + +0183F +MONGOLIAN LETTER ZRA + +01840 +MONGOLIAN LETTER LHA + +01841 +MONGOLIAN LETTER ZHI + +01842 +MONGOLIAN LETTER CHI + +01843 +MONGOLIAN LETTER TODO LONG VOWEL SIGN + +01844 +MONGOLIAN LETTER TODO E + +01845 +MONGOLIAN LETTER TODO I + +01846 +MONGOLIAN LETTER TODO O + +01847 +MONGOLIAN LETTER TODO U + +01848 +MONGOLIAN LETTER TODO OE + +01849 +MONGOLIAN LETTER TODO UE + +0184A +MONGOLIAN LETTER TODO ANG + +0184B +MONGOLIAN LETTER TODO BA + +0184C +MONGOLIAN LETTER TODO PA + +0184D +MONGOLIAN LETTER TODO QA + +0184E +MONGOLIAN LETTER TODO GA + +0184F +MONGOLIAN LETTER TODO MA + +01850 +MONGOLIAN LETTER TODO TA + +01851 +MONGOLIAN LETTER TODO DA + +01852 +MONGOLIAN LETTER TODO CHA + +01853 +MONGOLIAN LETTER TODO JA + +01854 +MONGOLIAN LETTER TODO TSA + +01855 +MONGOLIAN LETTER TODO YA + +01856 +MONGOLIAN LETTER TODO WA + +01857 +MONGOLIAN LETTER TODO KA + +01858 +MONGOLIAN LETTER TODO GAA + +01859 +MONGOLIAN LETTER TODO HAA + +0185A +MONGOLIAN LETTER TODO JIA + +0185B +MONGOLIAN LETTER TODO NIA + +0185C +MONGOLIAN LETTER TODO DZA + +0185D +MONGOLIAN LETTER SIBE E + +0185E +MONGOLIAN LETTER SIBE I + +0185F +MONGOLIAN LETTER SIBE IY + +01860 +MONGOLIAN LETTER SIBE UE + +01861 +MONGOLIAN LETTER SIBE U + +01862 +MONGOLIAN LETTER SIBE ANG + +01863 +MONGOLIAN LETTER SIBE KA + +01864 +MONGOLIAN LETTER SIBE GA + +01865 +MONGOLIAN LETTER SIBE HA + +01866 +MONGOLIAN LETTER SIBE PA + +01867 +MONGOLIAN LETTER SIBE SHA + +01868 +MONGOLIAN LETTER SIBE TA + +01869 +MONGOLIAN LETTER SIBE DA + +0186A +MONGOLIAN LETTER SIBE JA + +0186B +MONGOLIAN LETTER SIBE FA + +0186C +MONGOLIAN LETTER SIBE GAA + +0186D +MONGOLIAN LETTER SIBE HAA + +0186E +MONGOLIAN LETTER SIBE TSA + +0186F +MONGOLIAN LETTER SIBE ZA + +01870 +MONGOLIAN LETTER SIBE RAA + +01871 +MONGOLIAN LETTER SIBE CHA + +01872 +MONGOLIAN LETTER SIBE ZHA + +01873 +MONGOLIAN LETTER MANCHU I + +01874 +MONGOLIAN LETTER MANCHU KA + +01875 +MONGOLIAN LETTER MANCHU RA + +01876 +MONGOLIAN LETTER MANCHU FA + +01877 +MONGOLIAN LETTER MANCHU ZHA + +01878 +MONGOLIAN LETTER CHA WITH TWO DOTS + +01880 +MONGOLIAN LETTER ALI GALI ANUSVARA ONE + +01881 +MONGOLIAN LETTER ALI GALI VISARGA ONE + +01882 +MONGOLIAN LETTER ALI GALI DAMARU + +01883 +MONGOLIAN LETTER ALI GALI UBADAMA + +01884 +MONGOLIAN LETTER ALI GALI INVERTED UBADAMA + +01885 +MONGOLIAN LETTER ALI GALI BALUDA + +01886 +MONGOLIAN LETTER ALI GALI THREE BALUDA + +01887 +MONGOLIAN LETTER ALI GALI A + +01888 +MONGOLIAN LETTER ALI GALI I + +01889 +MONGOLIAN LETTER ALI GALI KA + +0188A +MONGOLIAN LETTER ALI GALI NGA + +0188B +MONGOLIAN LETTER ALI GALI CA + +0188C +MONGOLIAN LETTER ALI GALI TTA + +0188D +MONGOLIAN LETTER ALI GALI TTHA + +0188E +MONGOLIAN LETTER ALI GALI DDA + +0188F +MONGOLIAN LETTER ALI GALI NNA + +01890 +MONGOLIAN LETTER ALI GALI TA + +01891 +MONGOLIAN LETTER ALI GALI DA + +01892 +MONGOLIAN LETTER ALI GALI PA + +01893 +MONGOLIAN LETTER ALI GALI PHA + +01894 +MONGOLIAN LETTER ALI GALI SSA + +01895 +MONGOLIAN LETTER ALI GALI ZHA + +01896 +MONGOLIAN LETTER ALI GALI ZA + +01897 +MONGOLIAN LETTER ALI GALI AH + +01898 +MONGOLIAN LETTER TODO ALI GALI TA + +01899 +MONGOLIAN LETTER TODO ALI GALI ZHA + +0189A +MONGOLIAN LETTER MANCHU ALI GALI GHA + +0189B +MONGOLIAN LETTER MANCHU ALI GALI NGA + +0189C +MONGOLIAN LETTER MANCHU ALI GALI CA + +0189D +MONGOLIAN LETTER MANCHU ALI GALI JHA + +0189E +MONGOLIAN LETTER MANCHU ALI GALI TTA + +0189F +MONGOLIAN LETTER MANCHU ALI GALI DDHA + +018A0 +MONGOLIAN LETTER MANCHU ALI GALI TA + +018A1 +MONGOLIAN LETTER MANCHU ALI GALI DHA + +018A2 +MONGOLIAN LETTER MANCHU ALI GALI SSA + +018A3 +MONGOLIAN LETTER MANCHU ALI GALI CYA + +018A4 +MONGOLIAN LETTER MANCHU ALI GALI ZHA + +018A5 +MONGOLIAN LETTER MANCHU ALI GALI ZA + +018A6 +MONGOLIAN LETTER ALI GALI HALF U + +018A7 +MONGOLIAN LETTER ALI GALI HALF YA + +018A8 +MONGOLIAN LETTER MANCHU ALI GALI BHA + +018A9 +MONGOLIAN LETTER ALI GALI DAGALGA + +018AA +MONGOLIAN LETTER MANCHU ALI GALI LHA + +018B0 +CANADIAN SYLLABICS OY + +018B1 +CANADIAN SYLLABICS AY + +018B2 +CANADIAN SYLLABICS AAY + +018B3 +CANADIAN SYLLABICS WAY + +018B4 +CANADIAN SYLLABICS POY + +018B5 +CANADIAN SYLLABICS PAY + +018B6 +CANADIAN SYLLABICS PWOY + +018B7 +CANADIAN SYLLABICS TAY + +018B8 +CANADIAN SYLLABICS KAY + +018B9 +CANADIAN SYLLABICS KWAY + +018BA +CANADIAN SYLLABICS MAY + +018BB +CANADIAN SYLLABICS NOY + +018BC +CANADIAN SYLLABICS NAY + +018BD +CANADIAN SYLLABICS LAY + +018BE +CANADIAN SYLLABICS SOY + +018BF +CANADIAN SYLLABICS SAY + +018C0 +CANADIAN SYLLABICS SHOY + +018C1 +CANADIAN SYLLABICS SHAY + +018C2 +CANADIAN SYLLABICS SHWOY + +018C3 +CANADIAN SYLLABICS YOY + +018C4 +CANADIAN SYLLABICS YAY + +018C5 +CANADIAN SYLLABICS RAY + +018C6 +CANADIAN SYLLABICS NWI + +018C7 +CANADIAN SYLLABICS OJIBWAY NWI + +018C8 +CANADIAN SYLLABICS NWII + +018C9 +CANADIAN SYLLABICS OJIBWAY NWII + +018CA +CANADIAN SYLLABICS NWO + +018CB +CANADIAN SYLLABICS OJIBWAY NWO + +018CC +CANADIAN SYLLABICS NWOO + +018CD +CANADIAN SYLLABICS OJIBWAY NWOO + +018CE +CANADIAN SYLLABICS RWEE + +018CF +CANADIAN SYLLABICS RWI + +018D0 +CANADIAN SYLLABICS RWII + +018D1 +CANADIAN SYLLABICS RWO + +018D2 +CANADIAN SYLLABICS RWOO + +018D3 +CANADIAN SYLLABICS RWA + +018D4 +CANADIAN SYLLABICS OJIBWAY P + +018D5 +CANADIAN SYLLABICS OJIBWAY T + +018D6 +CANADIAN SYLLABICS OJIBWAY K + +018D7 +CANADIAN SYLLABICS OJIBWAY C + +018D8 +CANADIAN SYLLABICS OJIBWAY M + +018D9 +CANADIAN SYLLABICS OJIBWAY N + +018DA +CANADIAN SYLLABICS OJIBWAY S + +018DB +CANADIAN SYLLABICS OJIBWAY SH + +018DC +CANADIAN SYLLABICS EASTERN W + +018DD +CANADIAN SYLLABICS WESTERN W + +018DE +CANADIAN SYLLABICS FINAL SMALL RING + +018DF +CANADIAN SYLLABICS FINAL RAISED DOT + +018E0 +CANADIAN SYLLABICS R-CREE RWE + +018E1 +CANADIAN SYLLABICS WEST-CREE LOO + +018E2 +CANADIAN SYLLABICS WEST-CREE LAA + +018E3 +CANADIAN SYLLABICS THWE + +018E4 +CANADIAN SYLLABICS THWA + +018E5 +CANADIAN SYLLABICS TTHWE + +018E6 +CANADIAN SYLLABICS TTHOO + +018E7 +CANADIAN SYLLABICS TTHAA + +018E8 +CANADIAN SYLLABICS TLHWE + +018E9 +CANADIAN SYLLABICS TLHOO + +018EA +CANADIAN SYLLABICS SAYISI SHWE + +018EB +CANADIAN SYLLABICS SAYISI SHOO + +018EC +CANADIAN SYLLABICS SAYISI HOO + +018ED +CANADIAN SYLLABICS CARRIER GWU + +018EE +CANADIAN SYLLABICS CARRIER DENE GEE + +018EF +CANADIAN SYLLABICS CARRIER GAA + +018F0 +CANADIAN SYLLABICS CARRIER GWA + +018F1 +CANADIAN SYLLABICS SAYISI JUU + +018F2 +CANADIAN SYLLABICS CARRIER JWA + +018F3 +CANADIAN SYLLABICS BEAVER DENE L + +018F4 +CANADIAN SYLLABICS BEAVER DENE R + +018F5 +CANADIAN SYLLABICS CARRIER DENTAL S + +01900 +LIMBU VOWEL-CARRIER LETTER + +01901 +LIMBU LETTER KA + +01902 +LIMBU LETTER KHA + +01903 +LIMBU LETTER GA + +01904 +LIMBU LETTER GHA + +01905 +LIMBU LETTER NGA + +01906 +LIMBU LETTER CA + +01907 +LIMBU LETTER CHA + +01908 +LIMBU LETTER JA + +01909 +LIMBU LETTER JHA + +0190A +LIMBU LETTER YAN + +0190B +LIMBU LETTER TA + +0190C +LIMBU LETTER THA + +0190D +LIMBU LETTER DA + +0190E +LIMBU LETTER DHA + +0190F +LIMBU LETTER NA + +01910 +LIMBU LETTER PA + +01911 +LIMBU LETTER PHA + +01912 +LIMBU LETTER BA + +01913 +LIMBU LETTER BHA + +01914 +LIMBU LETTER MA + +01915 +LIMBU LETTER YA + +01916 +LIMBU LETTER RA + +01917 +LIMBU LETTER LA + +01918 +LIMBU LETTER WA + +01919 +LIMBU LETTER SHA + +0191A +LIMBU LETTER SSA + +0191B +LIMBU LETTER SA + +0191C +LIMBU LETTER HA + +0191D +LIMBU LETTER GYAN + +0191E +LIMBU LETTER TRA + +01920 +LIMBU VOWEL SIGN A + +01921 +LIMBU VOWEL SIGN I + +01922 +LIMBU VOWEL SIGN U + +01923 +LIMBU VOWEL SIGN EE + +01924 +LIMBU VOWEL SIGN AI + +01925 +LIMBU VOWEL SIGN OO + +01926 +LIMBU VOWEL SIGN AU + +01927 +LIMBU VOWEL SIGN E + +01928 +LIMBU VOWEL SIGN O + +01929 +LIMBU SUBJOINED LETTER YA + +0192A +LIMBU SUBJOINED LETTER RA + +0192B +LIMBU SUBJOINED LETTER WA + +01930 +LIMBU SMALL LETTER KA + +01931 +LIMBU SMALL LETTER NGA + +01932 +LIMBU SMALL LETTER ANUSVARA + +01933 +LIMBU SMALL LETTER TA + +01934 +LIMBU SMALL LETTER NA + +01935 +LIMBU SMALL LETTER PA + +01936 +LIMBU SMALL LETTER MA + +01937 +LIMBU SMALL LETTER RA + +01938 +LIMBU SMALL LETTER LA + +01939 +LIMBU SIGN MUKPHRENG + +0193A +LIMBU SIGN KEMPHRENG + +0193B +LIMBU SIGN SA-I + +01940 +LIMBU SIGN LOO + +01944 +LIMBU EXCLAMATION MARK + +01945 +LIMBU QUESTION MARK + +01946 +LIMBU DIGIT ZERO + +01947 +LIMBU DIGIT ONE + +01948 +LIMBU DIGIT TWO + +01949 +LIMBU DIGIT THREE + +0194A +LIMBU DIGIT FOUR + +0194B +LIMBU DIGIT FIVE + +0194C +LIMBU DIGIT SIX + +0194D +LIMBU DIGIT SEVEN + +0194E +LIMBU DIGIT EIGHT + +0194F +LIMBU DIGIT NINE + +01950 +TAI LE LETTER KA + +01951 +TAI LE LETTER XA + +01952 +TAI LE LETTER NGA + +01953 +TAI LE LETTER TSA + +01954 +TAI LE LETTER SA + +01955 +TAI LE LETTER YA + +01956 +TAI LE LETTER TA + +01957 +TAI LE LETTER THA + +01958 +TAI LE LETTER LA + +01959 +TAI LE LETTER PA + +0195A +TAI LE LETTER PHA + +0195B +TAI LE LETTER MA + +0195C +TAI LE LETTER FA + +0195D +TAI LE LETTER VA + +0195E +TAI LE LETTER HA + +0195F +TAI LE LETTER QA + +01960 +TAI LE LETTER KHA + +01961 +TAI LE LETTER TSHA + +01962 +TAI LE LETTER NA + +01963 +TAI LE LETTER A + +01964 +TAI LE LETTER I + +01965 +TAI LE LETTER EE + +01966 +TAI LE LETTER EH + +01967 +TAI LE LETTER U + +01968 +TAI LE LETTER OO + +01969 +TAI LE LETTER O + +0196A +TAI LE LETTER UE + +0196B +TAI LE LETTER E + +0196C +TAI LE LETTER AUE + +0196D +TAI LE LETTER AI + +01970 +TAI LE LETTER TONE-2 + +01971 +TAI LE LETTER TONE-3 + +01972 +TAI LE LETTER TONE-4 + +01973 +TAI LE LETTER TONE-5 + +01974 +TAI LE LETTER TONE-6 + +01980 +NEW TAI LUE LETTER HIGH QA + +01981 +NEW TAI LUE LETTER LOW QA + +01982 +NEW TAI LUE LETTER HIGH KA + +01983 +NEW TAI LUE LETTER HIGH XA + +01984 +NEW TAI LUE LETTER HIGH NGA + +01985 +NEW TAI LUE LETTER LOW KA + +01986 +NEW TAI LUE LETTER LOW XA + +01987 +NEW TAI LUE LETTER LOW NGA + +01988 +NEW TAI LUE LETTER HIGH TSA + +01989 +NEW TAI LUE LETTER HIGH SA + +0198A +NEW TAI LUE LETTER HIGH YA + +0198B +NEW TAI LUE LETTER LOW TSA + +0198C +NEW TAI LUE LETTER LOW SA + +0198D +NEW TAI LUE LETTER LOW YA + +0198E +NEW TAI LUE LETTER HIGH TA + +0198F +NEW TAI LUE LETTER HIGH THA + +01990 +NEW TAI LUE LETTER HIGH NA + +01991 +NEW TAI LUE LETTER LOW TA + +01992 +NEW TAI LUE LETTER LOW THA + +01993 +NEW TAI LUE LETTER LOW NA + +01994 +NEW TAI LUE LETTER HIGH PA + +01995 +NEW TAI LUE LETTER HIGH PHA + +01996 +NEW TAI LUE LETTER HIGH MA + +01997 +NEW TAI LUE LETTER LOW PA + +01998 +NEW TAI LUE LETTER LOW PHA + +01999 +NEW TAI LUE LETTER LOW MA + +0199A +NEW TAI LUE LETTER HIGH FA + +0199B +NEW TAI LUE LETTER HIGH VA + +0199C +NEW TAI LUE LETTER HIGH LA + +0199D +NEW TAI LUE LETTER LOW FA + +0199E +NEW TAI LUE LETTER LOW VA + +0199F +NEW TAI LUE LETTER LOW LA + +019A0 +NEW TAI LUE LETTER HIGH HA + +019A1 +NEW TAI LUE LETTER HIGH DA + +019A2 +NEW TAI LUE LETTER HIGH BA + +019A3 +NEW TAI LUE LETTER LOW HA + +019A4 +NEW TAI LUE LETTER LOW DA + +019A5 +NEW TAI LUE LETTER LOW BA + +019A6 +NEW TAI LUE LETTER HIGH KVA + +019A7 +NEW TAI LUE LETTER HIGH XVA + +019A8 +NEW TAI LUE LETTER LOW KVA + +019A9 +NEW TAI LUE LETTER LOW XVA + +019AA +NEW TAI LUE LETTER HIGH SUA + +019AB +NEW TAI LUE LETTER LOW SUA + +019B0 +NEW TAI LUE VOWEL SIGN VOWEL SHORTENER + +019B1 +NEW TAI LUE VOWEL SIGN AA + +019B2 +NEW TAI LUE VOWEL SIGN II + +019B3 +NEW TAI LUE VOWEL SIGN U + +019B4 +NEW TAI LUE VOWEL SIGN UU + +019B5 +NEW TAI LUE VOWEL SIGN E + +019B6 +NEW TAI LUE VOWEL SIGN AE + +019B7 +NEW TAI LUE VOWEL SIGN O + +019B8 +NEW TAI LUE VOWEL SIGN OA + +019B9 +NEW TAI LUE VOWEL SIGN UE + +019BA +NEW TAI LUE VOWEL SIGN AY + +019BB +NEW TAI LUE VOWEL SIGN AAY + +019BC +NEW TAI LUE VOWEL SIGN UY + +019BD +NEW TAI LUE VOWEL SIGN OY + +019BE +NEW TAI LUE VOWEL SIGN OAY + +019BF +NEW TAI LUE VOWEL SIGN UEY + +019C0 +NEW TAI LUE VOWEL SIGN IY + +019C1 +NEW TAI LUE LETTER FINAL V + +019C2 +NEW TAI LUE LETTER FINAL NG + +019C3 +NEW TAI LUE LETTER FINAL N + +019C4 +NEW TAI LUE LETTER FINAL M + +019C5 +NEW TAI LUE LETTER FINAL K + +019C6 +NEW TAI LUE LETTER FINAL D + +019C7 +NEW TAI LUE LETTER FINAL B + +019C8 +NEW TAI LUE TONE MARK-1 + +019C9 +NEW TAI LUE TONE MARK-2 + +019D0 +NEW TAI LUE DIGIT ZERO + +019D1 +NEW TAI LUE DIGIT ONE + +019D2 +NEW TAI LUE DIGIT TWO + +019D3 +NEW TAI LUE DIGIT THREE + +019D4 +NEW TAI LUE DIGIT FOUR + +019D5 +NEW TAI LUE DIGIT FIVE + +019D6 +NEW TAI LUE DIGIT SIX + +019D7 +NEW TAI LUE DIGIT SEVEN + +019D8 +NEW TAI LUE DIGIT EIGHT + +019D9 +NEW TAI LUE DIGIT NINE + +019DA +NEW TAI LUE THAM DIGIT ONE + +019DE +NEW TAI LUE SIGN LAE + +019DF +NEW TAI LUE SIGN LAEV + +019E0 +KHMER SYMBOL PATHAMASAT + +019E1 +KHMER SYMBOL MUOY KOET + +019E2 +KHMER SYMBOL PII KOET + +019E3 +KHMER SYMBOL BEI KOET + +019E4 +KHMER SYMBOL BUON KOET + +019E5 +KHMER SYMBOL PRAM KOET + +019E6 +KHMER SYMBOL PRAM-MUOY KOET + +019E7 +KHMER SYMBOL PRAM-PII KOET + +019E8 +KHMER SYMBOL PRAM-BEI KOET + +019E9 +KHMER SYMBOL PRAM-BUON KOET + +019EA +KHMER SYMBOL DAP KOET + +019EB +KHMER SYMBOL DAP-MUOY KOET + +019EC +KHMER SYMBOL DAP-PII KOET + +019ED +KHMER SYMBOL DAP-BEI KOET + +019EE +KHMER SYMBOL DAP-BUON KOET + +019EF +KHMER SYMBOL DAP-PRAM KOET + +019F0 +KHMER SYMBOL TUTEYASAT + +019F1 +KHMER SYMBOL MUOY ROC + +019F2 +KHMER SYMBOL PII ROC + +019F3 +KHMER SYMBOL BEI ROC + +019F4 +KHMER SYMBOL BUON ROC + +019F5 +KHMER SYMBOL PRAM ROC + +019F6 +KHMER SYMBOL PRAM-MUOY ROC + +019F7 +KHMER SYMBOL PRAM-PII ROC + +019F8 +KHMER SYMBOL PRAM-BEI ROC + +019F9 +KHMER SYMBOL PRAM-BUON ROC + +019FA +KHMER SYMBOL DAP ROC + +019FB +KHMER SYMBOL DAP-MUOY ROC + +019FC +KHMER SYMBOL DAP-PII ROC + +019FD +KHMER SYMBOL DAP-BEI ROC + +019FE +KHMER SYMBOL DAP-BUON ROC + +019FF +KHMER SYMBOL DAP-PRAM ROC + +01A00 +BUGINESE LETTER KA + +01A01 +BUGINESE LETTER GA + +01A02 +BUGINESE LETTER NGA + +01A03 +BUGINESE LETTER NGKA + +01A04 +BUGINESE LETTER PA + +01A05 +BUGINESE LETTER BA + +01A06 +BUGINESE LETTER MA + +01A07 +BUGINESE LETTER MPA + +01A08 +BUGINESE LETTER TA + +01A09 +BUGINESE LETTER DA + +01A0A +BUGINESE LETTER NA + +01A0B +BUGINESE LETTER NRA + +01A0C +BUGINESE LETTER CA + +01A0D +BUGINESE LETTER JA + +01A0E +BUGINESE LETTER NYA + +01A0F +BUGINESE LETTER NYCA + +01A10 +BUGINESE LETTER YA + +01A11 +BUGINESE LETTER RA + +01A12 +BUGINESE LETTER LA + +01A13 +BUGINESE LETTER VA + +01A14 +BUGINESE LETTER SA + +01A15 +BUGINESE LETTER A + +01A16 +BUGINESE LETTER HA + +01A17 +BUGINESE VOWEL SIGN I + +01A18 +BUGINESE VOWEL SIGN U + +01A19 +BUGINESE VOWEL SIGN E + +01A1A +BUGINESE VOWEL SIGN O + +01A1B +BUGINESE VOWEL SIGN AE + +01A1E +BUGINESE PALLAWA + +01A1F +BUGINESE END OF SECTION + +01A20 +TAI THAM LETTER HIGH KA + +01A21 +TAI THAM LETTER HIGH KHA + +01A22 +TAI THAM LETTER HIGH KXA + +01A23 +TAI THAM LETTER LOW KA + +01A24 +TAI THAM LETTER LOW KXA + +01A25 +TAI THAM LETTER LOW KHA + +01A26 +TAI THAM LETTER NGA + +01A27 +TAI THAM LETTER HIGH CA + +01A28 +TAI THAM LETTER HIGH CHA + +01A29 +TAI THAM LETTER LOW CA + +01A2A +TAI THAM LETTER LOW SA + +01A2B +TAI THAM LETTER LOW CHA + +01A2C +TAI THAM LETTER NYA + +01A2D +TAI THAM LETTER RATA + +01A2E +TAI THAM LETTER HIGH RATHA + +01A2F +TAI THAM LETTER DA + +01A30 +TAI THAM LETTER LOW RATHA + +01A31 +TAI THAM LETTER RANA + +01A32 +TAI THAM LETTER HIGH TA + +01A33 +TAI THAM LETTER HIGH THA + +01A34 +TAI THAM LETTER LOW TA + +01A35 +TAI THAM LETTER LOW THA + +01A36 +TAI THAM LETTER NA + +01A37 +TAI THAM LETTER BA + +01A38 +TAI THAM LETTER HIGH PA + +01A39 +TAI THAM LETTER HIGH PHA + +01A3A +TAI THAM LETTER HIGH FA + +01A3B +TAI THAM LETTER LOW PA + +01A3C +TAI THAM LETTER LOW FA + +01A3D +TAI THAM LETTER LOW PHA + +01A3E +TAI THAM LETTER MA + +01A3F +TAI THAM LETTER LOW YA + +01A40 +TAI THAM LETTER HIGH YA + +01A41 +TAI THAM LETTER RA + +01A42 +TAI THAM LETTER RUE + +01A43 +TAI THAM LETTER LA + +01A44 +TAI THAM LETTER LUE + +01A45 +TAI THAM LETTER WA + +01A46 +TAI THAM LETTER HIGH SHA + +01A47 +TAI THAM LETTER HIGH SSA + +01A48 +TAI THAM LETTER HIGH SA + +01A49 +TAI THAM LETTER HIGH HA + +01A4A +TAI THAM LETTER LLA + +01A4B +TAI THAM LETTER A + +01A4C +TAI THAM LETTER LOW HA + +01A4D +TAI THAM LETTER I + +01A4E +TAI THAM LETTER II + +01A4F +TAI THAM LETTER U + +01A50 +TAI THAM LETTER UU + +01A51 +TAI THAM LETTER EE + +01A52 +TAI THAM LETTER OO + +01A53 +TAI THAM LETTER LAE + +01A54 +TAI THAM LETTER GREAT SA + +01A55 +TAI THAM CONSONANT SIGN MEDIAL RA + +01A56 +TAI THAM CONSONANT SIGN MEDIAL LA + +01A57 +TAI THAM CONSONANT SIGN LA TANG LAI + +01A58 +TAI THAM SIGN MAI KANG LAI + +01A59 +TAI THAM CONSONANT SIGN FINAL NGA + +01A5A +TAI THAM CONSONANT SIGN LOW PA + +01A5B +TAI THAM CONSONANT SIGN HIGH RATHA OR LOW PA + +01A5C +TAI THAM CONSONANT SIGN MA + +01A5D +TAI THAM CONSONANT SIGN BA + +01A5E +TAI THAM CONSONANT SIGN SA + +01A60 +TAI THAM SIGN SAKOT + +01A61 +TAI THAM VOWEL SIGN A + +01A62 +TAI THAM VOWEL SIGN MAI SAT + +01A63 +TAI THAM VOWEL SIGN AA + +01A64 +TAI THAM VOWEL SIGN TALL AA + +01A65 +TAI THAM VOWEL SIGN I + +01A66 +TAI THAM VOWEL SIGN II + +01A67 +TAI THAM VOWEL SIGN UE + +01A68 +TAI THAM VOWEL SIGN UUE + +01A69 +TAI THAM VOWEL SIGN U + +01A6A +TAI THAM VOWEL SIGN UU + +01A6B +TAI THAM VOWEL SIGN O + +01A6C +TAI THAM VOWEL SIGN OA BELOW + +01A6D +TAI THAM VOWEL SIGN OY + +01A6E +TAI THAM VOWEL SIGN E + +01A6F +TAI THAM VOWEL SIGN AE + +01A70 +TAI THAM VOWEL SIGN OO + +01A71 +TAI THAM VOWEL SIGN AI + +01A72 +TAI THAM VOWEL SIGN THAM AI + +01A73 +TAI THAM VOWEL SIGN OA ABOVE + +01A74 +TAI THAM SIGN MAI KANG + +01A75 +TAI THAM SIGN TONE-1 + +01A76 +TAI THAM SIGN TONE-2 + +01A77 +TAI THAM SIGN KHUEN TONE-3 + +01A78 +TAI THAM SIGN KHUEN TONE-4 + +01A79 +TAI THAM SIGN KHUEN TONE-5 + +01A7A +TAI THAM SIGN RA HAAM + +01A7B +TAI THAM SIGN MAI SAM + +01A7C +TAI THAM SIGN KHUEN-LUE KARAN + +01A7F +TAI THAM COMBINING CRYPTOGRAMMIC DOT + +01A80 +TAI THAM HORA DIGIT ZERO + +01A81 +TAI THAM HORA DIGIT ONE + +01A82 +TAI THAM HORA DIGIT TWO + +01A83 +TAI THAM HORA DIGIT THREE + +01A84 +TAI THAM HORA DIGIT FOUR + +01A85 +TAI THAM HORA DIGIT FIVE + +01A86 +TAI THAM HORA DIGIT SIX + +01A87 +TAI THAM HORA DIGIT SEVEN + +01A88 +TAI THAM HORA DIGIT EIGHT + +01A89 +TAI THAM HORA DIGIT NINE + +01A90 +TAI THAM THAM DIGIT ZERO + +01A91 +TAI THAM THAM DIGIT ONE + +01A92 +TAI THAM THAM DIGIT TWO + +01A93 +TAI THAM THAM DIGIT THREE + +01A94 +TAI THAM THAM DIGIT FOUR + +01A95 +TAI THAM THAM DIGIT FIVE + +01A96 +TAI THAM THAM DIGIT SIX + +01A97 +TAI THAM THAM DIGIT SEVEN + +01A98 +TAI THAM THAM DIGIT EIGHT + +01A99 +TAI THAM THAM DIGIT NINE + +01AA0 +TAI THAM SIGN WIANG + +01AA1 +TAI THAM SIGN WIANGWAAK + +01AA2 +TAI THAM SIGN SAWAN + +01AA3 +TAI THAM SIGN KEOW + +01AA4 +TAI THAM SIGN HOY + +01AA5 +TAI THAM SIGN DOKMAI + +01AA6 +TAI THAM SIGN REVERSED ROTATED RANA + +01AA7 +TAI THAM SIGN MAI YAMOK + +01AA8 +TAI THAM SIGN KAAN + +01AA9 +TAI THAM SIGN KAANKUU + +01AAA +TAI THAM SIGN SATKAAN + +01AAB +TAI THAM SIGN SATKAANKUU + +01AAC +TAI THAM SIGN HANG + +01AAD +TAI THAM SIGN CAANG + +01AB0 +COMBINING DOUBLED CIRCUMFLEX ACCENT + +01AB1 +COMBINING DIAERESIS-RING + +01AB2 +COMBINING INFINITY + +01AB3 +COMBINING DOWNWARDS ARROW + +01AB4 +COMBINING TRIPLE DOT + +01AB5 +COMBINING X-X BELOW + +01AB6 +COMBINING WIGGLY LINE BELOW + +01AB7 +COMBINING OPEN MARK BELOW + +01AB8 +COMBINING DOUBLE OPEN MARK BELOW + +01AB9 +COMBINING LIGHT CENTRALIZATION STROKE BELOW + +01ABA +COMBINING STRONG CENTRALIZATION STROKE BELOW + +01ABB +COMBINING PARENTHESES ABOVE + +01ABC +COMBINING DOUBLE PARENTHESES ABOVE + +01ABD +COMBINING PARENTHESES BELOW + +01ABE +COMBINING PARENTHESES OVERLAY + +01ABF +COMBINING LATIN SMALL LETTER W BELOW + +01AC0 +COMBINING LATIN SMALL LETTER TURNED W BELOW + +01AC1 +COMBINING LEFT PARENTHESIS ABOVE LEFT + +01AC2 +COMBINING RIGHT PARENTHESIS ABOVE RIGHT + +01AC3 +COMBINING LEFT PARENTHESIS BELOW LEFT + +01AC4 +COMBINING RIGHT PARENTHESIS BELOW RIGHT + +01AC5 +COMBINING SQUARE BRACKETS ABOVE + +01AC6 +COMBINING NUMBER SIGN ABOVE + +01AC7 +COMBINING INVERTED DOUBLE ARCH ABOVE + +01AC8 +COMBINING PLUS SIGN ABOVE + +01AC9 +COMBINING DOUBLE PLUS SIGN ABOVE + +01ACA +COMBINING DOUBLE PLUS SIGN BELOW + +01ACB +COMBINING TRIPLE ACUTE ACCENT + +01ACC +COMBINING LATIN SMALL LETTER INSULAR G + +01ACD +COMBINING LATIN SMALL LETTER INSULAR R + +01ACE +COMBINING LATIN SMALL LETTER INSULAR T + +01ACF +COMBINING DOUBLE CARON + +01AD0 +COMBINING VERTICAL-LINE-ACUTE + +01AD1 +COMBINING GRAVE-VERTICAL-LINE + +01AD2 +COMBINING VERTICAL-LINE-GRAVE + +01AD3 +COMBINING ACUTE-VERTICAL-LINE + +01AD4 +COMBINING VERTICAL-LINE-MACRON + +01AD5 +COMBINING MACRON-VERTICAL-LINE + +01AD6 +COMBINING VERTICAL-LINE-ACUTE-GRAVE + +01AD7 +COMBINING VERTICAL-LINE-GRAVE-ACUTE + +01AD8 +COMBINING MACRON-ACUTE-GRAVE + +01AD9 +COMBINING SHARP SIGN + +01ADA +COMBINING FLAT SIGN + +01ADB +COMBINING DOWN TACK ABOVE + +01ADC +COMBINING DIAERESIS WITH RAISED LEFT DOT + +01ADD +COMBINING DOT-AND-RING BELOW + +01AE0 +COMBINING LEFT TACK ABOVE + +01AE1 +COMBINING RIGHT TACK ABOVE + +01AE2 +COMBINING MINUS SIGN ABOVE + +01AE3 +COMBINING INVERTED BRIDGE ABOVE + +01AE4 +COMBINING SQUARE ABOVE + +01AE5 +COMBINING SEAGULL ABOVE + +01AE6 +COMBINING DOUBLE ARCH BELOW + +01AE7 +COMBINING DOUBLE ARCH ABOVE + +01AE8 +COMBINING EQUALS SIGN ABOVE + +01AE9 +COMBINING LEFT ANGLE CENTRED ABOVE + +01AEA +COMBINING UPWARDS ARROW ABOVE + +01AEB +COMBINING DOUBLE RIGHTWARDS ARROW ABOVE + +01B00 +BALINESE SIGN ULU RICEM + +01B01 +BALINESE SIGN ULU CANDRA + +01B02 +BALINESE SIGN CECEK + +01B03 +BALINESE SIGN SURANG + +01B04 +BALINESE SIGN BISAH + +01B05 +BALINESE LETTER AKARA + +01B06 +BALINESE LETTER AKARA TEDUNG + +01B07 +BALINESE LETTER IKARA + +01B08 +BALINESE LETTER IKARA TEDUNG + +01B09 +BALINESE LETTER UKARA + +01B0A +BALINESE LETTER UKARA TEDUNG + +01B0B +BALINESE LETTER RA REPA + +01B0C +BALINESE LETTER RA REPA TEDUNG + +01B0D +BALINESE LETTER LA LENGA + +01B0E +BALINESE LETTER LA LENGA TEDUNG + +01B0F +BALINESE LETTER EKARA + +01B10 +BALINESE LETTER AIKARA + +01B11 +BALINESE LETTER OKARA + +01B12 +BALINESE LETTER OKARA TEDUNG + +01B13 +BALINESE LETTER KA + +01B14 +BALINESE LETTER KA MAHAPRANA + +01B15 +BALINESE LETTER GA + +01B16 +BALINESE LETTER GA GORA + +01B17 +BALINESE LETTER NGA + +01B18 +BALINESE LETTER CA + +01B19 +BALINESE LETTER CA LACA + +01B1A +BALINESE LETTER JA + +01B1B +BALINESE LETTER JA JERA + +01B1C +BALINESE LETTER NYA + +01B1D +BALINESE LETTER TA LATIK + +01B1E +BALINESE LETTER TA MURDA MAHAPRANA + +01B1F +BALINESE LETTER DA MURDA ALPAPRANA + +01B20 +BALINESE LETTER DA MURDA MAHAPRANA + +01B21 +BALINESE LETTER NA RAMBAT + +01B22 +BALINESE LETTER TA + +01B23 +BALINESE LETTER TA TAWA + +01B24 +BALINESE LETTER DA + +01B25 +BALINESE LETTER DA MADU + +01B26 +BALINESE LETTER NA + +01B27 +BALINESE LETTER PA + +01B28 +BALINESE LETTER PA KAPAL + +01B29 +BALINESE LETTER BA + +01B2A +BALINESE LETTER BA KEMBANG + +01B2B +BALINESE LETTER MA + +01B2C +BALINESE LETTER YA + +01B2D +BALINESE LETTER RA + +01B2E +BALINESE LETTER LA + +01B2F +BALINESE LETTER WA + +01B30 +BALINESE LETTER SA SAGA + +01B31 +BALINESE LETTER SA SAPA + +01B32 +BALINESE LETTER SA + +01B33 +BALINESE LETTER HA + +01B34 +BALINESE SIGN REREKAN + +01B35 +BALINESE VOWEL SIGN TEDUNG + +01B36 +BALINESE VOWEL SIGN ULU + +01B37 +BALINESE VOWEL SIGN ULU SARI + +01B38 +BALINESE VOWEL SIGN SUKU + +01B39 +BALINESE VOWEL SIGN SUKU ILUT + +01B3A +BALINESE VOWEL SIGN RA REPA + +01B3B +BALINESE VOWEL SIGN RA REPA TEDUNG + +01B3C +BALINESE VOWEL SIGN LA LENGA + +01B3D +BALINESE VOWEL SIGN LA LENGA TEDUNG + +01B3E +BALINESE VOWEL SIGN TALING + +01B3F +BALINESE VOWEL SIGN TALING REPA + +01B40 +BALINESE VOWEL SIGN TALING TEDUNG + +01B41 +BALINESE VOWEL SIGN TALING REPA TEDUNG + +01B42 +BALINESE VOWEL SIGN PEPET + +01B43 +BALINESE VOWEL SIGN PEPET TEDUNG + +01B44 +BALINESE ADEG ADEG + +01B45 +BALINESE LETTER KAF SASAK + +01B46 +BALINESE LETTER KHOT SASAK + +01B47 +BALINESE LETTER TZIR SASAK + +01B48 +BALINESE LETTER EF SASAK + +01B49 +BALINESE LETTER VE SASAK + +01B4A +BALINESE LETTER ZAL SASAK + +01B4B +BALINESE LETTER ASYURA SASAK + +01B4C +BALINESE LETTER ARCHAIC JNYA + +01B4E +BALINESE INVERTED CARIK SIKI + +01B4F +BALINESE INVERTED CARIK PAREREN + +01B50 +BALINESE DIGIT ZERO + +01B51 +BALINESE DIGIT ONE + +01B52 +BALINESE DIGIT TWO + +01B53 +BALINESE DIGIT THREE + +01B54 +BALINESE DIGIT FOUR + +01B55 +BALINESE DIGIT FIVE + +01B56 +BALINESE DIGIT SIX + +01B57 +BALINESE DIGIT SEVEN + +01B58 +BALINESE DIGIT EIGHT + +01B59 +BALINESE DIGIT NINE + +01B5A +BALINESE PANTI + +01B5B +BALINESE PAMADA + +01B5C +BALINESE WINDU + +01B5D +BALINESE CARIK PAMUNGKAH + +01B5E +BALINESE CARIK SIKI + +01B5F +BALINESE CARIK PAREREN + +01B60 +BALINESE PAMENENG + +01B61 +BALINESE MUSICAL SYMBOL DONG + +01B62 +BALINESE MUSICAL SYMBOL DENG + +01B63 +BALINESE MUSICAL SYMBOL DUNG + +01B64 +BALINESE MUSICAL SYMBOL DANG + +01B65 +BALINESE MUSICAL SYMBOL DANG SURANG + +01B66 +BALINESE MUSICAL SYMBOL DING + +01B67 +BALINESE MUSICAL SYMBOL DAENG + +01B68 +BALINESE MUSICAL SYMBOL DEUNG + +01B69 +BALINESE MUSICAL SYMBOL DAING + +01B6A +BALINESE MUSICAL SYMBOL DANG GEDE + +01B6B +BALINESE MUSICAL SYMBOL COMBINING TEGEH + +01B6C +BALINESE MUSICAL SYMBOL COMBINING ENDEP + +01B6D +BALINESE MUSICAL SYMBOL COMBINING KEMPUL + +01B6E +BALINESE MUSICAL SYMBOL COMBINING KEMPLI + +01B6F +BALINESE MUSICAL SYMBOL COMBINING JEGOGAN + +01B70 +BALINESE MUSICAL SYMBOL COMBINING KEMPUL WITH JEGOGAN + +01B71 +BALINESE MUSICAL SYMBOL COMBINING KEMPLI WITH JEGOGAN + +01B72 +BALINESE MUSICAL SYMBOL COMBINING BENDE + +01B73 +BALINESE MUSICAL SYMBOL COMBINING GONG + +01B74 +BALINESE MUSICAL SYMBOL RIGHT-HAND OPEN DUG + +01B75 +BALINESE MUSICAL SYMBOL RIGHT-HAND OPEN DAG + +01B76 +BALINESE MUSICAL SYMBOL RIGHT-HAND CLOSED TUK + +01B77 +BALINESE MUSICAL SYMBOL RIGHT-HAND CLOSED TAK + +01B78 +BALINESE MUSICAL SYMBOL LEFT-HAND OPEN PANG + +01B79 +BALINESE MUSICAL SYMBOL LEFT-HAND OPEN PUNG + +01B7A +BALINESE MUSICAL SYMBOL LEFT-HAND CLOSED PLAK + +01B7B +BALINESE MUSICAL SYMBOL LEFT-HAND CLOSED PLUK + +01B7C +BALINESE MUSICAL SYMBOL LEFT-HAND OPEN PING + +01B7D +BALINESE PANTI LANTANG + +01B7E +BALINESE PAMADA LANTANG + +01B7F +BALINESE PANTI BAWAK + +01B80 +SUNDANESE SIGN PANYECEK + +01B81 +SUNDANESE SIGN PANGLAYAR + +01B82 +SUNDANESE SIGN PANGWISAD + +01B83 +SUNDANESE LETTER A + +01B84 +SUNDANESE LETTER I + +01B85 +SUNDANESE LETTER U + +01B86 +SUNDANESE LETTER AE + +01B87 +SUNDANESE LETTER O + +01B88 +SUNDANESE LETTER E + +01B89 +SUNDANESE LETTER EU + +01B8A +SUNDANESE LETTER KA + +01B8B +SUNDANESE LETTER QA + +01B8C +SUNDANESE LETTER GA + +01B8D +SUNDANESE LETTER NGA + +01B8E +SUNDANESE LETTER CA + +01B8F +SUNDANESE LETTER JA + +01B90 +SUNDANESE LETTER ZA + +01B91 +SUNDANESE LETTER NYA + +01B92 +SUNDANESE LETTER TA + +01B93 +SUNDANESE LETTER DA + +01B94 +SUNDANESE LETTER NA + +01B95 +SUNDANESE LETTER PA + +01B96 +SUNDANESE LETTER FA + +01B97 +SUNDANESE LETTER VA + +01B98 +SUNDANESE LETTER BA + +01B99 +SUNDANESE LETTER MA + +01B9A +SUNDANESE LETTER YA + +01B9B +SUNDANESE LETTER RA + +01B9C +SUNDANESE LETTER LA + +01B9D +SUNDANESE LETTER WA + +01B9E +SUNDANESE LETTER SA + +01B9F +SUNDANESE LETTER XA + +01BA0 +SUNDANESE LETTER HA + +01BA1 +SUNDANESE CONSONANT SIGN PAMINGKAL + +01BA2 +SUNDANESE CONSONANT SIGN PANYAKRA + +01BA3 +SUNDANESE CONSONANT SIGN PANYIKU + +01BA4 +SUNDANESE VOWEL SIGN PANGHULU + +01BA5 +SUNDANESE VOWEL SIGN PANYUKU + +01BA6 +SUNDANESE VOWEL SIGN PANAELAENG + +01BA7 +SUNDANESE VOWEL SIGN PANOLONG + +01BA8 +SUNDANESE VOWEL SIGN PAMEPET + +01BA9 +SUNDANESE VOWEL SIGN PANEULEUNG + +01BAA +SUNDANESE SIGN PAMAAEH + +01BAB +SUNDANESE SIGN VIRAMA + +01BAC +SUNDANESE CONSONANT SIGN PASANGAN MA + +01BAD +SUNDANESE CONSONANT SIGN PASANGAN WA + +01BAE +SUNDANESE LETTER KHA + +01BAF +SUNDANESE LETTER SYA + +01BB0 +SUNDANESE DIGIT ZERO + +01BB1 +SUNDANESE DIGIT ONE + +01BB2 +SUNDANESE DIGIT TWO + +01BB3 +SUNDANESE DIGIT THREE + +01BB4 +SUNDANESE DIGIT FOUR + +01BB5 +SUNDANESE DIGIT FIVE + +01BB6 +SUNDANESE DIGIT SIX + +01BB7 +SUNDANESE DIGIT SEVEN + +01BB8 +SUNDANESE DIGIT EIGHT + +01BB9 +SUNDANESE DIGIT NINE + +01BBA +SUNDANESE AVAGRAHA + +01BBB +SUNDANESE LETTER REU + +01BBC +SUNDANESE LETTER LEU + +01BBD +SUNDANESE LETTER ARCHAIC I + +01BBD +SUNDANESE LETTER BHA + +01BBE +SUNDANESE LETTER FINAL K + +01BBF +SUNDANESE LETTER FINAL M + +01BC0 +BATAK LETTER A + +01BC1 +BATAK LETTER SIMALUNGUN A + +01BC2 +BATAK LETTER HA + +01BC3 +BATAK LETTER SIMALUNGUN HA + +01BC4 +BATAK LETTER MANDAILING HA + +01BC5 +BATAK LETTER BA + +01BC6 +BATAK LETTER KARO BA + +01BC7 +BATAK LETTER PA + +01BC8 +BATAK LETTER SIMALUNGUN PA + +01BC9 +BATAK LETTER NA + +01BCA +BATAK LETTER MANDAILING NA + +01BCB +BATAK LETTER WA + +01BCC +BATAK LETTER SIMALUNGUN WA + +01BCD +BATAK LETTER PAKPAK WA + +01BCE +BATAK LETTER GA + +01BCF +BATAK LETTER SIMALUNGUN GA + +01BD0 +BATAK LETTER JA + +01BD1 +BATAK LETTER DA + +01BD2 +BATAK LETTER RA + +01BD3 +BATAK LETTER SIMALUNGUN RA + +01BD4 +BATAK LETTER MA + +01BD5 +BATAK LETTER SIMALUNGUN MA + +01BD6 +BATAK LETTER SOUTHERN TA + +01BD7 +BATAK LETTER NORTHERN TA + +01BD8 +BATAK LETTER SA + +01BD9 +BATAK LETTER SIMALUNGUN SA + +01BDA +BATAK LETTER MANDAILING SA + +01BDB +BATAK LETTER YA + +01BDC +BATAK LETTER SIMALUNGUN YA + +01BDD +BATAK LETTER NGA + +01BDE +BATAK LETTER LA + +01BDF +BATAK LETTER SIMALUNGUN LA + +01BE0 +BATAK LETTER NYA + +01BE1 +BATAK LETTER CA + +01BE2 +BATAK LETTER NDA + +01BE3 +BATAK LETTER MBA + +01BE4 +BATAK LETTER I + +01BE5 +BATAK LETTER U + +01BE6 +BATAK SIGN TOMPI + +01BE7 +BATAK VOWEL SIGN E + +01BE8 +BATAK VOWEL SIGN PAKPAK E + +01BE9 +BATAK VOWEL SIGN EE + +01BEA +BATAK VOWEL SIGN I + +01BEB +BATAK VOWEL SIGN KARO I + +01BEC +BATAK VOWEL SIGN O + +01BED +BATAK VOWEL SIGN KARO O + +01BEE +BATAK VOWEL SIGN U + +01BEF +BATAK VOWEL SIGN U FOR SIMALUNGUN SA + +01BF0 +BATAK CONSONANT SIGN NG + +01BF1 +BATAK CONSONANT SIGN H + +01BF2 +BATAK PANGOLAT + +01BF3 +BATAK PANONGONAN + +01BFC +BATAK SYMBOL BINDU NA METEK + +01BFD +BATAK SYMBOL BINDU PINARBORAS + +01BFE +BATAK SYMBOL BINDU JUDUL + +01BFF +BATAK SYMBOL BINDU PANGOLAT + +01C00 +LEPCHA LETTER KA + +01C01 +LEPCHA LETTER KLA + +01C02 +LEPCHA LETTER KHA + +01C03 +LEPCHA LETTER GA + +01C04 +LEPCHA LETTER GLA + +01C05 +LEPCHA LETTER NGA + +01C06 +LEPCHA LETTER CA + +01C07 +LEPCHA LETTER CHA + +01C08 +LEPCHA LETTER JA + +01C09 +LEPCHA LETTER NYA + +01C0A +LEPCHA LETTER TA + +01C0B +LEPCHA LETTER THA + +01C0C +LEPCHA LETTER DA + +01C0D +LEPCHA LETTER NA + +01C0E +LEPCHA LETTER PA + +01C0F +LEPCHA LETTER PLA + +01C10 +LEPCHA LETTER PHA + +01C11 +LEPCHA LETTER FA + +01C12 +LEPCHA LETTER FLA + +01C13 +LEPCHA LETTER BA + +01C14 +LEPCHA LETTER BLA + +01C15 +LEPCHA LETTER MA + +01C16 +LEPCHA LETTER MLA + +01C17 +LEPCHA LETTER TSA + +01C18 +LEPCHA LETTER TSHA + +01C19 +LEPCHA LETTER DZA + +01C1A +LEPCHA LETTER YA + +01C1B +LEPCHA LETTER RA + +01C1C +LEPCHA LETTER LA + +01C1D +LEPCHA LETTER HA + +01C1E +LEPCHA LETTER HLA + +01C1F +LEPCHA LETTER VA + +01C20 +LEPCHA LETTER SA + +01C21 +LEPCHA LETTER SHA + +01C22 +LEPCHA LETTER WA + +01C23 +LEPCHA LETTER A + +01C24 +LEPCHA SUBJOINED LETTER YA + +01C25 +LEPCHA SUBJOINED LETTER RA + +01C26 +LEPCHA VOWEL SIGN AA + +01C27 +LEPCHA VOWEL SIGN I + +01C28 +LEPCHA VOWEL SIGN O + +01C29 +LEPCHA VOWEL SIGN OO + +01C2A +LEPCHA VOWEL SIGN U + +01C2B +LEPCHA VOWEL SIGN UU + +01C2C +LEPCHA VOWEL SIGN E + +01C2D +LEPCHA CONSONANT SIGN K + +01C2E +LEPCHA CONSONANT SIGN M + +01C2F +LEPCHA CONSONANT SIGN L + +01C30 +LEPCHA CONSONANT SIGN N + +01C31 +LEPCHA CONSONANT SIGN P + +01C32 +LEPCHA CONSONANT SIGN R + +01C33 +LEPCHA CONSONANT SIGN T + +01C34 +LEPCHA CONSONANT SIGN NYIN-DO + +01C35 +LEPCHA CONSONANT SIGN KANG + +01C36 +LEPCHA SIGN RAN + +01C37 +LEPCHA SIGN NUKTA + +01C3B +LEPCHA PUNCTUATION TA-ROL + +01C3C +LEPCHA PUNCTUATION NYET THYOOM TA-ROL + +01C3D +LEPCHA PUNCTUATION CER-WA + +01C3E +LEPCHA PUNCTUATION TSHOOK CER-WA + +01C3F +LEPCHA PUNCTUATION TSHOOK + +01C40 +LEPCHA DIGIT ZERO + +01C41 +LEPCHA DIGIT ONE + +01C42 +LEPCHA DIGIT TWO + +01C43 +LEPCHA DIGIT THREE + +01C44 +LEPCHA DIGIT FOUR + +01C45 +LEPCHA DIGIT FIVE + +01C46 +LEPCHA DIGIT SIX + +01C47 +LEPCHA DIGIT SEVEN + +01C48 +LEPCHA DIGIT EIGHT + +01C49 +LEPCHA DIGIT NINE + +01C4D +LEPCHA LETTER TTA + +01C4E +LEPCHA LETTER TTHA + +01C4F +LEPCHA LETTER DDA + +01C50 +OL CHIKI DIGIT ZERO + +01C51 +OL CHIKI DIGIT ONE + +01C52 +OL CHIKI DIGIT TWO + +01C53 +OL CHIKI DIGIT THREE + +01C54 +OL CHIKI DIGIT FOUR + +01C55 +OL CHIKI DIGIT FIVE + +01C56 +OL CHIKI DIGIT SIX + +01C57 +OL CHIKI DIGIT SEVEN + +01C58 +OL CHIKI DIGIT EIGHT + +01C59 +OL CHIKI DIGIT NINE + +01C5A +OL CHIKI LETTER LA + +01C5B +OL CHIKI LETTER AT + +01C5C +OL CHIKI LETTER AG + +01C5D +OL CHIKI LETTER ANG + +01C5E +OL CHIKI LETTER AL + +01C5F +OL CHIKI LETTER LAA + +01C60 +OL CHIKI LETTER AAK + +01C61 +OL CHIKI LETTER AAJ + +01C62 +OL CHIKI LETTER AAM + +01C63 +OL CHIKI LETTER AAW + +01C64 +OL CHIKI LETTER LI + +01C65 +OL CHIKI LETTER IS + +01C66 +OL CHIKI LETTER IH + +01C67 +OL CHIKI LETTER INY + +01C68 +OL CHIKI LETTER IR + +01C69 +OL CHIKI LETTER LU + +01C6A +OL CHIKI LETTER UC + +01C6B +OL CHIKI LETTER UD + +01C6C +OL CHIKI LETTER UNN + +01C6D +OL CHIKI LETTER UY + +01C6E +OL CHIKI LETTER LE + +01C6F +OL CHIKI LETTER EP + +01C70 +OL CHIKI LETTER EDD + +01C71 +OL CHIKI LETTER EN + +01C72 +OL CHIKI LETTER ERR + +01C73 +OL CHIKI LETTER LO + +01C74 +OL CHIKI LETTER OTT + +01C75 +OL CHIKI LETTER OB + +01C76 +OL CHIKI LETTER OV + +01C77 +OL CHIKI LETTER OH + +01C78 +OL CHIKI MU TTUDDAG + +01C79 +OL CHIKI GAAHLAA TTUDDAAG + +01C7A +OL CHIKI MU-GAAHLAA TTUDDAAG + +01C7B +OL CHIKI RELAA + +01C7C +OL CHIKI PHAARKAA + +01C7D +OL CHIKI AHAD + +01C7E +OL CHIKI PUNCTUATION MUCAAD + +01C7F +OL CHIKI PUNCTUATION DOUBLE MUCAAD + +01C80 +CYRILLIC SMALL LETTER ROUNDED VE + +01C81 +CYRILLIC SMALL LETTER LONG-LEGGED DE + +01C82 +CYRILLIC SMALL LETTER NARROW O + +01C83 +CYRILLIC SMALL LETTER WIDE ES + +01C84 +CYRILLIC SMALL LETTER TALL TE + +01C85 +CYRILLIC SMALL LETTER THREE-LEGGED TE + +01C86 +CYRILLIC SMALL LETTER TALL HARD SIGN + +01C87 +CYRILLIC SMALL LETTER TALL YAT + +01C88 +CYRILLIC SMALL LETTER UNBLENDED UK + +01C89 +CYRILLIC CAPITAL LETTER TJE + +01C8A +CYRILLIC SMALL LETTER TJE + +01C90 +GEORGIAN MTAVRULI CAPITAL LETTER AN + +01C91 +GEORGIAN MTAVRULI CAPITAL LETTER BAN + +01C92 +GEORGIAN MTAVRULI CAPITAL LETTER GAN + +01C93 +GEORGIAN MTAVRULI CAPITAL LETTER DON + +01C94 +GEORGIAN MTAVRULI CAPITAL LETTER EN + +01C95 +GEORGIAN MTAVRULI CAPITAL LETTER VIN + +01C96 +GEORGIAN MTAVRULI CAPITAL LETTER ZEN + +01C97 +GEORGIAN MTAVRULI CAPITAL LETTER TAN + +01C98 +GEORGIAN MTAVRULI CAPITAL LETTER IN + +01C99 +GEORGIAN MTAVRULI CAPITAL LETTER KAN + +01C9A +GEORGIAN MTAVRULI CAPITAL LETTER LAS + +01C9B +GEORGIAN MTAVRULI CAPITAL LETTER MAN + +01C9C +GEORGIAN MTAVRULI CAPITAL LETTER NAR + +01C9D +GEORGIAN MTAVRULI CAPITAL LETTER ON + +01C9E +GEORGIAN MTAVRULI CAPITAL LETTER PAR + +01C9F +GEORGIAN MTAVRULI CAPITAL LETTER ZHAR + +01CA0 +GEORGIAN MTAVRULI CAPITAL LETTER RAE + +01CA1 +GEORGIAN MTAVRULI CAPITAL LETTER SAN + +01CA2 +GEORGIAN MTAVRULI CAPITAL LETTER TAR + +01CA3 +GEORGIAN MTAVRULI CAPITAL LETTER UN + +01CA4 +GEORGIAN MTAVRULI CAPITAL LETTER PHAR + +01CA5 +GEORGIAN MTAVRULI CAPITAL LETTER KHAR + +01CA6 +GEORGIAN MTAVRULI CAPITAL LETTER GHAN + +01CA7 +GEORGIAN MTAVRULI CAPITAL LETTER QAR + +01CA8 +GEORGIAN MTAVRULI CAPITAL LETTER SHIN + +01CA9 +GEORGIAN MTAVRULI CAPITAL LETTER CHIN + +01CAA +GEORGIAN MTAVRULI CAPITAL LETTER CAN + +01CAB +GEORGIAN MTAVRULI CAPITAL LETTER JIL + +01CAC +GEORGIAN MTAVRULI CAPITAL LETTER CIL + +01CAD +GEORGIAN MTAVRULI CAPITAL LETTER CHAR + +01CAE +GEORGIAN MTAVRULI CAPITAL LETTER XAN + +01CAF +GEORGIAN MTAVRULI CAPITAL LETTER JHAN + +01CB0 +GEORGIAN MTAVRULI CAPITAL LETTER HAE + +01CB1 +GEORGIAN MTAVRULI CAPITAL LETTER HE + +01CB2 +GEORGIAN MTAVRULI CAPITAL LETTER HIE + +01CB3 +GEORGIAN MTAVRULI CAPITAL LETTER WE + +01CB4 +GEORGIAN MTAVRULI CAPITAL LETTER HAR + +01CB5 +GEORGIAN MTAVRULI CAPITAL LETTER HOE + +01CB6 +GEORGIAN MTAVRULI CAPITAL LETTER FI + +01CB7 +GEORGIAN MTAVRULI CAPITAL LETTER YN + +01CB8 +GEORGIAN MTAVRULI CAPITAL LETTER ELIFI + +01CB9 +GEORGIAN MTAVRULI CAPITAL LETTER TURNED GAN + +01CBA +GEORGIAN MTAVRULI CAPITAL LETTER AIN + +01CBD +GEORGIAN MTAVRULI CAPITAL LETTER AEN + +01CBE +GEORGIAN MTAVRULI CAPITAL LETTER HARD SIGN + +01CBF +GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN + +01CC0 +SUNDANESE PUNCTUATION BINDU SURYA + +01CC1 +SUNDANESE PUNCTUATION BINDU PANGLONG + +01CC2 +SUNDANESE PUNCTUATION BINDU PURNAMA + +01CC3 +SUNDANESE PUNCTUATION BINDU CAKRA + +01CC4 +SUNDANESE PUNCTUATION BINDU LEU SATANGA + +01CC5 +SUNDANESE PUNCTUATION BINDU KA SATANGA + +01CC6 +SUNDANESE PUNCTUATION BINDU DA SATANGA + +01CC7 +SUNDANESE PUNCTUATION BINDU BA SATANGA + +01CD0 +VEDIC TONE KARSHANA + +01CD1 +VEDIC TONE SHARA + +01CD2 +VEDIC TONE PRENKHA + +01CD3 +VEDIC SIGN NIHSHVASA + +01CD4 +VEDIC SIGN YAJURVEDIC MIDLINE SVARITA + +01CD5 +VEDIC TONE YAJURVEDIC AGGRAVATED INDEPENDENT SVARITA + +01CD6 +VEDIC TONE YAJURVEDIC INDEPENDENT SVARITA + +01CD7 +VEDIC TONE YAJURVEDIC KATHAKA INDEPENDENT SVARITA + +01CD8 +VEDIC TONE CANDRA BELOW + +01CD9 +VEDIC TONE YAJURVEDIC KATHAKA INDEPENDENT SVARITA SCHROEDER + +01CDA +VEDIC TONE DOUBLE SVARITA + +01CDB +VEDIC TONE TRIPLE SVARITA + +01CDC +VEDIC TONE KATHAKA ANUDATTA + +01CDD +VEDIC TONE DOT BELOW + +01CDE +VEDIC TONE TWO DOTS BELOW + +01CDF +VEDIC TONE THREE DOTS BELOW + +01CE0 +VEDIC TONE RIGVEDIC KASHMIRI INDEPENDENT SVARITA + +01CE1 +VEDIC TONE ATHARVAVEDIC INDEPENDENT SVARITA + +01CE2 +VEDIC SIGN VISARGA SVARITA + +01CE3 +VEDIC SIGN VISARGA UDATTA + +01CE4 +VEDIC SIGN REVERSED VISARGA UDATTA + +01CE5 +VEDIC SIGN VISARGA ANUDATTA + +01CE6 +VEDIC SIGN REVERSED VISARGA ANUDATTA + +01CE7 +VEDIC SIGN VISARGA UDATTA WITH TAIL + +01CE8 +VEDIC SIGN VISARGA ANUDATTA WITH TAIL + +01CE9 +VEDIC SIGN ANUSVARA ANTARGOMUKHA + +01CEA +VEDIC SIGN ANUSVARA BAHIRGOMUKHA + +01CEB +VEDIC SIGN ANUSVARA VAMAGOMUKHA + +01CEC +VEDIC SIGN ANUSVARA VAMAGOMUKHA WITH TAIL + +01CED +VEDIC SIGN TIRYAK + +01CEE +VEDIC SIGN HEXIFORM LONG ANUSVARA + +01CEF +VEDIC SIGN LONG ANUSVARA + +01CF0 +VEDIC SIGN RTHANG LONG ANUSVARA + +01CF1 +VEDIC SIGN ANUSVARA UBHAYATO MUKHA + +01CF2 +VEDIC SIGN ARDHAVISARGA + +01CF3 +VEDIC SIGN ROTATED ARDHAVISARGA + +01CF4 +VEDIC TONE CANDRA ABOVE + +01CF5 +VEDIC SIGN JIHVAMULIYA + +01CF6 +VEDIC SIGN UPADHMANIYA + +01CF7 +VEDIC SIGN ATIKRAMA + +01CF8 +VEDIC TONE RING ABOVE + +01CF9 +VEDIC TONE DOUBLE RING ABOVE + +01CFA +VEDIC SIGN DOUBLE ANUSVARA ANTARGOMUKHA + +01D00 +LATIN LETTER SMALL CAPITAL A + +01D01 +LATIN LETTER SMALL CAPITAL AE + +01D02 +LATIN SMALL LETTER TURNED AE + +01D03 +LATIN LETTER SMALL CAPITAL BARRED B + +01D04 +LATIN LETTER SMALL CAPITAL C + +01D05 +LATIN LETTER SMALL CAPITAL D + +01D06 +LATIN LETTER SMALL CAPITAL ETH + +01D07 +LATIN LETTER SMALL CAPITAL E + +01D08 +LATIN SMALL LETTER TURNED OPEN E + +01D09 +LATIN SMALL LETTER TURNED I + +01D0A +LATIN LETTER SMALL CAPITAL J + +01D0B +LATIN LETTER SMALL CAPITAL K + +01D0C +LATIN LETTER SMALL CAPITAL L WITH STROKE + +01D0D +LATIN LETTER SMALL CAPITAL M + +01D0E +LATIN LETTER SMALL CAPITAL REVERSED N + +01D0F +LATIN LETTER SMALL CAPITAL O + +01D10 +LATIN LETTER SMALL CAPITAL OPEN O + +01D11 +LATIN SMALL LETTER SIDEWAYS O + +01D12 +LATIN SMALL LETTER SIDEWAYS OPEN O + +01D13 +LATIN SMALL LETTER SIDEWAYS O WITH STROKE + +01D14 +LATIN SMALL LETTER TURNED OE + +01D15 +LATIN LETTER SMALL CAPITAL OU + +01D16 +LATIN SMALL LETTER TOP HALF O + +01D17 +LATIN SMALL LETTER BOTTOM HALF O + +01D18 +LATIN LETTER SMALL CAPITAL P + +01D19 +LATIN LETTER SMALL CAPITAL REVERSED R + +01D1A +LATIN LETTER SMALL CAPITAL TURNED R + +01D1B +LATIN LETTER SMALL CAPITAL T + +01D1C +LATIN LETTER SMALL CAPITAL U + +01D1D +LATIN SMALL LETTER SIDEWAYS U + +01D1E +LATIN SMALL LETTER SIDEWAYS DIAERESIZED U + +01D1F +LATIN SMALL LETTER SIDEWAYS TURNED M + +01D20 +LATIN LETTER SMALL CAPITAL V + +01D21 +LATIN LETTER SMALL CAPITAL W + +01D22 +LATIN LETTER SMALL CAPITAL Z + +01D23 +LATIN LETTER SMALL CAPITAL EZH + +01D24 +LATIN LETTER VOICED LARYNGEAL SPIRANT + +01D25 +LATIN LETTER AIN + +01D26 +GREEK LETTER SMALL CAPITAL GAMMA + +01D27 +GREEK LETTER SMALL CAPITAL LAMDA + +01D28 +GREEK LETTER SMALL CAPITAL PI + +01D29 +GREEK LETTER SMALL CAPITAL RHO + +01D2A +GREEK LETTER SMALL CAPITAL PSI + +01D2B +CYRILLIC LETTER SMALL CAPITAL EL + +01D2C +MODIFIER LETTER CAPITAL A + +01D2D +MODIFIER LETTER CAPITAL AE + +01D2E +MODIFIER LETTER CAPITAL B + +01D2F +MODIFIER LETTER CAPITAL BARRED B + +01D30 +MODIFIER LETTER CAPITAL D + +01D31 +MODIFIER LETTER CAPITAL E + +01D32 +MODIFIER LETTER CAPITAL REVERSED E + +01D33 +MODIFIER LETTER CAPITAL G + +01D34 +MODIFIER LETTER CAPITAL H + +01D35 +MODIFIER LETTER CAPITAL I + +01D36 +MODIFIER LETTER CAPITAL J + +01D37 +MODIFIER LETTER CAPITAL K + +01D38 +MODIFIER LETTER CAPITAL L + +01D39 +MODIFIER LETTER CAPITAL M + +01D3A +MODIFIER LETTER CAPITAL N + +01D3B +MODIFIER LETTER CAPITAL REVERSED N + +01D3C +MODIFIER LETTER CAPITAL O + +01D3D +MODIFIER LETTER CAPITAL OU + +01D3E +MODIFIER LETTER CAPITAL P + +01D3F +MODIFIER LETTER CAPITAL R + +01D40 +MODIFIER LETTER CAPITAL T + +01D41 +MODIFIER LETTER CAPITAL U + +01D42 +MODIFIER LETTER CAPITAL W + +01D43 +MODIFIER LETTER SMALL A + +01D44 +MODIFIER LETTER SMALL TURNED A + +01D45 +MODIFIER LETTER SMALL ALPHA + +01D46 +MODIFIER LETTER SMALL TURNED AE + +01D47 +MODIFIER LETTER SMALL B + +01D48 +MODIFIER LETTER SMALL D + +01D49 +MODIFIER LETTER SMALL E + +01D4A +MODIFIER LETTER SMALL SCHWA + +01D4B +MODIFIER LETTER SMALL OPEN E + +01D4C +MODIFIER LETTER SMALL TURNED OPEN E + +01D4D +MODIFIER LETTER SMALL G + +01D4E +MODIFIER LETTER SMALL TURNED I + +01D4F +MODIFIER LETTER SMALL K + +01D50 +MODIFIER LETTER SMALL M + +01D51 +MODIFIER LETTER SMALL ENG + +01D52 +MODIFIER LETTER SMALL O + +01D53 +MODIFIER LETTER SMALL OPEN O + +01D54 +MODIFIER LETTER SMALL TOP HALF O + +01D55 +MODIFIER LETTER SMALL BOTTOM HALF O + +01D56 +MODIFIER LETTER SMALL P + +01D57 +MODIFIER LETTER SMALL T + +01D58 +MODIFIER LETTER SMALL U + +01D59 +MODIFIER LETTER SMALL SIDEWAYS U + +01D5A +MODIFIER LETTER SMALL TURNED M + +01D5B +MODIFIER LETTER SMALL V + +01D5C +MODIFIER LETTER SMALL AIN + +01D5D +MODIFIER LETTER SMALL BETA + +01D5E +MODIFIER LETTER SMALL GREEK GAMMA + +01D5F +MODIFIER LETTER SMALL DELTA + +01D60 +MODIFIER LETTER SMALL GREEK PHI + +01D61 +MODIFIER LETTER SMALL CHI + +01D62 +LATIN SUBSCRIPT SMALL LETTER I + +01D63 +LATIN SUBSCRIPT SMALL LETTER R + +01D64 +LATIN SUBSCRIPT SMALL LETTER U + +01D65 +LATIN SUBSCRIPT SMALL LETTER V + +01D66 +GREEK SUBSCRIPT SMALL LETTER BETA + +01D67 +GREEK SUBSCRIPT SMALL LETTER GAMMA + +01D68 +GREEK SUBSCRIPT SMALL LETTER RHO + +01D69 +GREEK SUBSCRIPT SMALL LETTER PHI + +01D6A +GREEK SUBSCRIPT SMALL LETTER CHI + +01D6B +LATIN SMALL LETTER UE + +01D6C +LATIN SMALL LETTER B WITH MIDDLE TILDE + +01D6D +LATIN SMALL LETTER D WITH MIDDLE TILDE + +01D6E +LATIN SMALL LETTER F WITH MIDDLE TILDE + +01D6F +LATIN SMALL LETTER M WITH MIDDLE TILDE + +01D70 +LATIN SMALL LETTER N WITH MIDDLE TILDE + +01D71 +LATIN SMALL LETTER P WITH MIDDLE TILDE + +01D72 +LATIN SMALL LETTER R WITH MIDDLE TILDE + +01D73 +LATIN SMALL LETTER R WITH FISHHOOK AND MIDDLE TILDE + +01D74 +LATIN SMALL LETTER S WITH MIDDLE TILDE + +01D75 +LATIN SMALL LETTER T WITH MIDDLE TILDE + +01D76 +LATIN SMALL LETTER Z WITH MIDDLE TILDE + +01D77 +LATIN SMALL LETTER TURNED G + +01D78 +MODIFIER LETTER CYRILLIC EN + +01D79 +LATIN SMALL LETTER INSULAR G + +01D7A +LATIN SMALL LETTER TH WITH STRIKETHROUGH + +01D7B +LATIN SMALL CAPITAL LETTER I WITH STROKE + +01D7C +LATIN SMALL LETTER IOTA WITH STROKE + +01D7D +LATIN SMALL LETTER P WITH STROKE + +01D7E +LATIN SMALL CAPITAL LETTER U WITH STROKE + +01D7F +LATIN SMALL LETTER UPSILON WITH STROKE + +01D80 +LATIN SMALL LETTER B WITH PALATAL HOOK + +01D81 +LATIN SMALL LETTER D WITH PALATAL HOOK + +01D82 +LATIN SMALL LETTER F WITH PALATAL HOOK + +01D83 +LATIN SMALL LETTER G WITH PALATAL HOOK + +01D84 +LATIN SMALL LETTER K WITH PALATAL HOOK + +01D85 +LATIN SMALL LETTER L WITH PALATAL HOOK + +01D86 +LATIN SMALL LETTER M WITH PALATAL HOOK + +01D87 +LATIN SMALL LETTER N WITH PALATAL HOOK + +01D88 +LATIN SMALL LETTER P WITH PALATAL HOOK + +01D89 +LATIN SMALL LETTER R WITH PALATAL HOOK + +01D8A +LATIN SMALL LETTER S WITH PALATAL HOOK + +01D8B +LATIN SMALL LETTER ESH WITH PALATAL HOOK + +01D8C +LATIN SMALL LETTER V WITH PALATAL HOOK + +01D8D +LATIN SMALL LETTER X WITH PALATAL HOOK + +01D8E +LATIN SMALL LETTER Z WITH PALATAL HOOK + +01D8F +LATIN SMALL LETTER A WITH RETROFLEX HOOK + +01D90 +LATIN SMALL LETTER ALPHA WITH RETROFLEX HOOK + +01D91 +LATIN SMALL LETTER D WITH HOOK AND TAIL + +01D92 +LATIN SMALL LETTER E WITH RETROFLEX HOOK + +01D93 +LATIN SMALL LETTER OPEN E WITH RETROFLEX HOOK + +01D94 +LATIN SMALL LETTER REVERSED OPEN E WITH RETROFLEX HOOK + +01D95 +LATIN SMALL LETTER SCHWA WITH RETROFLEX HOOK + +01D96 +LATIN SMALL LETTER I WITH RETROFLEX HOOK + +01D97 +LATIN SMALL LETTER OPEN O WITH RETROFLEX HOOK + +01D98 +LATIN SMALL LETTER ESH WITH RETROFLEX HOOK + +01D99 +LATIN SMALL LETTER U WITH RETROFLEX HOOK + +01D9A +LATIN SMALL LETTER EZH WITH RETROFLEX HOOK + +01D9B +MODIFIER LETTER SMALL TURNED ALPHA + +01D9C +MODIFIER LETTER SMALL C + +01D9D +MODIFIER LETTER SMALL C WITH CURL + +01D9E +MODIFIER LETTER SMALL ETH + +01D9F +MODIFIER LETTER SMALL REVERSED OPEN E + +01DA0 +MODIFIER LETTER SMALL F + +01DA1 +MODIFIER LETTER SMALL DOTLESS J WITH STROKE + +01DA2 +MODIFIER LETTER SMALL SCRIPT G + +01DA3 +MODIFIER LETTER SMALL TURNED H + +01DA4 +MODIFIER LETTER SMALL I WITH STROKE + +01DA5 +MODIFIER LETTER SMALL IOTA + +01DA6 +MODIFIER LETTER SMALL CAPITAL I + +01DA7 +MODIFIER LETTER SMALL CAPITAL I WITH STROKE + +01DA8 +MODIFIER LETTER SMALL J WITH CROSSED-TAIL + +01DA9 +MODIFIER LETTER SMALL L WITH RETROFLEX HOOK + +01DAA +MODIFIER LETTER SMALL L WITH PALATAL HOOK + +01DAB +MODIFIER LETTER SMALL CAPITAL L + +01DAC +MODIFIER LETTER SMALL M WITH HOOK + +01DAD +MODIFIER LETTER SMALL TURNED M WITH LONG LEG + +01DAE +MODIFIER LETTER SMALL N WITH LEFT HOOK + +01DAF +MODIFIER LETTER SMALL N WITH RETROFLEX HOOK + +01DB0 +MODIFIER LETTER SMALL CAPITAL N + +01DB1 +MODIFIER LETTER SMALL BARRED O + +01DB2 +MODIFIER LETTER SMALL PHI + +01DB3 +MODIFIER LETTER SMALL S WITH HOOK + +01DB4 +MODIFIER LETTER SMALL ESH + +01DB5 +MODIFIER LETTER SMALL T WITH PALATAL HOOK + +01DB6 +MODIFIER LETTER SMALL U BAR + +01DB7 +MODIFIER LETTER SMALL UPSILON + +01DB8 +MODIFIER LETTER SMALL CAPITAL U + +01DB9 +MODIFIER LETTER SMALL V WITH HOOK + +01DBA +MODIFIER LETTER SMALL TURNED V + +01DBB +MODIFIER LETTER SMALL Z + +01DBC +MODIFIER LETTER SMALL Z WITH RETROFLEX HOOK + +01DBD +MODIFIER LETTER SMALL Z WITH CURL + +01DBE +MODIFIER LETTER SMALL EZH + +01DBF +MODIFIER LETTER SMALL THETA + +01DC0 +COMBINING DOTTED GRAVE ACCENT + +01DC1 +COMBINING DOTTED ACUTE ACCENT + +01DC2 +COMBINING SNAKE BELOW + +01DC3 +COMBINING SUSPENSION MARK + +01DC4 +COMBINING MACRON-ACUTE + +01DC5 +COMBINING GRAVE-MACRON + +01DC6 +COMBINING MACRON-GRAVE + +01DC7 +COMBINING ACUTE-MACRON + +01DC8 +COMBINING GRAVE-ACUTE-GRAVE + +01DC9 +COMBINING ACUTE-GRAVE-ACUTE + +01DCA +COMBINING LATIN SMALL LETTER R BELOW + +01DCB +COMBINING BREVE-MACRON + +01DCC +COMBINING MACRON-BREVE + +01DCD +COMBINING DOUBLE CIRCUMFLEX ABOVE + +01DCE +COMBINING OGONEK ABOVE + +01DCF +COMBINING ZIGZAG BELOW + +01DD0 +COMBINING IS BELOW + +01DD1 +COMBINING UR ABOVE + +01DD2 +COMBINING US ABOVE + +01DD3 +COMBINING LATIN SMALL LETTER FLATTENED OPEN A ABOVE + +01DD4 +COMBINING LATIN SMALL LETTER AE + +01DD5 +COMBINING LATIN SMALL LETTER AO + +01DD6 +COMBINING LATIN SMALL LETTER AV + +01DD7 +COMBINING LATIN SMALL LETTER C CEDILLA + +01DD8 +COMBINING LATIN SMALL LETTER INSULAR D + +01DD9 +COMBINING LATIN SMALL LETTER ETH + +01DDA +COMBINING LATIN SMALL LETTER G + +01DDB +COMBINING LATIN LETTER SMALL CAPITAL G + +01DDC +COMBINING LATIN SMALL LETTER K + +01DDD +COMBINING LATIN SMALL LETTER L + +01DDE +COMBINING LATIN LETTER SMALL CAPITAL L + +01DDF +COMBINING LATIN LETTER SMALL CAPITAL M + +01DE0 +COMBINING LATIN SMALL LETTER N + +01DE1 +COMBINING LATIN LETTER SMALL CAPITAL N + +01DE2 +COMBINING LATIN LETTER SMALL CAPITAL R + +01DE3 +COMBINING LATIN SMALL LETTER R ROTUNDA + +01DE4 +COMBINING LATIN SMALL LETTER S + +01DE5 +COMBINING LATIN SMALL LETTER LONG S + +01DE6 +COMBINING LATIN SMALL LETTER Z + +01DE7 +COMBINING LATIN SMALL LETTER ALPHA + +01DE8 +COMBINING LATIN SMALL LETTER B + +01DE9 +COMBINING LATIN SMALL LETTER BETA + +01DEA +COMBINING LATIN SMALL LETTER SCHWA + +01DEB +COMBINING LATIN SMALL LETTER F + +01DEC +COMBINING LATIN SMALL LETTER L WITH DOUBLE MIDDLE TILDE + +01DED +COMBINING LATIN SMALL LETTER O WITH LIGHT CENTRALIZATION STROKE + +01DEE +COMBINING LATIN SMALL LETTER P + +01DEF +COMBINING LATIN SMALL LETTER ESH + +01DF0 +COMBINING LATIN SMALL LETTER U WITH LIGHT CENTRALIZATION STROKE + +01DF1 +COMBINING LATIN SMALL LETTER W + +01DF2 +COMBINING LATIN SMALL LETTER A WITH DIAERESIS + +01DF3 +COMBINING LATIN SMALL LETTER O WITH DIAERESIS + +01DF4 +COMBINING LATIN SMALL LETTER U WITH DIAERESIS + +01DF5 +COMBINING UP TACK ABOVE + +01DF6 +COMBINING KAVYKA ABOVE RIGHT + +01DF7 +COMBINING KAVYKA ABOVE LEFT + +01DF8 +COMBINING DOT ABOVE LEFT + +01DF9 +COMBINING WIDE INVERTED BRIDGE BELOW + +01DFA +COMBINING DOT BELOW LEFT + +01DFB +COMBINING DELETION MARK + +01DFC +COMBINING DOUBLE INVERTED BREVE BELOW + +01DFD +COMBINING ALMOST EQUAL TO BELOW + +01DFE +COMBINING LEFT ARROWHEAD ABOVE + +01DFF +COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW + +01E00 +LATIN CAPITAL LETTER A WITH RING BELOW + +01E01 +LATIN SMALL LETTER A WITH RING BELOW + +01E02 +LATIN CAPITAL LETTER B WITH DOT ABOVE + +01E03 +LATIN SMALL LETTER B WITH DOT ABOVE + +01E04 +LATIN CAPITAL LETTER B WITH DOT BELOW + +01E05 +LATIN SMALL LETTER B WITH DOT BELOW + +01E06 +LATIN CAPITAL LETTER B WITH LINE BELOW + +01E07 +LATIN SMALL LETTER B WITH LINE BELOW + +01E08 +LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE + +01E09 +LATIN SMALL LETTER C WITH CEDILLA AND ACUTE + +01E0A +LATIN CAPITAL LETTER D WITH DOT ABOVE + +01E0B +LATIN SMALL LETTER D WITH DOT ABOVE + +01E0C +LATIN CAPITAL LETTER D WITH DOT BELOW + +01E0D +LATIN SMALL LETTER D WITH DOT BELOW + +01E0E +LATIN CAPITAL LETTER D WITH LINE BELOW + +01E0F +LATIN SMALL LETTER D WITH LINE BELOW + +01E10 +LATIN CAPITAL LETTER D WITH CEDILLA + +01E11 +LATIN SMALL LETTER D WITH CEDILLA + +01E12 +LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW + +01E13 +LATIN SMALL LETTER D WITH CIRCUMFLEX BELOW + +01E14 +LATIN CAPITAL LETTER E WITH MACRON AND GRAVE + +01E15 +LATIN SMALL LETTER E WITH MACRON AND GRAVE + +01E16 +LATIN CAPITAL LETTER E WITH MACRON AND ACUTE + +01E17 +LATIN SMALL LETTER E WITH MACRON AND ACUTE + +01E18 +LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW + +01E19 +LATIN SMALL LETTER E WITH CIRCUMFLEX BELOW + +01E1A +LATIN CAPITAL LETTER E WITH TILDE BELOW + +01E1B +LATIN SMALL LETTER E WITH TILDE BELOW + +01E1C +LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE + +01E1D +LATIN SMALL LETTER E WITH CEDILLA AND BREVE + +01E1E +LATIN CAPITAL LETTER F WITH DOT ABOVE + +01E1F +LATIN SMALL LETTER F WITH DOT ABOVE + +01E20 +LATIN CAPITAL LETTER G WITH MACRON + +01E21 +LATIN SMALL LETTER G WITH MACRON + +01E22 +LATIN CAPITAL LETTER H WITH DOT ABOVE + +01E23 +LATIN SMALL LETTER H WITH DOT ABOVE + +01E24 +LATIN CAPITAL LETTER H WITH DOT BELOW + +01E25 +LATIN SMALL LETTER H WITH DOT BELOW + +01E26 +LATIN CAPITAL LETTER H WITH DIAERESIS + +01E27 +LATIN SMALL LETTER H WITH DIAERESIS + +01E28 +LATIN CAPITAL LETTER H WITH CEDILLA + +01E29 +LATIN SMALL LETTER H WITH CEDILLA + +01E2A +LATIN CAPITAL LETTER H WITH BREVE BELOW + +01E2B +LATIN SMALL LETTER H WITH BREVE BELOW + +01E2C +LATIN CAPITAL LETTER I WITH TILDE BELOW + +01E2D +LATIN SMALL LETTER I WITH TILDE BELOW + +01E2E +LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE + +01E2F +LATIN SMALL LETTER I WITH DIAERESIS AND ACUTE + +01E30 +LATIN CAPITAL LETTER K WITH ACUTE + +01E31 +LATIN SMALL LETTER K WITH ACUTE + +01E32 +LATIN CAPITAL LETTER K WITH DOT BELOW + +01E33 +LATIN SMALL LETTER K WITH DOT BELOW + +01E34 +LATIN CAPITAL LETTER K WITH LINE BELOW + +01E35 +LATIN SMALL LETTER K WITH LINE BELOW + +01E36 +LATIN CAPITAL LETTER L WITH DOT BELOW + +01E37 +LATIN SMALL LETTER L WITH DOT BELOW + +01E38 +LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON + +01E39 +LATIN SMALL LETTER L WITH DOT BELOW AND MACRON + +01E3A +LATIN CAPITAL LETTER L WITH LINE BELOW + +01E3B +LATIN SMALL LETTER L WITH LINE BELOW + +01E3C +LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW + +01E3D +LATIN SMALL LETTER L WITH CIRCUMFLEX BELOW + +01E3E +LATIN CAPITAL LETTER M WITH ACUTE + +01E3F +LATIN SMALL LETTER M WITH ACUTE + +01E40 +LATIN CAPITAL LETTER M WITH DOT ABOVE + +01E41 +LATIN SMALL LETTER M WITH DOT ABOVE + +01E42 +LATIN CAPITAL LETTER M WITH DOT BELOW + +01E43 +LATIN SMALL LETTER M WITH DOT BELOW + +01E44 +LATIN CAPITAL LETTER N WITH DOT ABOVE + +01E45 +LATIN SMALL LETTER N WITH DOT ABOVE + +01E46 +LATIN CAPITAL LETTER N WITH DOT BELOW + +01E47 +LATIN SMALL LETTER N WITH DOT BELOW + +01E48 +LATIN CAPITAL LETTER N WITH LINE BELOW + +01E49 +LATIN SMALL LETTER N WITH LINE BELOW + +01E4A +LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW + +01E4B +LATIN SMALL LETTER N WITH CIRCUMFLEX BELOW + +01E4C +LATIN CAPITAL LETTER O WITH TILDE AND ACUTE + +01E4D +LATIN SMALL LETTER O WITH TILDE AND ACUTE + +01E4E +LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS + +01E4F +LATIN SMALL LETTER O WITH TILDE AND DIAERESIS + +01E50 +LATIN CAPITAL LETTER O WITH MACRON AND GRAVE + +01E51 +LATIN SMALL LETTER O WITH MACRON AND GRAVE + +01E52 +LATIN CAPITAL LETTER O WITH MACRON AND ACUTE + +01E53 +LATIN SMALL LETTER O WITH MACRON AND ACUTE + +01E54 +LATIN CAPITAL LETTER P WITH ACUTE + +01E55 +LATIN SMALL LETTER P WITH ACUTE + +01E56 +LATIN CAPITAL LETTER P WITH DOT ABOVE + +01E57 +LATIN SMALL LETTER P WITH DOT ABOVE + +01E58 +LATIN CAPITAL LETTER R WITH DOT ABOVE + +01E59 +LATIN SMALL LETTER R WITH DOT ABOVE + +01E5A +LATIN CAPITAL LETTER R WITH DOT BELOW + +01E5B +LATIN SMALL LETTER R WITH DOT BELOW + +01E5C +LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON + +01E5D +LATIN SMALL LETTER R WITH DOT BELOW AND MACRON + +01E5E +LATIN CAPITAL LETTER R WITH LINE BELOW + +01E5F +LATIN SMALL LETTER R WITH LINE BELOW + +01E60 +LATIN CAPITAL LETTER S WITH DOT ABOVE + +01E61 +LATIN SMALL LETTER S WITH DOT ABOVE + +01E62 +LATIN CAPITAL LETTER S WITH DOT BELOW + +01E63 +LATIN SMALL LETTER S WITH DOT BELOW + +01E64 +LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE + +01E65 +LATIN SMALL LETTER S WITH ACUTE AND DOT ABOVE + +01E66 +LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE + +01E67 +LATIN SMALL LETTER S WITH CARON AND DOT ABOVE + +01E68 +LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE + +01E69 +LATIN SMALL LETTER S WITH DOT BELOW AND DOT ABOVE + +01E6A +LATIN CAPITAL LETTER T WITH DOT ABOVE + +01E6B +LATIN SMALL LETTER T WITH DOT ABOVE + +01E6C +LATIN CAPITAL LETTER T WITH DOT BELOW + +01E6D +LATIN SMALL LETTER T WITH DOT BELOW + +01E6E +LATIN CAPITAL LETTER T WITH LINE BELOW + +01E6F +LATIN SMALL LETTER T WITH LINE BELOW + +01E70 +LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW + +01E71 +LATIN SMALL LETTER T WITH CIRCUMFLEX BELOW + +01E72 +LATIN CAPITAL LETTER U WITH DIAERESIS BELOW + +01E73 +LATIN SMALL LETTER U WITH DIAERESIS BELOW + +01E74 +LATIN CAPITAL LETTER U WITH TILDE BELOW + +01E75 +LATIN SMALL LETTER U WITH TILDE BELOW + +01E76 +LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW + +01E77 +LATIN SMALL LETTER U WITH CIRCUMFLEX BELOW + +01E78 +LATIN CAPITAL LETTER U WITH TILDE AND ACUTE + +01E79 +LATIN SMALL LETTER U WITH TILDE AND ACUTE + +01E7A +LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS + +01E7B +LATIN SMALL LETTER U WITH MACRON AND DIAERESIS + +01E7C +LATIN CAPITAL LETTER V WITH TILDE + +01E7D +LATIN SMALL LETTER V WITH TILDE + +01E7E +LATIN CAPITAL LETTER V WITH DOT BELOW + +01E7F +LATIN SMALL LETTER V WITH DOT BELOW + +01E80 +LATIN CAPITAL LETTER W WITH GRAVE + +01E81 +LATIN SMALL LETTER W WITH GRAVE + +01E82 +LATIN CAPITAL LETTER W WITH ACUTE + +01E83 +LATIN SMALL LETTER W WITH ACUTE + +01E84 +LATIN CAPITAL LETTER W WITH DIAERESIS + +01E85 +LATIN SMALL LETTER W WITH DIAERESIS + +01E86 +LATIN CAPITAL LETTER W WITH DOT ABOVE + +01E87 +LATIN SMALL LETTER W WITH DOT ABOVE + +01E88 +LATIN CAPITAL LETTER W WITH DOT BELOW + +01E89 +LATIN SMALL LETTER W WITH DOT BELOW + +01E8A +LATIN CAPITAL LETTER X WITH DOT ABOVE + +01E8B +LATIN SMALL LETTER X WITH DOT ABOVE + +01E8C +LATIN CAPITAL LETTER X WITH DIAERESIS + +01E8D +LATIN SMALL LETTER X WITH DIAERESIS + +01E8E +LATIN CAPITAL LETTER Y WITH DOT ABOVE + +01E8F +LATIN SMALL LETTER Y WITH DOT ABOVE + +01E90 +LATIN CAPITAL LETTER Z WITH CIRCUMFLEX + +01E91 +LATIN SMALL LETTER Z WITH CIRCUMFLEX + +01E92 +LATIN CAPITAL LETTER Z WITH DOT BELOW + +01E93 +LATIN SMALL LETTER Z WITH DOT BELOW + +01E94 +LATIN CAPITAL LETTER Z WITH LINE BELOW + +01E95 +LATIN SMALL LETTER Z WITH LINE BELOW + +01E96 +LATIN SMALL LETTER H WITH LINE BELOW + +01E97 +LATIN SMALL LETTER T WITH DIAERESIS + +01E98 +LATIN SMALL LETTER W WITH RING ABOVE + +01E99 +LATIN SMALL LETTER Y WITH RING ABOVE + +01E9A +LATIN SMALL LETTER A WITH RIGHT HALF RING + +01E9B +LATIN SMALL LETTER LONG S WITH DOT ABOVE + +01E9C +LATIN SMALL LETTER LONG S WITH DIAGONAL STROKE + +01E9D +LATIN SMALL LETTER LONG S WITH HIGH STROKE + +01E9E +LATIN CAPITAL LETTER SHARP S + +01E9F +LATIN SMALL LETTER DELTA + +01EA0 +LATIN CAPITAL LETTER A WITH DOT BELOW + +01EA1 +LATIN SMALL LETTER A WITH DOT BELOW + +01EA2 +LATIN CAPITAL LETTER A WITH HOOK ABOVE + +01EA3 +LATIN SMALL LETTER A WITH HOOK ABOVE + +01EA4 +LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE + +01EA5 +LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE + +01EA6 +LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE + +01EA7 +LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE + +01EA8 +LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE + +01EA9 +LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE + +01EAA +LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE + +01EAB +LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE + +01EAC +LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW + +01EAD +LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW + +01EAE +LATIN CAPITAL LETTER A WITH BREVE AND ACUTE + +01EAF +LATIN SMALL LETTER A WITH BREVE AND ACUTE + +01EB0 +LATIN CAPITAL LETTER A WITH BREVE AND GRAVE + +01EB1 +LATIN SMALL LETTER A WITH BREVE AND GRAVE + +01EB2 +LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE + +01EB3 +LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE + +01EB4 +LATIN CAPITAL LETTER A WITH BREVE AND TILDE + +01EB5 +LATIN SMALL LETTER A WITH BREVE AND TILDE + +01EB6 +LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW + +01EB7 +LATIN SMALL LETTER A WITH BREVE AND DOT BELOW + +01EB8 +LATIN CAPITAL LETTER E WITH DOT BELOW + +01EB9 +LATIN SMALL LETTER E WITH DOT BELOW + +01EBA +LATIN CAPITAL LETTER E WITH HOOK ABOVE + +01EBB +LATIN SMALL LETTER E WITH HOOK ABOVE + +01EBC +LATIN CAPITAL LETTER E WITH TILDE + +01EBD +LATIN SMALL LETTER E WITH TILDE + +01EBE +LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE + +01EBF +LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE + +01EC0 +LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE + +01EC1 +LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE + +01EC2 +LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE + +01EC3 +LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE + +01EC4 +LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE + +01EC5 +LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE + +01EC6 +LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW + +01EC7 +LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW + +01EC8 +LATIN CAPITAL LETTER I WITH HOOK ABOVE + +01EC9 +LATIN SMALL LETTER I WITH HOOK ABOVE + +01ECA +LATIN CAPITAL LETTER I WITH DOT BELOW + +01ECB +LATIN SMALL LETTER I WITH DOT BELOW + +01ECC +LATIN CAPITAL LETTER O WITH DOT BELOW + +01ECD +LATIN SMALL LETTER O WITH DOT BELOW + +01ECE +LATIN CAPITAL LETTER O WITH HOOK ABOVE + +01ECF +LATIN SMALL LETTER O WITH HOOK ABOVE + +01ED0 +LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE + +01ED1 +LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE + +01ED2 +LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE + +01ED3 +LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE + +01ED4 +LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE + +01ED5 +LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE + +01ED6 +LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE + +01ED7 +LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE + +01ED8 +LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW + +01ED9 +LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW + +01EDA +LATIN CAPITAL LETTER O WITH HORN AND ACUTE + +01EDB +LATIN SMALL LETTER O WITH HORN AND ACUTE + +01EDC +LATIN CAPITAL LETTER O WITH HORN AND GRAVE + +01EDD +LATIN SMALL LETTER O WITH HORN AND GRAVE + +01EDE +LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE + +01EDF +LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE + +01EE0 +LATIN CAPITAL LETTER O WITH HORN AND TILDE + +01EE1 +LATIN SMALL LETTER O WITH HORN AND TILDE + +01EE2 +LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW + +01EE3 +LATIN SMALL LETTER O WITH HORN AND DOT BELOW + +01EE4 +LATIN CAPITAL LETTER U WITH DOT BELOW + +01EE5 +LATIN SMALL LETTER U WITH DOT BELOW + +01EE6 +LATIN CAPITAL LETTER U WITH HOOK ABOVE + +01EE7 +LATIN SMALL LETTER U WITH HOOK ABOVE + +01EE8 +LATIN CAPITAL LETTER U WITH HORN AND ACUTE + +01EE9 +LATIN SMALL LETTER U WITH HORN AND ACUTE + +01EEA +LATIN CAPITAL LETTER U WITH HORN AND GRAVE + +01EEB +LATIN SMALL LETTER U WITH HORN AND GRAVE + +01EEC +LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE + +01EED +LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE + +01EEE +LATIN CAPITAL LETTER U WITH HORN AND TILDE + +01EEF +LATIN SMALL LETTER U WITH HORN AND TILDE + +01EF0 +LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW + +01EF1 +LATIN SMALL LETTER U WITH HORN AND DOT BELOW + +01EF2 +LATIN CAPITAL LETTER Y WITH GRAVE + +01EF3 +LATIN SMALL LETTER Y WITH GRAVE + +01EF4 +LATIN CAPITAL LETTER Y WITH DOT BELOW + +01EF5 +LATIN SMALL LETTER Y WITH DOT BELOW + +01EF6 +LATIN CAPITAL LETTER Y WITH HOOK ABOVE + +01EF7 +LATIN SMALL LETTER Y WITH HOOK ABOVE + +01EF8 +LATIN CAPITAL LETTER Y WITH TILDE + +01EF9 +LATIN SMALL LETTER Y WITH TILDE + +01EFA +LATIN CAPITAL LETTER MIDDLE-WELSH LL + +01EFB +LATIN SMALL LETTER MIDDLE-WELSH LL + +01EFC +LATIN CAPITAL LETTER MIDDLE-WELSH V + +01EFD +LATIN SMALL LETTER MIDDLE-WELSH V + +01EFE +LATIN CAPITAL LETTER Y WITH LOOP + +01EFF +LATIN SMALL LETTER Y WITH LOOP + +01F00 +GREEK SMALL LETTER ALPHA WITH PSILI + +01F01 +GREEK SMALL LETTER ALPHA WITH DASIA + +01F02 +GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA + +01F03 +GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA + +01F04 +GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA + +01F05 +GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA + +01F06 +GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI + +01F07 +GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI + +01F08 +GREEK CAPITAL LETTER ALPHA WITH PSILI + +01F09 +GREEK CAPITAL LETTER ALPHA WITH DASIA + +01F0A +GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA + +01F0B +GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA + +01F0C +GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA + +01F0D +GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA + +01F0E +GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI + +01F0F +GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI + +01F10 +GREEK SMALL LETTER EPSILON WITH PSILI + +01F11 +GREEK SMALL LETTER EPSILON WITH DASIA + +01F12 +GREEK SMALL LETTER EPSILON WITH PSILI AND VARIA + +01F13 +GREEK SMALL LETTER EPSILON WITH DASIA AND VARIA + +01F14 +GREEK SMALL LETTER EPSILON WITH PSILI AND OXIA + +01F15 +GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA + +01F18 +GREEK CAPITAL LETTER EPSILON WITH PSILI + +01F19 +GREEK CAPITAL LETTER EPSILON WITH DASIA + +01F1A +GREEK CAPITAL LETTER EPSILON WITH PSILI AND VARIA + +01F1B +GREEK CAPITAL LETTER EPSILON WITH DASIA AND VARIA + +01F1C +GREEK CAPITAL LETTER EPSILON WITH PSILI AND OXIA + +01F1D +GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA + +01F20 +GREEK SMALL LETTER ETA WITH PSILI + +01F21 +GREEK SMALL LETTER ETA WITH DASIA + +01F22 +GREEK SMALL LETTER ETA WITH PSILI AND VARIA + +01F23 +GREEK SMALL LETTER ETA WITH DASIA AND VARIA + +01F24 +GREEK SMALL LETTER ETA WITH PSILI AND OXIA + +01F25 +GREEK SMALL LETTER ETA WITH DASIA AND OXIA + +01F26 +GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI + +01F27 +GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI + +01F28 +GREEK CAPITAL LETTER ETA WITH PSILI + +01F29 +GREEK CAPITAL LETTER ETA WITH DASIA + +01F2A +GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA + +01F2B +GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA + +01F2C +GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA + +01F2D +GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA + +01F2E +GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI + +01F2F +GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI + +01F30 +GREEK SMALL LETTER IOTA WITH PSILI + +01F31 +GREEK SMALL LETTER IOTA WITH DASIA + +01F32 +GREEK SMALL LETTER IOTA WITH PSILI AND VARIA + +01F33 +GREEK SMALL LETTER IOTA WITH DASIA AND VARIA + +01F34 +GREEK SMALL LETTER IOTA WITH PSILI AND OXIA + +01F35 +GREEK SMALL LETTER IOTA WITH DASIA AND OXIA + +01F36 +GREEK SMALL LETTER IOTA WITH PSILI AND PERISPOMENI + +01F37 +GREEK SMALL LETTER IOTA WITH DASIA AND PERISPOMENI + +01F38 +GREEK CAPITAL LETTER IOTA WITH PSILI + +01F39 +GREEK CAPITAL LETTER IOTA WITH DASIA + +01F3A +GREEK CAPITAL LETTER IOTA WITH PSILI AND VARIA + +01F3B +GREEK CAPITAL LETTER IOTA WITH DASIA AND VARIA + +01F3C +GREEK CAPITAL LETTER IOTA WITH PSILI AND OXIA + +01F3D +GREEK CAPITAL LETTER IOTA WITH DASIA AND OXIA + +01F3E +GREEK CAPITAL LETTER IOTA WITH PSILI AND PERISPOMENI + +01F3F +GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI + +01F40 +GREEK SMALL LETTER OMICRON WITH PSILI + +01F41 +GREEK SMALL LETTER OMICRON WITH DASIA + +01F42 +GREEK SMALL LETTER OMICRON WITH PSILI AND VARIA + +01F43 +GREEK SMALL LETTER OMICRON WITH DASIA AND VARIA + +01F44 +GREEK SMALL LETTER OMICRON WITH PSILI AND OXIA + +01F45 +GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA + +01F48 +GREEK CAPITAL LETTER OMICRON WITH PSILI + +01F49 +GREEK CAPITAL LETTER OMICRON WITH DASIA + +01F4A +GREEK CAPITAL LETTER OMICRON WITH PSILI AND VARIA + +01F4B +GREEK CAPITAL LETTER OMICRON WITH DASIA AND VARIA + +01F4C +GREEK CAPITAL LETTER OMICRON WITH PSILI AND OXIA + +01F4D +GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA + +01F50 +GREEK SMALL LETTER UPSILON WITH PSILI + +01F51 +GREEK SMALL LETTER UPSILON WITH DASIA + +01F52 +GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA + +01F53 +GREEK SMALL LETTER UPSILON WITH DASIA AND VARIA + +01F54 +GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA + +01F55 +GREEK SMALL LETTER UPSILON WITH DASIA AND OXIA + +01F56 +GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI + +01F57 +GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI + +01F59 +GREEK CAPITAL LETTER UPSILON WITH DASIA + +01F5B +GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA + +01F5D +GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA + +01F5F +GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI + +01F60 +GREEK SMALL LETTER OMEGA WITH PSILI + +01F61 +GREEK SMALL LETTER OMEGA WITH DASIA + +01F62 +GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA + +01F63 +GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA + +01F64 +GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA + +01F65 +GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA + +01F66 +GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI + +01F67 +GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI + +01F68 +GREEK CAPITAL LETTER OMEGA WITH PSILI + +01F69 +GREEK CAPITAL LETTER OMEGA WITH DASIA + +01F6A +GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA + +01F6B +GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA + +01F6C +GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA + +01F6D +GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA + +01F6E +GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI + +01F6F +GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI + +01F70 +GREEK SMALL LETTER ALPHA WITH VARIA + +01F71 +GREEK SMALL LETTER ALPHA WITH OXIA + +01F72 +GREEK SMALL LETTER EPSILON WITH VARIA + +01F73 +GREEK SMALL LETTER EPSILON WITH OXIA + +01F74 +GREEK SMALL LETTER ETA WITH VARIA + +01F75 +GREEK SMALL LETTER ETA WITH OXIA + +01F76 +GREEK SMALL LETTER IOTA WITH VARIA + +01F77 +GREEK SMALL LETTER IOTA WITH OXIA + +01F78 +GREEK SMALL LETTER OMICRON WITH VARIA + +01F79 +GREEK SMALL LETTER OMICRON WITH OXIA + +01F7A +GREEK SMALL LETTER UPSILON WITH VARIA + +01F7B +GREEK SMALL LETTER UPSILON WITH OXIA + +01F7C +GREEK SMALL LETTER OMEGA WITH VARIA + +01F7D +GREEK SMALL LETTER OMEGA WITH OXIA + +01F80 +GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI + +01F81 +GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI + +01F82 +GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI + +01F83 +GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI + +01F84 +GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI + +01F85 +GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI + +01F86 +GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI + +01F87 +GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI + +01F88 +GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI + +01F89 +GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI + +01F8A +GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI + +01F8B +GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI + +01F8C +GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI + +01F8D +GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI + +01F8E +GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI + +01F8F +GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI + +01F90 +GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI + +01F91 +GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI + +01F92 +GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI + +01F93 +GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI + +01F94 +GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI + +01F95 +GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI + +01F96 +GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI + +01F97 +GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI + +01F98 +GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI + +01F99 +GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI + +01F9A +GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI + +01F9B +GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI + +01F9C +GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI + +01F9D +GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI + +01F9E +GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI + +01F9F +GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI + +01FA0 +GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI + +01FA1 +GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI + +01FA2 +GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI + +01FA3 +GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI + +01FA4 +GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI + +01FA5 +GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI + +01FA6 +GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI + +01FA7 +GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI + +01FA8 +GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI + +01FA9 +GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI + +01FAA +GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI + +01FAB +GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI + +01FAC +GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI + +01FAD +GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI + +01FAE +GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI + +01FAF +GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI + +01FB0 +GREEK SMALL LETTER ALPHA WITH VRACHY + +01FB1 +GREEK SMALL LETTER ALPHA WITH MACRON + +01FB2 +GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI + +01FB3 +GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI + +01FB4 +GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI + +01FB6 +GREEK SMALL LETTER ALPHA WITH PERISPOMENI + +01FB7 +GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI + +01FB8 +GREEK CAPITAL LETTER ALPHA WITH VRACHY + +01FB9 +GREEK CAPITAL LETTER ALPHA WITH MACRON + +01FBA +GREEK CAPITAL LETTER ALPHA WITH VARIA + +01FBB +GREEK CAPITAL LETTER ALPHA WITH OXIA + +01FBC +GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI + +01FBD +GREEK KORONIS + +01FBE +GREEK PROSGEGRAMMENI + +01FBF +GREEK PSILI + +01FC0 +GREEK PERISPOMENI + +01FC1 +GREEK DIALYTIKA AND PERISPOMENI + +01FC2 +GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI + +01FC3 +GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI + +01FC4 +GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI + +01FC6 +GREEK SMALL LETTER ETA WITH PERISPOMENI + +01FC7 +GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI + +01FC8 +GREEK CAPITAL LETTER EPSILON WITH VARIA + +01FC9 +GREEK CAPITAL LETTER EPSILON WITH OXIA + +01FCA +GREEK CAPITAL LETTER ETA WITH VARIA + +01FCB +GREEK CAPITAL LETTER ETA WITH OXIA + +01FCC +GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI + +01FCD +GREEK PSILI AND VARIA + +01FCE +GREEK PSILI AND OXIA + +01FCF +GREEK PSILI AND PERISPOMENI + +01FD0 +GREEK SMALL LETTER IOTA WITH VRACHY + +01FD1 +GREEK SMALL LETTER IOTA WITH MACRON + +01FD2 +GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA + +01FD3 +GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA + +01FD6 +GREEK SMALL LETTER IOTA WITH PERISPOMENI + +01FD7 +GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI + +01FD8 +GREEK CAPITAL LETTER IOTA WITH VRACHY + +01FD9 +GREEK CAPITAL LETTER IOTA WITH MACRON + +01FDA +GREEK CAPITAL LETTER IOTA WITH VARIA + +01FDB +GREEK CAPITAL LETTER IOTA WITH OXIA + +01FDD +GREEK DASIA AND VARIA + +01FDE +GREEK DASIA AND OXIA + +01FDF +GREEK DASIA AND PERISPOMENI + +01FE0 +GREEK SMALL LETTER UPSILON WITH VRACHY + +01FE1 +GREEK SMALL LETTER UPSILON WITH MACRON + +01FE2 +GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA + +01FE3 +GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA + +01FE4 +GREEK SMALL LETTER RHO WITH PSILI + +01FE5 +GREEK SMALL LETTER RHO WITH DASIA + +01FE6 +GREEK SMALL LETTER UPSILON WITH PERISPOMENI + +01FE7 +GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI + +01FE8 +GREEK CAPITAL LETTER UPSILON WITH VRACHY + +01FE9 +GREEK CAPITAL LETTER UPSILON WITH MACRON + +01FEA +GREEK CAPITAL LETTER UPSILON WITH VARIA + +01FEB +GREEK CAPITAL LETTER UPSILON WITH OXIA + +01FEC +GREEK CAPITAL LETTER RHO WITH DASIA + +01FED +GREEK DIALYTIKA AND VARIA + +01FEE +GREEK DIALYTIKA AND OXIA + +01FEF +GREEK VARIA + +01FF2 +GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI + +01FF3 +GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI + +01FF4 +GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI + +01FF6 +GREEK SMALL LETTER OMEGA WITH PERISPOMENI + +01FF7 +GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI + +01FF8 +GREEK CAPITAL LETTER OMICRON WITH VARIA + +01FF9 +GREEK CAPITAL LETTER OMICRON WITH OXIA + +01FFA +GREEK CAPITAL LETTER OMEGA WITH VARIA + +01FFB +GREEK CAPITAL LETTER OMEGA WITH OXIA + +01FFC +GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI + +01FFD +GREEK OXIA + +01FFE +GREEK DASIA + +02000 +EN QUAD + +02001 +EM QUAD + +02002 +EN SPACE + +02003 +EM SPACE + +02004 +THREE-PER-EM SPACE + +02005 +FOUR-PER-EM SPACE + +02006 +SIX-PER-EM SPACE + +02007 +FIGURE SPACE + +02008 +PUNCTUATION SPACE + +02009 +THIN SPACE + +0200A +HAIR SPACE + +0200B +ZERO WIDTH SPACE + +0200B +ZWSP + +0200C +ZERO WIDTH NON-JOINER + +0200C +ZWNJ + +0200D +ZERO WIDTH JOINER + +0200D +ZWJ + +0200E +LEFT-TO-RIGHT MARK + +0200E +LRM + +0200F +RIGHT-TO-LEFT MARK + +0200F +RLM + +02010 +HYPHEN + +02011 +NON-BREAKING HYPHEN + +02012 +FIGURE DASH + +02013 +EN DASH + +02014 +EM DASH + +02015 +HORIZONTAL BAR + +02016 +DOUBLE VERTICAL LINE + +02017 +DOUBLE LOW LINE + +02018 +LEFT SINGLE QUOTATION MARK + +02019 +RIGHT SINGLE QUOTATION MARK + +0201A +SINGLE LOW-9 QUOTATION MARK + +0201B +SINGLE HIGH-REVERSED-9 QUOTATION MARK + +0201C +LEFT DOUBLE QUOTATION MARK + +0201D +RIGHT DOUBLE QUOTATION MARK + +0201E +DOUBLE LOW-9 QUOTATION MARK + +0201F +DOUBLE HIGH-REVERSED-9 QUOTATION MARK + +02020 +DAGGER + +02021 +DOUBLE DAGGER + +02022 +BULLET + +02023 +TRIANGULAR BULLET + +02024 +ONE DOT LEADER + +02025 +TWO DOT LEADER + +02026 +HORIZONTAL ELLIPSIS + +02027 +HYPHENATION POINT + +02028 +LINE SEPARATOR + +02029 +PARAGRAPH SEPARATOR + +0202A +LEFT-TO-RIGHT EMBEDDING + +0202A +LRE + +0202B +RIGHT-TO-LEFT EMBEDDING + +0202B +RLE + +0202C +POP DIRECTIONAL FORMATTING + +0202C +PDF + +0202D +LEFT-TO-RIGHT OVERRIDE + +0202D +LRO + +0202E +RIGHT-TO-LEFT OVERRIDE + +0202E +RLO + +0202F +NARROW NO-BREAK SPACE + +0202F +NNBSP + +02030 +PER MILLE SIGN + +02031 +PER TEN THOUSAND SIGN + +02032 +PRIME + +02033 +DOUBLE PRIME + +02034 +TRIPLE PRIME + +02035 +REVERSED PRIME + +02036 +REVERSED DOUBLE PRIME + +02037 +REVERSED TRIPLE PRIME + +02038 +CARET + +02039 +SINGLE LEFT-POINTING ANGLE QUOTATION MARK + +0203A +SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + +0203B +REFERENCE MARK + +0203C +DOUBLE EXCLAMATION MARK + +0203D +INTERROBANG + +0203E +OVERLINE + +0203F +UNDERTIE + +02040 +CHARACTER TIE + +02041 +CARET INSERTION POINT + +02042 +ASTERISM + +02043 +HYPHEN BULLET + +02044 +FRACTION SLASH + +02045 +LEFT SQUARE BRACKET WITH QUILL + +02046 +RIGHT SQUARE BRACKET WITH QUILL + +02047 +DOUBLE QUESTION MARK + +02048 +QUESTION EXCLAMATION MARK + +02049 +EXCLAMATION QUESTION MARK + +0204A +TIRONIAN SIGN ET + +0204B +REVERSED PILCROW SIGN + +0204C +BLACK LEFTWARDS BULLET + +0204D +BLACK RIGHTWARDS BULLET + +0204E +LOW ASTERISK + +0204F +REVERSED SEMICOLON + +02050 +CLOSE UP + +02051 +TWO ASTERISKS ALIGNED VERTICALLY + +02052 +COMMERCIAL MINUS SIGN + +02053 +SWUNG DASH + +02054 +INVERTED UNDERTIE + +02055 +FLOWER PUNCTUATION MARK + +02056 +THREE DOT PUNCTUATION + +02057 +QUADRUPLE PRIME + +02058 +FOUR DOT PUNCTUATION + +02059 +FIVE DOT PUNCTUATION + +0205A +TWO DOT PUNCTUATION + +0205B +FOUR DOT MARK + +0205C +DOTTED CROSS + +0205D +TRICOLON + +0205E +VERTICAL FOUR DOTS + +0205F +MEDIUM MATHEMATICAL SPACE + +0205F +MMSP + +02060 +WORD JOINER + +02060 +WJ + +02061 +FUNCTION APPLICATION + +02062 +INVISIBLE TIMES + +02063 +INVISIBLE SEPARATOR + +02064 +INVISIBLE PLUS + +02066 +LEFT-TO-RIGHT ISOLATE + +02066 +LRI + +02067 +RIGHT-TO-LEFT ISOLATE + +02067 +RLI + +02068 +FIRST STRONG ISOLATE + +02068 +FSI + +02069 +POP DIRECTIONAL ISOLATE + +02069 +PDI + +0206A +INHIBIT SYMMETRIC SWAPPING + +0206B +ACTIVATE SYMMETRIC SWAPPING + +0206C +INHIBIT ARABIC FORM SHAPING + +0206D +ACTIVATE ARABIC FORM SHAPING + +0206E +NATIONAL DIGIT SHAPES + +0206F +NOMINAL DIGIT SHAPES + +02070 +SUPERSCRIPT ZERO + +02071 +SUPERSCRIPT LATIN SMALL LETTER I + +02074 +SUPERSCRIPT FOUR + +02075 +SUPERSCRIPT FIVE + +02076 +SUPERSCRIPT SIX + +02077 +SUPERSCRIPT SEVEN + +02078 +SUPERSCRIPT EIGHT + +02079 +SUPERSCRIPT NINE + +0207A +SUPERSCRIPT PLUS SIGN + +0207B +SUPERSCRIPT MINUS + +0207C +SUPERSCRIPT EQUALS SIGN + +0207D +SUPERSCRIPT LEFT PARENTHESIS + +0207E +SUPERSCRIPT RIGHT PARENTHESIS + +0207F +SUPERSCRIPT LATIN SMALL LETTER N + +02080 +SUBSCRIPT ZERO + +02081 +SUBSCRIPT ONE + +02082 +SUBSCRIPT TWO + +02083 +SUBSCRIPT THREE + +02084 +SUBSCRIPT FOUR + +02085 +SUBSCRIPT FIVE + +02086 +SUBSCRIPT SIX + +02087 +SUBSCRIPT SEVEN + +02088 +SUBSCRIPT EIGHT + +02089 +SUBSCRIPT NINE + +0208A +SUBSCRIPT PLUS SIGN + +0208B +SUBSCRIPT MINUS + +0208C +SUBSCRIPT EQUALS SIGN + +0208D +SUBSCRIPT LEFT PARENTHESIS + +0208E +SUBSCRIPT RIGHT PARENTHESIS + +02090 +LATIN SUBSCRIPT SMALL LETTER A + +02091 +LATIN SUBSCRIPT SMALL LETTER E + +02092 +LATIN SUBSCRIPT SMALL LETTER O + +02093 +LATIN SUBSCRIPT SMALL LETTER X + +02094 +LATIN SUBSCRIPT SMALL LETTER SCHWA + +02095 +LATIN SUBSCRIPT SMALL LETTER H + +02096 +LATIN SUBSCRIPT SMALL LETTER K + +02097 +LATIN SUBSCRIPT SMALL LETTER L + +02098 +LATIN SUBSCRIPT SMALL LETTER M + +02099 +LATIN SUBSCRIPT SMALL LETTER N + +0209A +LATIN SUBSCRIPT SMALL LETTER P + +0209B +LATIN SUBSCRIPT SMALL LETTER S + +0209C +LATIN SUBSCRIPT SMALL LETTER T + +020A0 +EURO-CURRENCY SIGN + +020A1 +COLON SIGN + +020A2 +CRUZEIRO SIGN + +020A3 +FRENCH FRANC SIGN + +020A4 +LIRA SIGN + +020A5 +MILL SIGN + +020A6 +NAIRA SIGN + +020A7 +PESETA SIGN + +020A8 +RUPEE SIGN + +020A9 +WON SIGN + +020AA +NEW SHEQEL SIGN + +020AB +DONG SIGN + +020AC +EURO SIGN + +020AD +KIP SIGN + +020AE +TUGRIK SIGN + +020AF +DRACHMA SIGN + +020B0 +GERMAN PENNY SIGN + +020B1 +PESO SIGN + +020B2 +GUARANI SIGN + +020B3 +AUSTRAL SIGN + +020B4 +HRYVNIA SIGN + +020B5 +CEDI SIGN + +020B6 +LIVRE TOURNOIS SIGN + +020B7 +SPESMILO SIGN + +020B8 +TENGE SIGN + +020B9 +INDIAN RUPEE SIGN + +020BA +TURKISH LIRA SIGN + +020BB +NORDIC MARK SIGN + +020BC +MANAT SIGN + +020BD +RUBLE SIGN + +020BE +LARI SIGN + +020BF +BITCOIN SIGN + +020C0 +SOM SIGN + +020C1 +SAUDI RIYAL SIGN + +020D0 +COMBINING LEFT HARPOON ABOVE + +020D1 +COMBINING RIGHT HARPOON ABOVE + +020D2 +COMBINING LONG VERTICAL LINE OVERLAY + +020D3 +COMBINING SHORT VERTICAL LINE OVERLAY + +020D4 +COMBINING ANTICLOCKWISE ARROW ABOVE + +020D5 +COMBINING CLOCKWISE ARROW ABOVE + +020D6 +COMBINING LEFT ARROW ABOVE + +020D7 +COMBINING RIGHT ARROW ABOVE + +020D8 +COMBINING RING OVERLAY + +020D9 +COMBINING CLOCKWISE RING OVERLAY + +020DA +COMBINING ANTICLOCKWISE RING OVERLAY + +020DB +COMBINING THREE DOTS ABOVE + +020DC +COMBINING FOUR DOTS ABOVE + +020DD +COMBINING ENCLOSING CIRCLE + +020DE +COMBINING ENCLOSING SQUARE + +020DF +COMBINING ENCLOSING DIAMOND + +020E0 +COMBINING ENCLOSING CIRCLE BACKSLASH + +020E1 +COMBINING LEFT RIGHT ARROW ABOVE + +020E2 +COMBINING ENCLOSING SCREEN + +020E3 +COMBINING ENCLOSING KEYCAP + +020E4 +COMBINING ENCLOSING UPWARD POINTING TRIANGLE + +020E5 +COMBINING REVERSE SOLIDUS OVERLAY + +020E6 +COMBINING DOUBLE VERTICAL STROKE OVERLAY + +020E7 +COMBINING ANNUITY SYMBOL + +020E8 +COMBINING TRIPLE UNDERDOT + +020E9 +COMBINING WIDE BRIDGE ABOVE + +020EA +COMBINING LEFTWARDS ARROW OVERLAY + +020EB +COMBINING LONG DOUBLE SOLIDUS OVERLAY + +020EC +COMBINING RIGHTWARDS HARPOON WITH BARB DOWNWARDS + +020ED +COMBINING LEFTWARDS HARPOON WITH BARB DOWNWARDS + +020EE +COMBINING LEFT ARROW BELOW + +020EF +COMBINING RIGHT ARROW BELOW + +020F0 +COMBINING ASTERISK ABOVE + +02100 +ACCOUNT OF + +02101 +ADDRESSED TO THE SUBJECT + +02102 +DOUBLE-STRUCK CAPITAL C + +02103 +DEGREE CELSIUS + +02104 +CENTRE LINE SYMBOL + +02105 +CARE OF + +02106 +CADA UNA + +02107 +EULER CONSTANT + +02108 +SCRUPLE + +02109 +DEGREE FAHRENHEIT + +0210A +SCRIPT SMALL G + +0210B +SCRIPT CAPITAL H + +0210C +BLACK-LETTER CAPITAL H + +0210D +DOUBLE-STRUCK CAPITAL H + +0210E +PLANCK CONSTANT + +0210F +PLANCK CONSTANT OVER TWO PI + +02110 +SCRIPT CAPITAL I + +02111 +BLACK-LETTER CAPITAL I + +02112 +SCRIPT CAPITAL L + +02113 +SCRIPT SMALL L + +02114 +L B BAR SYMBOL + +02115 +DOUBLE-STRUCK CAPITAL N + +02116 +NUMERO SIGN + +02117 +SOUND RECORDING COPYRIGHT + +02118 +WEIERSTRASS ELLIPTIC FUNCTION + +02118 +SCRIPT CAPITAL P + +02119 +DOUBLE-STRUCK CAPITAL P + +0211A +DOUBLE-STRUCK CAPITAL Q + +0211B +SCRIPT CAPITAL R + +0211C +BLACK-LETTER CAPITAL R + +0211D +DOUBLE-STRUCK CAPITAL R + +0211E +PRESCRIPTION TAKE + +0211F +RESPONSE + +02120 +SERVICE MARK + +02121 +TELEPHONE SIGN + +02122 +TRADE MARK SIGN + +02123 +VERSICLE + +02124 +DOUBLE-STRUCK CAPITAL Z + +02125 +OUNCE SIGN + +02126 +OHM SIGN + +02127 +INVERTED OHM SIGN + +02128 +BLACK-LETTER CAPITAL Z + +02129 +TURNED GREEK SMALL LETTER IOTA + +0212A +KELVIN SIGN + +0212B +ANGSTROM SIGN + +0212C +SCRIPT CAPITAL B + +0212D +BLACK-LETTER CAPITAL C + +0212E +ESTIMATED SYMBOL + +0212F +SCRIPT SMALL E + +02130 +SCRIPT CAPITAL E + +02131 +SCRIPT CAPITAL F + +02132 +TURNED CAPITAL F + +02133 +SCRIPT CAPITAL M + +02134 +SCRIPT SMALL O + +02135 +ALEF SYMBOL + +02136 +BET SYMBOL + +02137 +GIMEL SYMBOL + +02138 +DALET SYMBOL + +02139 +INFORMATION SOURCE + +0213A +ROTATED CAPITAL Q + +0213B +FACSIMILE SIGN + +0213C +DOUBLE-STRUCK SMALL PI + +0213D +DOUBLE-STRUCK SMALL GAMMA + +0213E +DOUBLE-STRUCK CAPITAL GAMMA + +0213F +DOUBLE-STRUCK CAPITAL PI + +02140 +DOUBLE-STRUCK N-ARY SUMMATION + +02141 +TURNED SANS-SERIF CAPITAL G + +02142 +TURNED SANS-SERIF CAPITAL L + +02143 +REVERSED SANS-SERIF CAPITAL L + +02144 +TURNED SANS-SERIF CAPITAL Y + +02145 +DOUBLE-STRUCK ITALIC CAPITAL D + +02146 +DOUBLE-STRUCK ITALIC SMALL D + +02147 +DOUBLE-STRUCK ITALIC SMALL E + +02148 +DOUBLE-STRUCK ITALIC SMALL I + +02149 +DOUBLE-STRUCK ITALIC SMALL J + +0214A +PROPERTY LINE + +0214B +TURNED AMPERSAND + +0214C +PER SIGN + +0214D +AKTIESELSKAB + +0214E +TURNED SMALL F + +0214F +SYMBOL FOR SAMARITAN SOURCE + +02150 +VULGAR FRACTION ONE SEVENTH + +02151 +VULGAR FRACTION ONE NINTH + +02152 +VULGAR FRACTION ONE TENTH + +02153 +VULGAR FRACTION ONE THIRD + +02154 +VULGAR FRACTION TWO THIRDS + +02155 +VULGAR FRACTION ONE FIFTH + +02156 +VULGAR FRACTION TWO FIFTHS + +02157 +VULGAR FRACTION THREE FIFTHS + +02158 +VULGAR FRACTION FOUR FIFTHS + +02159 +VULGAR FRACTION ONE SIXTH + +0215A +VULGAR FRACTION FIVE SIXTHS + +0215B +VULGAR FRACTION ONE EIGHTH + +0215C +VULGAR FRACTION THREE EIGHTHS + +0215D +VULGAR FRACTION FIVE EIGHTHS + +0215E +VULGAR FRACTION SEVEN EIGHTHS + +0215F +FRACTION NUMERATOR ONE + +02160 +ROMAN NUMERAL ONE + +02161 +ROMAN NUMERAL TWO + +02162 +ROMAN NUMERAL THREE + +02163 +ROMAN NUMERAL FOUR + +02164 +ROMAN NUMERAL FIVE + +02165 +ROMAN NUMERAL SIX + +02166 +ROMAN NUMERAL SEVEN + +02167 +ROMAN NUMERAL EIGHT + +02168 +ROMAN NUMERAL NINE + +02169 +ROMAN NUMERAL TEN + +0216A +ROMAN NUMERAL ELEVEN + +0216B +ROMAN NUMERAL TWELVE + +0216C +ROMAN NUMERAL FIFTY + +0216D +ROMAN NUMERAL ONE HUNDRED + +0216E +ROMAN NUMERAL FIVE HUNDRED + +0216F +ROMAN NUMERAL ONE THOUSAND + +02170 +SMALL ROMAN NUMERAL ONE + +02171 +SMALL ROMAN NUMERAL TWO + +02172 +SMALL ROMAN NUMERAL THREE + +02173 +SMALL ROMAN NUMERAL FOUR + +02174 +SMALL ROMAN NUMERAL FIVE + +02175 +SMALL ROMAN NUMERAL SIX + +02176 +SMALL ROMAN NUMERAL SEVEN + +02177 +SMALL ROMAN NUMERAL EIGHT + +02178 +SMALL ROMAN NUMERAL NINE + +02179 +SMALL ROMAN NUMERAL TEN + +0217A +SMALL ROMAN NUMERAL ELEVEN + +0217B +SMALL ROMAN NUMERAL TWELVE + +0217C +SMALL ROMAN NUMERAL FIFTY + +0217D +SMALL ROMAN NUMERAL ONE HUNDRED + +0217E +SMALL ROMAN NUMERAL FIVE HUNDRED + +0217F +SMALL ROMAN NUMERAL ONE THOUSAND + +02180 +ROMAN NUMERAL ONE THOUSAND C D + +02181 +ROMAN NUMERAL FIVE THOUSAND + +02182 +ROMAN NUMERAL TEN THOUSAND + +02183 +ROMAN NUMERAL REVERSED ONE HUNDRED + +02184 +LATIN SMALL LETTER REVERSED C + +02185 +ROMAN NUMERAL SIX LATE FORM + +02186 +ROMAN NUMERAL FIFTY EARLY FORM + +02187 +ROMAN NUMERAL FIFTY THOUSAND + +02188 +ROMAN NUMERAL ONE HUNDRED THOUSAND + +02189 +VULGAR FRACTION ZERO THIRDS + +0218A +TURNED DIGIT TWO + +0218B +TURNED DIGIT THREE + +02190 +LEFTWARDS ARROW + +02191 +UPWARDS ARROW + +02192 +RIGHTWARDS ARROW + +02193 +DOWNWARDS ARROW + +02194 +LEFT RIGHT ARROW + +02195 +UP DOWN ARROW + +02196 +NORTH WEST ARROW + +02197 +NORTH EAST ARROW + +02198 +SOUTH EAST ARROW + +02199 +SOUTH WEST ARROW + +0219A +LEFTWARDS ARROW WITH STROKE + +0219B +RIGHTWARDS ARROW WITH STROKE + +0219C +LEFTWARDS WAVE ARROW + +0219D +RIGHTWARDS WAVE ARROW + +0219E +LEFTWARDS TWO HEADED ARROW + +0219F +UPWARDS TWO HEADED ARROW + +021A0 +RIGHTWARDS TWO HEADED ARROW + +021A1 +DOWNWARDS TWO HEADED ARROW + +021A2 +LEFTWARDS ARROW WITH TAIL + +021A3 +RIGHTWARDS ARROW WITH TAIL + +021A4 +LEFTWARDS ARROW FROM BAR + +021A5 +UPWARDS ARROW FROM BAR + +021A6 +RIGHTWARDS ARROW FROM BAR + +021A7 +DOWNWARDS ARROW FROM BAR + +021A8 +UP DOWN ARROW WITH BASE + +021A9 +LEFTWARDS ARROW WITH HOOK + +021AA +RIGHTWARDS ARROW WITH HOOK + +021AB +LEFTWARDS ARROW WITH LOOP + +021AC +RIGHTWARDS ARROW WITH LOOP + +021AD +LEFT RIGHT WAVE ARROW + +021AE +LEFT RIGHT ARROW WITH STROKE + +021AF +DOWNWARDS ZIGZAG ARROW + +021B0 +UPWARDS ARROW WITH TIP LEFTWARDS + +021B1 +UPWARDS ARROW WITH TIP RIGHTWARDS + +021B2 +DOWNWARDS ARROW WITH TIP LEFTWARDS + +021B3 +DOWNWARDS ARROW WITH TIP RIGHTWARDS + +021B4 +RIGHTWARDS ARROW WITH CORNER DOWNWARDS + +021B5 +DOWNWARDS ARROW WITH CORNER LEFTWARDS + +021B6 +ANTICLOCKWISE TOP SEMICIRCLE ARROW + +021B7 +CLOCKWISE TOP SEMICIRCLE ARROW + +021B8 +NORTH WEST ARROW TO LONG BAR + +021B9 +LEFTWARDS ARROW TO BAR OVER RIGHTWARDS ARROW TO BAR + +021BA +ANTICLOCKWISE OPEN CIRCLE ARROW + +021BB +CLOCKWISE OPEN CIRCLE ARROW + +021BC +LEFTWARDS HARPOON WITH BARB UPWARDS + +021BD +LEFTWARDS HARPOON WITH BARB DOWNWARDS + +021BE +UPWARDS HARPOON WITH BARB RIGHTWARDS + +021BF +UPWARDS HARPOON WITH BARB LEFTWARDS + +021C0 +RIGHTWARDS HARPOON WITH BARB UPWARDS + +021C1 +RIGHTWARDS HARPOON WITH BARB DOWNWARDS + +021C2 +DOWNWARDS HARPOON WITH BARB RIGHTWARDS + +021C3 +DOWNWARDS HARPOON WITH BARB LEFTWARDS + +021C4 +RIGHTWARDS ARROW OVER LEFTWARDS ARROW + +021C5 +UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW + +021C6 +LEFTWARDS ARROW OVER RIGHTWARDS ARROW + +021C7 +LEFTWARDS PAIRED ARROWS + +021C8 +UPWARDS PAIRED ARROWS + +021C9 +RIGHTWARDS PAIRED ARROWS + +021CA +DOWNWARDS PAIRED ARROWS + +021CB +LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON + +021CC +RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON + +021CD +LEFTWARDS DOUBLE ARROW WITH STROKE + +021CE +LEFT RIGHT DOUBLE ARROW WITH STROKE + +021CF +RIGHTWARDS DOUBLE ARROW WITH STROKE + +021D0 +LEFTWARDS DOUBLE ARROW + +021D1 +UPWARDS DOUBLE ARROW + +021D2 +RIGHTWARDS DOUBLE ARROW + +021D3 +DOWNWARDS DOUBLE ARROW + +021D4 +LEFT RIGHT DOUBLE ARROW + +021D5 +UP DOWN DOUBLE ARROW + +021D6 +NORTH WEST DOUBLE ARROW + +021D7 +NORTH EAST DOUBLE ARROW + +021D8 +SOUTH EAST DOUBLE ARROW + +021D9 +SOUTH WEST DOUBLE ARROW + +021DA +LEFTWARDS TRIPLE ARROW + +021DB +RIGHTWARDS TRIPLE ARROW + +021DC +LEFTWARDS SQUIGGLE ARROW + +021DD +RIGHTWARDS SQUIGGLE ARROW + +021DE +UPWARDS ARROW WITH DOUBLE STROKE + +021DF +DOWNWARDS ARROW WITH DOUBLE STROKE + +021E0 +LEFTWARDS DASHED ARROW + +021E1 +UPWARDS DASHED ARROW + +021E2 +RIGHTWARDS DASHED ARROW + +021E3 +DOWNWARDS DASHED ARROW + +021E4 +LEFTWARDS ARROW TO BAR + +021E5 +RIGHTWARDS ARROW TO BAR + +021E6 +LEFTWARDS WHITE ARROW + +021E7 +UPWARDS WHITE ARROW + +021E8 +RIGHTWARDS WHITE ARROW + +021E9 +DOWNWARDS WHITE ARROW + +021EA +UPWARDS WHITE ARROW FROM BAR + +021EB +UPWARDS WHITE ARROW ON PEDESTAL + +021EC +UPWARDS WHITE ARROW ON PEDESTAL WITH HORIZONTAL BAR + +021ED +UPWARDS WHITE ARROW ON PEDESTAL WITH VERTICAL BAR + +021EE +UPWARDS WHITE DOUBLE ARROW + +021EF +UPWARDS WHITE DOUBLE ARROW ON PEDESTAL + +021F0 +RIGHTWARDS WHITE ARROW FROM WALL + +021F1 +NORTH WEST ARROW TO CORNER + +021F2 +SOUTH EAST ARROW TO CORNER + +021F3 +UP DOWN WHITE ARROW + +021F4 +RIGHT ARROW WITH SMALL CIRCLE + +021F5 +DOWNWARDS ARROW LEFTWARDS OF UPWARDS ARROW + +021F6 +THREE RIGHTWARDS ARROWS + +021F7 +LEFTWARDS ARROW WITH VERTICAL STROKE + +021F8 +RIGHTWARDS ARROW WITH VERTICAL STROKE + +021F9 +LEFT RIGHT ARROW WITH VERTICAL STROKE + +021FA +LEFTWARDS ARROW WITH DOUBLE VERTICAL STROKE + +021FB +RIGHTWARDS ARROW WITH DOUBLE VERTICAL STROKE + +021FC +LEFT RIGHT ARROW WITH DOUBLE VERTICAL STROKE + +021FD +LEFTWARDS OPEN-HEADED ARROW + +021FE +RIGHTWARDS OPEN-HEADED ARROW + +021FF +LEFT RIGHT OPEN-HEADED ARROW + +02200 +FOR ALL + +02201 +COMPLEMENT + +02202 +PARTIAL DIFFERENTIAL + +02203 +THERE EXISTS + +02204 +THERE DOES NOT EXIST + +02205 +EMPTY SET + +02206 +INCREMENT + +02207 +NABLA + +02208 +ELEMENT OF + +02209 +NOT AN ELEMENT OF + +0220A +SMALL ELEMENT OF + +0220B +CONTAINS AS MEMBER + +0220C +DOES NOT CONTAIN AS MEMBER + +0220D +SMALL CONTAINS AS MEMBER + +0220E +END OF PROOF + +0220F +N-ARY PRODUCT + +02210 +N-ARY COPRODUCT + +02211 +N-ARY SUMMATION + +02212 +MINUS SIGN + +02213 +MINUS-OR-PLUS SIGN + +02214 +DOT PLUS + +02215 +DIVISION SLASH + +02216 +SET MINUS + +02217 +ASTERISK OPERATOR + +02218 +RING OPERATOR + +02219 +BULLET OPERATOR + +0221A +SQUARE ROOT + +0221B +CUBE ROOT + +0221C +FOURTH ROOT + +0221D +PROPORTIONAL TO + +0221E +INFINITY + +0221F +RIGHT ANGLE + +02220 +ANGLE + +02221 +MEASURED ANGLE + +02222 +SPHERICAL ANGLE + +02223 +DIVIDES + +02224 +DOES NOT DIVIDE + +02225 +PARALLEL TO + +02226 +NOT PARALLEL TO + +02227 +LOGICAL AND + +02228 +LOGICAL OR + +02229 +INTERSECTION + +0222A +UNION + +0222B +INTEGRAL + +0222C +DOUBLE INTEGRAL + +0222D +TRIPLE INTEGRAL + +0222E +CONTOUR INTEGRAL + +0222F +SURFACE INTEGRAL + +02230 +VOLUME INTEGRAL + +02231 +CLOCKWISE INTEGRAL + +02232 +CLOCKWISE CONTOUR INTEGRAL + +02233 +ANTICLOCKWISE CONTOUR INTEGRAL + +02234 +THEREFORE + +02235 +BECAUSE + +02236 +RATIO + +02237 +PROPORTION + +02238 +DOT MINUS + +02239 +EXCESS + +0223A +GEOMETRIC PROPORTION + +0223B +HOMOTHETIC + +0223C +TILDE OPERATOR + +0223D +REVERSED TILDE + +0223E +INVERTED LAZY S + +0223F +SINE WAVE + +02240 +WREATH PRODUCT + +02241 +NOT TILDE + +02242 +MINUS TILDE + +02243 +ASYMPTOTICALLY EQUAL TO + +02244 +NOT ASYMPTOTICALLY EQUAL TO + +02245 +APPROXIMATELY EQUAL TO + +02246 +APPROXIMATELY BUT NOT ACTUALLY EQUAL TO + +02247 +NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO + +02248 +ALMOST EQUAL TO + +02249 +NOT ALMOST EQUAL TO + +0224A +ALMOST EQUAL OR EQUAL TO + +0224B +TRIPLE TILDE + +0224C +ALL EQUAL TO + +0224D +EQUIVALENT TO + +0224E +GEOMETRICALLY EQUIVALENT TO + +0224F +DIFFERENCE BETWEEN + +02250 +APPROACHES THE LIMIT + +02251 +GEOMETRICALLY EQUAL TO + +02252 +APPROXIMATELY EQUAL TO OR THE IMAGE OF + +02253 +IMAGE OF OR APPROXIMATELY EQUAL TO + +02254 +COLON EQUALS + +02255 +EQUALS COLON + +02256 +RING IN EQUAL TO + +02257 +RING EQUAL TO + +02258 +CORRESPONDS TO + +02259 +ESTIMATES + +0225A +EQUIANGULAR TO + +0225B +STAR EQUALS + +0225C +DELTA EQUAL TO + +0225D +EQUAL TO BY DEFINITION + +0225E +MEASURED BY + +0225F +QUESTIONED EQUAL TO + +02260 +NOT EQUAL TO + +02261 +IDENTICAL TO + +02262 +NOT IDENTICAL TO + +02263 +STRICTLY EQUIVALENT TO + +02264 +LESS-THAN OR EQUAL TO + +02265 +GREATER-THAN OR EQUAL TO + +02266 +LESS-THAN OVER EQUAL TO + +02267 +GREATER-THAN OVER EQUAL TO + +02268 +LESS-THAN BUT NOT EQUAL TO + +02269 +GREATER-THAN BUT NOT EQUAL TO + +0226A +MUCH LESS-THAN + +0226B +MUCH GREATER-THAN + +0226C +BETWEEN + +0226D +NOT EQUIVALENT TO + +0226E +NOT LESS-THAN + +0226F +NOT GREATER-THAN + +02270 +NEITHER LESS-THAN NOR EQUAL TO + +02271 +NEITHER GREATER-THAN NOR EQUAL TO + +02272 +LESS-THAN OR EQUIVALENT TO + +02273 +GREATER-THAN OR EQUIVALENT TO + +02274 +NEITHER LESS-THAN NOR EQUIVALENT TO + +02275 +NEITHER GREATER-THAN NOR EQUIVALENT TO + +02276 +LESS-THAN OR GREATER-THAN + +02277 +GREATER-THAN OR LESS-THAN + +02278 +NEITHER LESS-THAN NOR GREATER-THAN + +02279 +NEITHER GREATER-THAN NOR LESS-THAN + +0227A +PRECEDES + +0227B +SUCCEEDS + +0227C +PRECEDES OR EQUAL TO + +0227D +SUCCEEDS OR EQUAL TO + +0227E +PRECEDES OR EQUIVALENT TO + +0227F +SUCCEEDS OR EQUIVALENT TO + +02280 +DOES NOT PRECEDE + +02281 +DOES NOT SUCCEED + +02282 +SUBSET OF + +02283 +SUPERSET OF + +02284 +NOT A SUBSET OF + +02285 +NOT A SUPERSET OF + +02286 +SUBSET OF OR EQUAL TO + +02287 +SUPERSET OF OR EQUAL TO + +02288 +NEITHER A SUBSET OF NOR EQUAL TO + +02289 +NEITHER A SUPERSET OF NOR EQUAL TO + +0228A +SUBSET OF WITH NOT EQUAL TO + +0228B +SUPERSET OF WITH NOT EQUAL TO + +0228C +MULTISET + +0228D +MULTISET MULTIPLICATION + +0228E +MULTISET UNION + +0228F +SQUARE IMAGE OF + +02290 +SQUARE ORIGINAL OF + +02291 +SQUARE IMAGE OF OR EQUAL TO + +02292 +SQUARE ORIGINAL OF OR EQUAL TO + +02293 +SQUARE CAP + +02294 +SQUARE CUP + +02295 +CIRCLED PLUS + +02296 +CIRCLED MINUS + +02297 +CIRCLED TIMES + +02298 +CIRCLED DIVISION SLASH + +02299 +CIRCLED DOT OPERATOR + +0229A +CIRCLED RING OPERATOR + +0229B +CIRCLED ASTERISK OPERATOR + +0229C +CIRCLED EQUALS + +0229D +CIRCLED DASH + +0229E +SQUARED PLUS + +0229F +SQUARED MINUS + +022A0 +SQUARED TIMES + +022A1 +SQUARED DOT OPERATOR + +022A2 +RIGHT TACK + +022A3 +LEFT TACK + +022A4 +DOWN TACK + +022A5 +UP TACK + +022A6 +ASSERTION + +022A7 +MODELS + +022A8 +TRUE + +022A9 +FORCES + +022AA +TRIPLE VERTICAL BAR RIGHT TURNSTILE + +022AB +DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE + +022AC +DOES NOT PROVE + +022AD +NOT TRUE + +022AE +DOES NOT FORCE + +022AF +NEGATED DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE + +022B0 +PRECEDES UNDER RELATION + +022B1 +SUCCEEDS UNDER RELATION + +022B2 +NORMAL SUBGROUP OF + +022B3 +CONTAINS AS NORMAL SUBGROUP + +022B4 +NORMAL SUBGROUP OF OR EQUAL TO + +022B5 +CONTAINS AS NORMAL SUBGROUP OR EQUAL TO + +022B6 +ORIGINAL OF + +022B7 +IMAGE OF + +022B8 +MULTIMAP + +022B9 +HERMITIAN CONJUGATE MATRIX + +022BA +INTERCALATE + +022BB +XOR + +022BC +NAND + +022BD +NOR + +022BE +RIGHT ANGLE WITH ARC + +022BF +RIGHT TRIANGLE + +022C0 +N-ARY LOGICAL AND + +022C1 +N-ARY LOGICAL OR + +022C2 +N-ARY INTERSECTION + +022C3 +N-ARY UNION + +022C4 +DIAMOND OPERATOR + +022C5 +DOT OPERATOR + +022C6 +STAR OPERATOR + +022C7 +DIVISION TIMES + +022C8 +BOWTIE + +022C9 +LEFT NORMAL FACTOR SEMIDIRECT PRODUCT + +022CA +RIGHT NORMAL FACTOR SEMIDIRECT PRODUCT + +022CB +LEFT SEMIDIRECT PRODUCT + +022CC +RIGHT SEMIDIRECT PRODUCT + +022CD +REVERSED TILDE EQUALS + +022CE +CURLY LOGICAL OR + +022CF +CURLY LOGICAL AND + +022D0 +DOUBLE SUBSET + +022D1 +DOUBLE SUPERSET + +022D2 +DOUBLE INTERSECTION + +022D3 +DOUBLE UNION + +022D4 +PITCHFORK + +022D5 +EQUAL AND PARALLEL TO + +022D6 +LESS-THAN WITH DOT + +022D7 +GREATER-THAN WITH DOT + +022D8 +VERY MUCH LESS-THAN + +022D9 +VERY MUCH GREATER-THAN + +022DA +LESS-THAN EQUAL TO OR GREATER-THAN + +022DB +GREATER-THAN EQUAL TO OR LESS-THAN + +022DC +EQUAL TO OR LESS-THAN + +022DD +EQUAL TO OR GREATER-THAN + +022DE +EQUAL TO OR PRECEDES + +022DF +EQUAL TO OR SUCCEEDS + +022E0 +DOES NOT PRECEDE OR EQUAL + +022E1 +DOES NOT SUCCEED OR EQUAL + +022E2 +NOT SQUARE IMAGE OF OR EQUAL TO + +022E3 +NOT SQUARE ORIGINAL OF OR EQUAL TO + +022E4 +SQUARE IMAGE OF OR NOT EQUAL TO + +022E5 +SQUARE ORIGINAL OF OR NOT EQUAL TO + +022E6 +LESS-THAN BUT NOT EQUIVALENT TO + +022E7 +GREATER-THAN BUT NOT EQUIVALENT TO + +022E8 +PRECEDES BUT NOT EQUIVALENT TO + +022E9 +SUCCEEDS BUT NOT EQUIVALENT TO + +022EA +NOT NORMAL SUBGROUP OF + +022EB +DOES NOT CONTAIN AS NORMAL SUBGROUP + +022EC +NOT NORMAL SUBGROUP OF OR EQUAL TO + +022ED +DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL + +022EE +VERTICAL ELLIPSIS + +022EF +MIDLINE HORIZONTAL ELLIPSIS + +022F0 +UP RIGHT DIAGONAL ELLIPSIS + +022F1 +DOWN RIGHT DIAGONAL ELLIPSIS + +022F2 +ELEMENT OF WITH LONG HORIZONTAL STROKE + +022F3 +ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE + +022F4 +SMALL ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE + +022F5 +ELEMENT OF WITH DOT ABOVE + +022F6 +ELEMENT OF WITH OVERBAR + +022F7 +SMALL ELEMENT OF WITH OVERBAR + +022F8 +ELEMENT OF WITH UNDERBAR + +022F9 +ELEMENT OF WITH TWO HORIZONTAL STROKES + +022FA +CONTAINS WITH LONG HORIZONTAL STROKE + +022FB +CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE + +022FC +SMALL CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE + +022FD +CONTAINS WITH OVERBAR + +022FE +SMALL CONTAINS WITH OVERBAR + +022FF +Z NOTATION BAG MEMBERSHIP + +02300 +DIAMETER SIGN + +02301 +ELECTRIC ARROW + +02302 +HOUSE + +02303 +UP ARROWHEAD + +02304 +DOWN ARROWHEAD + +02305 +PROJECTIVE + +02306 +PERSPECTIVE + +02307 +WAVY LINE + +02308 +LEFT CEILING + +02309 +RIGHT CEILING + +0230A +LEFT FLOOR + +0230B +RIGHT FLOOR + +0230C +BOTTOM RIGHT CROP + +0230D +BOTTOM LEFT CROP + +0230E +TOP RIGHT CROP + +0230F +TOP LEFT CROP + +02310 +REVERSED NOT SIGN + +02311 +SQUARE LOZENGE + +02312 +ARC + +02313 +SEGMENT + +02314 +SECTOR + +02315 +TELEPHONE RECORDER + +02316 +POSITION INDICATOR + +02317 +VIEWDATA SQUARE + +02318 +PLACE OF INTEREST SIGN + +02319 +TURNED NOT SIGN + +0231A +WATCH + +0231B +HOURGLASS + +0231C +TOP LEFT CORNER + +0231D +TOP RIGHT CORNER + +0231E +BOTTOM LEFT CORNER + +0231F +BOTTOM RIGHT CORNER + +02320 +TOP HALF INTEGRAL + +02321 +BOTTOM HALF INTEGRAL + +02322 +FROWN + +02323 +SMILE + +02324 +UP ARROWHEAD BETWEEN TWO HORIZONTAL BARS + +02325 +OPTION KEY + +02326 +ERASE TO THE RIGHT + +02327 +X IN A RECTANGLE BOX + +02328 +KEYBOARD + +02329 +LEFT-POINTING ANGLE BRACKET + +0232A +RIGHT-POINTING ANGLE BRACKET + +0232B +ERASE TO THE LEFT + +0232C +BENZENE RING + +0232D +CYLINDRICITY + +0232E +ALL AROUND-PROFILE + +0232F +SYMMETRY + +02330 +TOTAL RUNOUT + +02331 +DIMENSION ORIGIN + +02332 +CONICAL TAPER + +02333 +SLOPE + +02334 +COUNTERBORE + +02335 +COUNTERSINK + +02336 +APL FUNCTIONAL SYMBOL I-BEAM + +02337 +APL FUNCTIONAL SYMBOL SQUISH QUAD + +02338 +APL FUNCTIONAL SYMBOL QUAD EQUAL + +02339 +APL FUNCTIONAL SYMBOL QUAD DIVIDE + +0233A +APL FUNCTIONAL SYMBOL QUAD DIAMOND + +0233B +APL FUNCTIONAL SYMBOL QUAD JOT + +0233C +APL FUNCTIONAL SYMBOL QUAD CIRCLE + +0233D +APL FUNCTIONAL SYMBOL CIRCLE STILE + +0233E +APL FUNCTIONAL SYMBOL CIRCLE JOT + +0233F +APL FUNCTIONAL SYMBOL SLASH BAR + +02340 +APL FUNCTIONAL SYMBOL BACKSLASH BAR + +02341 +APL FUNCTIONAL SYMBOL QUAD SLASH + +02342 +APL FUNCTIONAL SYMBOL QUAD BACKSLASH + +02343 +APL FUNCTIONAL SYMBOL QUAD LESS-THAN + +02344 +APL FUNCTIONAL SYMBOL QUAD GREATER-THAN + +02345 +APL FUNCTIONAL SYMBOL LEFTWARDS VANE + +02346 +APL FUNCTIONAL SYMBOL RIGHTWARDS VANE + +02347 +APL FUNCTIONAL SYMBOL QUAD LEFTWARDS ARROW + +02348 +APL FUNCTIONAL SYMBOL QUAD RIGHTWARDS ARROW + +02349 +APL FUNCTIONAL SYMBOL CIRCLE BACKSLASH + +0234A +APL FUNCTIONAL SYMBOL DOWN TACK UNDERBAR + +0234B +APL FUNCTIONAL SYMBOL DELTA STILE + +0234C +APL FUNCTIONAL SYMBOL QUAD DOWN CARET + +0234D +APL FUNCTIONAL SYMBOL QUAD DELTA + +0234E +APL FUNCTIONAL SYMBOL DOWN TACK JOT + +0234F +APL FUNCTIONAL SYMBOL UPWARDS VANE + +02350 +APL FUNCTIONAL SYMBOL QUAD UPWARDS ARROW + +02351 +APL FUNCTIONAL SYMBOL UP TACK OVERBAR + +02352 +APL FUNCTIONAL SYMBOL DEL STILE + +02353 +APL FUNCTIONAL SYMBOL QUAD UP CARET + +02354 +APL FUNCTIONAL SYMBOL QUAD DEL + +02355 +APL FUNCTIONAL SYMBOL UP TACK JOT + +02356 +APL FUNCTIONAL SYMBOL DOWNWARDS VANE + +02357 +APL FUNCTIONAL SYMBOL QUAD DOWNWARDS ARROW + +02358 +APL FUNCTIONAL SYMBOL QUOTE UNDERBAR + +02359 +APL FUNCTIONAL SYMBOL DELTA UNDERBAR + +0235A +APL FUNCTIONAL SYMBOL DIAMOND UNDERBAR + +0235B +APL FUNCTIONAL SYMBOL JOT UNDERBAR + +0235C +APL FUNCTIONAL SYMBOL CIRCLE UNDERBAR + +0235D +APL FUNCTIONAL SYMBOL UP SHOE JOT + +0235E +APL FUNCTIONAL SYMBOL QUOTE QUAD + +0235F +APL FUNCTIONAL SYMBOL CIRCLE STAR + +02360 +APL FUNCTIONAL SYMBOL QUAD COLON + +02361 +APL FUNCTIONAL SYMBOL UP TACK DIAERESIS + +02362 +APL FUNCTIONAL SYMBOL DEL DIAERESIS + +02363 +APL FUNCTIONAL SYMBOL STAR DIAERESIS + +02364 +APL FUNCTIONAL SYMBOL JOT DIAERESIS + +02365 +APL FUNCTIONAL SYMBOL CIRCLE DIAERESIS + +02366 +APL FUNCTIONAL SYMBOL DOWN SHOE STILE + +02367 +APL FUNCTIONAL SYMBOL LEFT SHOE STILE + +02368 +APL FUNCTIONAL SYMBOL TILDE DIAERESIS + +02369 +APL FUNCTIONAL SYMBOL GREATER-THAN DIAERESIS + +0236A +APL FUNCTIONAL SYMBOL COMMA BAR + +0236B +APL FUNCTIONAL SYMBOL DEL TILDE + +0236C +APL FUNCTIONAL SYMBOL ZILDE + +0236D +APL FUNCTIONAL SYMBOL STILE TILDE + +0236E +APL FUNCTIONAL SYMBOL SEMICOLON UNDERBAR + +0236F +APL FUNCTIONAL SYMBOL QUAD NOT EQUAL + +02370 +APL FUNCTIONAL SYMBOL QUAD QUESTION + +02371 +APL FUNCTIONAL SYMBOL DOWN CARET TILDE + +02372 +APL FUNCTIONAL SYMBOL UP CARET TILDE + +02373 +APL FUNCTIONAL SYMBOL IOTA + +02374 +APL FUNCTIONAL SYMBOL RHO + +02375 +APL FUNCTIONAL SYMBOL OMEGA + +02376 +APL FUNCTIONAL SYMBOL ALPHA UNDERBAR + +02377 +APL FUNCTIONAL SYMBOL EPSILON UNDERBAR + +02378 +APL FUNCTIONAL SYMBOL IOTA UNDERBAR + +02379 +APL FUNCTIONAL SYMBOL OMEGA UNDERBAR + +0237A +APL FUNCTIONAL SYMBOL ALPHA + +0237B +NOT CHECK MARK + +0237C +RIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROW + +0237D +SHOULDERED OPEN BOX + +0237E +BELL SYMBOL + +0237F +VERTICAL LINE WITH MIDDLE DOT + +02380 +INSERTION SYMBOL + +02381 +CONTINUOUS UNDERLINE SYMBOL + +02382 +DISCONTINUOUS UNDERLINE SYMBOL + +02383 +EMPHASIS SYMBOL + +02384 +COMPOSITION SYMBOL + +02385 +WHITE SQUARE WITH CENTRE VERTICAL LINE + +02386 +ENTER SYMBOL + +02387 +ALTERNATIVE KEY SYMBOL + +02388 +HELM SYMBOL + +02389 +CIRCLED HORIZONTAL BAR WITH NOTCH + +0238A +CIRCLED TRIANGLE DOWN + +0238B +BROKEN CIRCLE WITH NORTHWEST ARROW + +0238C +UNDO SYMBOL + +0238D +MONOSTABLE SYMBOL + +0238E +HYSTERESIS SYMBOL + +0238F +OPEN-CIRCUIT-OUTPUT H-TYPE SYMBOL + +02390 +OPEN-CIRCUIT-OUTPUT L-TYPE SYMBOL + +02391 +PASSIVE-PULL-DOWN-OUTPUT SYMBOL + +02392 +PASSIVE-PULL-UP-OUTPUT SYMBOL + +02393 +DIRECT CURRENT SYMBOL FORM TWO + +02394 +SOFTWARE-FUNCTION SYMBOL + +02395 +APL FUNCTIONAL SYMBOL QUAD + +02396 +DECIMAL SEPARATOR KEY SYMBOL + +02397 +PREVIOUS PAGE + +02398 +NEXT PAGE + +02399 +PRINT SCREEN SYMBOL + +0239A +CLEAR SCREEN SYMBOL + +0239B +LEFT PARENTHESIS UPPER HOOK + +0239C +LEFT PARENTHESIS EXTENSION + +0239D +LEFT PARENTHESIS LOWER HOOK + +0239E +RIGHT PARENTHESIS UPPER HOOK + +0239F +RIGHT PARENTHESIS EXTENSION + +023A0 +RIGHT PARENTHESIS LOWER HOOK + +023A1 +LEFT SQUARE BRACKET UPPER CORNER + +023A2 +LEFT SQUARE BRACKET EXTENSION + +023A3 +LEFT SQUARE BRACKET LOWER CORNER + +023A4 +RIGHT SQUARE BRACKET UPPER CORNER + +023A5 +RIGHT SQUARE BRACKET EXTENSION + +023A6 +RIGHT SQUARE BRACKET LOWER CORNER + +023A7 +LEFT CURLY BRACKET UPPER HOOK + +023A8 +LEFT CURLY BRACKET MIDDLE PIECE + +023A9 +LEFT CURLY BRACKET LOWER HOOK + +023AA +CURLY BRACKET EXTENSION + +023AB +RIGHT CURLY BRACKET UPPER HOOK + +023AC +RIGHT CURLY BRACKET MIDDLE PIECE + +023AD +RIGHT CURLY BRACKET LOWER HOOK + +023AE +INTEGRAL EXTENSION + +023AF +HORIZONTAL LINE EXTENSION + +023B0 +UPPER LEFT OR LOWER RIGHT CURLY BRACKET SECTION + +023B1 +UPPER RIGHT OR LOWER LEFT CURLY BRACKET SECTION + +023B2 +SUMMATION TOP + +023B3 +SUMMATION BOTTOM + +023B4 +TOP SQUARE BRACKET + +023B5 +BOTTOM SQUARE BRACKET + +023B6 +BOTTOM SQUARE BRACKET OVER TOP SQUARE BRACKET + +023B7 +RADICAL SYMBOL BOTTOM + +023B8 +LEFT VERTICAL BOX LINE + +023B9 +RIGHT VERTICAL BOX LINE + +023BA +HORIZONTAL SCAN LINE-1 + +023BB +HORIZONTAL SCAN LINE-3 + +023BC +HORIZONTAL SCAN LINE-7 + +023BD +HORIZONTAL SCAN LINE-9 + +023BE +DENTISTRY SYMBOL LIGHT VERTICAL AND TOP RIGHT + +023BF +DENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM RIGHT + +023C0 +DENTISTRY SYMBOL LIGHT VERTICAL WITH CIRCLE + +023C1 +DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH CIRCLE + +023C2 +DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH CIRCLE + +023C3 +DENTISTRY SYMBOL LIGHT VERTICAL WITH TRIANGLE + +023C4 +DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH TRIANGLE + +023C5 +DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH TRIANGLE + +023C6 +DENTISTRY SYMBOL LIGHT VERTICAL AND WAVE + +023C7 +DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH WAVE + +023C8 +DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH WAVE + +023C9 +DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL + +023CA +DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL + +023CB +DENTISTRY SYMBOL LIGHT VERTICAL AND TOP LEFT + +023CC +DENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM LEFT + +023CD +SQUARE FOOT + +023CE +RETURN SYMBOL + +023CF +EJECT SYMBOL + +023D0 +VERTICAL LINE EXTENSION + +023D1 +METRICAL BREVE + +023D2 +METRICAL LONG OVER SHORT + +023D3 +METRICAL SHORT OVER LONG + +023D4 +METRICAL LONG OVER TWO SHORTS + +023D5 +METRICAL TWO SHORTS OVER LONG + +023D6 +METRICAL TWO SHORTS JOINED + +023D7 +METRICAL TRISEME + +023D8 +METRICAL TETRASEME + +023D9 +METRICAL PENTASEME + +023DA +EARTH GROUND + +023DB +FUSE + +023DC +TOP PARENTHESIS + +023DD +BOTTOM PARENTHESIS + +023DE +TOP CURLY BRACKET + +023DF +BOTTOM CURLY BRACKET + +023E0 +TOP TORTOISE SHELL BRACKET + +023E1 +BOTTOM TORTOISE SHELL BRACKET + +023E2 +WHITE TRAPEZIUM + +023E3 +BENZENE RING WITH CIRCLE + +023E4 +STRAIGHTNESS + +023E5 +FLATNESS + +023E6 +AC CURRENT + +023E7 +ELECTRICAL INTERSECTION + +023E8 +DECIMAL EXPONENT SYMBOL + +023E9 +BLACK RIGHT-POINTING DOUBLE TRIANGLE + +023EA +BLACK LEFT-POINTING DOUBLE TRIANGLE + +023EB +BLACK UP-POINTING DOUBLE TRIANGLE + +023EC +BLACK DOWN-POINTING DOUBLE TRIANGLE + +023ED +BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR + +023EE +BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR + +023EF +BLACK RIGHT-POINTING TRIANGLE WITH DOUBLE VERTICAL BAR + +023F0 +ALARM CLOCK + +023F1 +STOPWATCH + +023F2 +TIMER CLOCK + +023F3 +HOURGLASS WITH FLOWING SAND + +023F4 +BLACK MEDIUM LEFT-POINTING TRIANGLE + +023F5 +BLACK MEDIUM RIGHT-POINTING TRIANGLE + +023F6 +BLACK MEDIUM UP-POINTING TRIANGLE + +023F7 +BLACK MEDIUM DOWN-POINTING TRIANGLE + +023F8 +DOUBLE VERTICAL BAR + +023F9 +BLACK SQUARE FOR STOP + +023FA +BLACK CIRCLE FOR RECORD + +023FB +POWER SYMBOL + +023FC +POWER ON-OFF SYMBOL + +023FD +POWER ON SYMBOL + +023FE +POWER SLEEP SYMBOL + +023FF +OBSERVER EYE SYMBOL + +02400 +SYMBOL FOR NULL + +02401 +SYMBOL FOR START OF HEADING + +02402 +SYMBOL FOR START OF TEXT + +02403 +SYMBOL FOR END OF TEXT + +02404 +SYMBOL FOR END OF TRANSMISSION + +02405 +SYMBOL FOR ENQUIRY + +02406 +SYMBOL FOR ACKNOWLEDGE + +02407 +SYMBOL FOR BELL + +02408 +SYMBOL FOR BACKSPACE + +02409 +SYMBOL FOR HORIZONTAL TABULATION + +0240A +SYMBOL FOR LINE FEED + +0240B +SYMBOL FOR VERTICAL TABULATION + +0240C +SYMBOL FOR FORM FEED + +0240D +SYMBOL FOR CARRIAGE RETURN + +0240E +SYMBOL FOR SHIFT OUT + +0240F +SYMBOL FOR SHIFT IN + +02410 +SYMBOL FOR DATA LINK ESCAPE + +02411 +SYMBOL FOR DEVICE CONTROL ONE + +02412 +SYMBOL FOR DEVICE CONTROL TWO + +02413 +SYMBOL FOR DEVICE CONTROL THREE + +02414 +SYMBOL FOR DEVICE CONTROL FOUR + +02415 +SYMBOL FOR NEGATIVE ACKNOWLEDGE + +02416 +SYMBOL FOR SYNCHRONOUS IDLE + +02417 +SYMBOL FOR END OF TRANSMISSION BLOCK + +02418 +SYMBOL FOR CANCEL + +02419 +SYMBOL FOR END OF MEDIUM + +0241A +SYMBOL FOR SUBSTITUTE + +0241B +SYMBOL FOR ESCAPE + +0241C +SYMBOL FOR FILE SEPARATOR + +0241D +SYMBOL FOR GROUP SEPARATOR + +0241E +SYMBOL FOR RECORD SEPARATOR + +0241F +SYMBOL FOR UNIT SEPARATOR + +02420 +SYMBOL FOR SPACE + +02421 +SYMBOL FOR DELETE + +02422 +BLANK SYMBOL + +02423 +OPEN BOX + +02424 +SYMBOL FOR NEWLINE + +02425 +SYMBOL FOR DELETE FORM TWO + +02426 +SYMBOL FOR SUBSTITUTE FORM TWO + +02427 +SYMBOL FOR DELETE SQUARE CHECKER BOARD FORM + +02428 +SYMBOL FOR DELETE RECTANGULAR CHECKER BOARD FORM + +02429 +SYMBOL FOR DELETE MEDIUM SHADE FORM + +02440 +OCR HOOK + +02441 +OCR CHAIR + +02442 +OCR FORK + +02443 +OCR INVERTED FORK + +02444 +OCR BELT BUCKLE + +02445 +OCR BOW TIE + +02446 +OCR BRANCH BANK IDENTIFICATION + +02447 +OCR AMOUNT OF CHECK + +02448 +MICR ON US SYMBOL + +02448 +OCR DASH + +02449 +MICR DASH SYMBOL + +02449 +OCR CUSTOMER ACCOUNT NUMBER + +0244A +OCR DOUBLE BACKSLASH + +02460 +CIRCLED DIGIT ONE + +02461 +CIRCLED DIGIT TWO + +02462 +CIRCLED DIGIT THREE + +02463 +CIRCLED DIGIT FOUR + +02464 +CIRCLED DIGIT FIVE + +02465 +CIRCLED DIGIT SIX + +02466 +CIRCLED DIGIT SEVEN + +02467 +CIRCLED DIGIT EIGHT + +02468 +CIRCLED DIGIT NINE + +02469 +CIRCLED NUMBER TEN + +0246A +CIRCLED NUMBER ELEVEN + +0246B +CIRCLED NUMBER TWELVE + +0246C +CIRCLED NUMBER THIRTEEN + +0246D +CIRCLED NUMBER FOURTEEN + +0246E +CIRCLED NUMBER FIFTEEN + +0246F +CIRCLED NUMBER SIXTEEN + +02470 +CIRCLED NUMBER SEVENTEEN + +02471 +CIRCLED NUMBER EIGHTEEN + +02472 +CIRCLED NUMBER NINETEEN + +02473 +CIRCLED NUMBER TWENTY + +02474 +PARENTHESIZED DIGIT ONE + +02475 +PARENTHESIZED DIGIT TWO + +02476 +PARENTHESIZED DIGIT THREE + +02477 +PARENTHESIZED DIGIT FOUR + +02478 +PARENTHESIZED DIGIT FIVE + +02479 +PARENTHESIZED DIGIT SIX + +0247A +PARENTHESIZED DIGIT SEVEN + +0247B +PARENTHESIZED DIGIT EIGHT + +0247C +PARENTHESIZED DIGIT NINE + +0247D +PARENTHESIZED NUMBER TEN + +0247E +PARENTHESIZED NUMBER ELEVEN + +0247F +PARENTHESIZED NUMBER TWELVE + +02480 +PARENTHESIZED NUMBER THIRTEEN + +02481 +PARENTHESIZED NUMBER FOURTEEN + +02482 +PARENTHESIZED NUMBER FIFTEEN + +02483 +PARENTHESIZED NUMBER SIXTEEN + +02484 +PARENTHESIZED NUMBER SEVENTEEN + +02485 +PARENTHESIZED NUMBER EIGHTEEN + +02486 +PARENTHESIZED NUMBER NINETEEN + +02487 +PARENTHESIZED NUMBER TWENTY + +02488 +DIGIT ONE FULL STOP + +02489 +DIGIT TWO FULL STOP + +0248A +DIGIT THREE FULL STOP + +0248B +DIGIT FOUR FULL STOP + +0248C +DIGIT FIVE FULL STOP + +0248D +DIGIT SIX FULL STOP + +0248E +DIGIT SEVEN FULL STOP + +0248F +DIGIT EIGHT FULL STOP + +02490 +DIGIT NINE FULL STOP + +02491 +NUMBER TEN FULL STOP + +02492 +NUMBER ELEVEN FULL STOP + +02493 +NUMBER TWELVE FULL STOP + +02494 +NUMBER THIRTEEN FULL STOP + +02495 +NUMBER FOURTEEN FULL STOP + +02496 +NUMBER FIFTEEN FULL STOP + +02497 +NUMBER SIXTEEN FULL STOP + +02498 +NUMBER SEVENTEEN FULL STOP + +02499 +NUMBER EIGHTEEN FULL STOP + +0249A +NUMBER NINETEEN FULL STOP + +0249B +NUMBER TWENTY FULL STOP + +0249C +PARENTHESIZED LATIN SMALL LETTER A + +0249D +PARENTHESIZED LATIN SMALL LETTER B + +0249E +PARENTHESIZED LATIN SMALL LETTER C + +0249F +PARENTHESIZED LATIN SMALL LETTER D + +024A0 +PARENTHESIZED LATIN SMALL LETTER E + +024A1 +PARENTHESIZED LATIN SMALL LETTER F + +024A2 +PARENTHESIZED LATIN SMALL LETTER G + +024A3 +PARENTHESIZED LATIN SMALL LETTER H + +024A4 +PARENTHESIZED LATIN SMALL LETTER I + +024A5 +PARENTHESIZED LATIN SMALL LETTER J + +024A6 +PARENTHESIZED LATIN SMALL LETTER K + +024A7 +PARENTHESIZED LATIN SMALL LETTER L + +024A8 +PARENTHESIZED LATIN SMALL LETTER M + +024A9 +PARENTHESIZED LATIN SMALL LETTER N + +024AA +PARENTHESIZED LATIN SMALL LETTER O + +024AB +PARENTHESIZED LATIN SMALL LETTER P + +024AC +PARENTHESIZED LATIN SMALL LETTER Q + +024AD +PARENTHESIZED LATIN SMALL LETTER R + +024AE +PARENTHESIZED LATIN SMALL LETTER S + +024AF +PARENTHESIZED LATIN SMALL LETTER T + +024B0 +PARENTHESIZED LATIN SMALL LETTER U + +024B1 +PARENTHESIZED LATIN SMALL LETTER V + +024B2 +PARENTHESIZED LATIN SMALL LETTER W + +024B3 +PARENTHESIZED LATIN SMALL LETTER X + +024B4 +PARENTHESIZED LATIN SMALL LETTER Y + +024B5 +PARENTHESIZED LATIN SMALL LETTER Z + +024B6 +CIRCLED LATIN CAPITAL LETTER A + +024B7 +CIRCLED LATIN CAPITAL LETTER B + +024B8 +CIRCLED LATIN CAPITAL LETTER C + +024B9 +CIRCLED LATIN CAPITAL LETTER D + +024BA +CIRCLED LATIN CAPITAL LETTER E + +024BB +CIRCLED LATIN CAPITAL LETTER F + +024BC +CIRCLED LATIN CAPITAL LETTER G + +024BD +CIRCLED LATIN CAPITAL LETTER H + +024BE +CIRCLED LATIN CAPITAL LETTER I + +024BF +CIRCLED LATIN CAPITAL LETTER J + +024C0 +CIRCLED LATIN CAPITAL LETTER K + +024C1 +CIRCLED LATIN CAPITAL LETTER L + +024C2 +CIRCLED LATIN CAPITAL LETTER M + +024C3 +CIRCLED LATIN CAPITAL LETTER N + +024C4 +CIRCLED LATIN CAPITAL LETTER O + +024C5 +CIRCLED LATIN CAPITAL LETTER P + +024C6 +CIRCLED LATIN CAPITAL LETTER Q + +024C7 +CIRCLED LATIN CAPITAL LETTER R + +024C8 +CIRCLED LATIN CAPITAL LETTER S + +024C9 +CIRCLED LATIN CAPITAL LETTER T + +024CA +CIRCLED LATIN CAPITAL LETTER U + +024CB +CIRCLED LATIN CAPITAL LETTER V + +024CC +CIRCLED LATIN CAPITAL LETTER W + +024CD +CIRCLED LATIN CAPITAL LETTER X + +024CE +CIRCLED LATIN CAPITAL LETTER Y + +024CF +CIRCLED LATIN CAPITAL LETTER Z + +024D0 +CIRCLED LATIN SMALL LETTER A + +024D1 +CIRCLED LATIN SMALL LETTER B + +024D2 +CIRCLED LATIN SMALL LETTER C + +024D3 +CIRCLED LATIN SMALL LETTER D + +024D4 +CIRCLED LATIN SMALL LETTER E + +024D5 +CIRCLED LATIN SMALL LETTER F + +024D6 +CIRCLED LATIN SMALL LETTER G + +024D7 +CIRCLED LATIN SMALL LETTER H + +024D8 +CIRCLED LATIN SMALL LETTER I + +024D9 +CIRCLED LATIN SMALL LETTER J + +024DA +CIRCLED LATIN SMALL LETTER K + +024DB +CIRCLED LATIN SMALL LETTER L + +024DC +CIRCLED LATIN SMALL LETTER M + +024DD +CIRCLED LATIN SMALL LETTER N + +024DE +CIRCLED LATIN SMALL LETTER O + +024DF +CIRCLED LATIN SMALL LETTER P + +024E0 +CIRCLED LATIN SMALL LETTER Q + +024E1 +CIRCLED LATIN SMALL LETTER R + +024E2 +CIRCLED LATIN SMALL LETTER S + +024E3 +CIRCLED LATIN SMALL LETTER T + +024E4 +CIRCLED LATIN SMALL LETTER U + +024E5 +CIRCLED LATIN SMALL LETTER V + +024E6 +CIRCLED LATIN SMALL LETTER W + +024E7 +CIRCLED LATIN SMALL LETTER X + +024E8 +CIRCLED LATIN SMALL LETTER Y + +024E9 +CIRCLED LATIN SMALL LETTER Z + +024EA +CIRCLED DIGIT ZERO + +024EB +NEGATIVE CIRCLED NUMBER ELEVEN + +024EC +NEGATIVE CIRCLED NUMBER TWELVE + +024ED +NEGATIVE CIRCLED NUMBER THIRTEEN + +024EE +NEGATIVE CIRCLED NUMBER FOURTEEN + +024EF +NEGATIVE CIRCLED NUMBER FIFTEEN + +024F0 +NEGATIVE CIRCLED NUMBER SIXTEEN + +024F1 +NEGATIVE CIRCLED NUMBER SEVENTEEN + +024F2 +NEGATIVE CIRCLED NUMBER EIGHTEEN + +024F3 +NEGATIVE CIRCLED NUMBER NINETEEN + +024F4 +NEGATIVE CIRCLED NUMBER TWENTY + +024F5 +DOUBLE CIRCLED DIGIT ONE + +024F6 +DOUBLE CIRCLED DIGIT TWO + +024F7 +DOUBLE CIRCLED DIGIT THREE + +024F8 +DOUBLE CIRCLED DIGIT FOUR + +024F9 +DOUBLE CIRCLED DIGIT FIVE + +024FA +DOUBLE CIRCLED DIGIT SIX + +024FB +DOUBLE CIRCLED DIGIT SEVEN + +024FC +DOUBLE CIRCLED DIGIT EIGHT + +024FD +DOUBLE CIRCLED DIGIT NINE + +024FE +DOUBLE CIRCLED NUMBER TEN + +024FF +NEGATIVE CIRCLED DIGIT ZERO + +02500 +BOX DRAWINGS LIGHT HORIZONTAL + +02501 +BOX DRAWINGS HEAVY HORIZONTAL + +02502 +BOX DRAWINGS LIGHT VERTICAL + +02503 +BOX DRAWINGS HEAVY VERTICAL + +02504 +BOX DRAWINGS LIGHT TRIPLE DASH HORIZONTAL + +02505 +BOX DRAWINGS HEAVY TRIPLE DASH HORIZONTAL + +02506 +BOX DRAWINGS LIGHT TRIPLE DASH VERTICAL + +02507 +BOX DRAWINGS HEAVY TRIPLE DASH VERTICAL + +02508 +BOX DRAWINGS LIGHT QUADRUPLE DASH HORIZONTAL + +02509 +BOX DRAWINGS HEAVY QUADRUPLE DASH HORIZONTAL + +0250A +BOX DRAWINGS LIGHT QUADRUPLE DASH VERTICAL + +0250B +BOX DRAWINGS HEAVY QUADRUPLE DASH VERTICAL + +0250C +BOX DRAWINGS LIGHT DOWN AND RIGHT + +0250D +BOX DRAWINGS DOWN LIGHT AND RIGHT HEAVY + +0250E +BOX DRAWINGS DOWN HEAVY AND RIGHT LIGHT + +0250F +BOX DRAWINGS HEAVY DOWN AND RIGHT + +02510 +BOX DRAWINGS LIGHT DOWN AND LEFT + +02511 +BOX DRAWINGS DOWN LIGHT AND LEFT HEAVY + +02512 +BOX DRAWINGS DOWN HEAVY AND LEFT LIGHT + +02513 +BOX DRAWINGS HEAVY DOWN AND LEFT + +02514 +BOX DRAWINGS LIGHT UP AND RIGHT + +02515 +BOX DRAWINGS UP LIGHT AND RIGHT HEAVY + +02516 +BOX DRAWINGS UP HEAVY AND RIGHT LIGHT + +02517 +BOX DRAWINGS HEAVY UP AND RIGHT + +02518 +BOX DRAWINGS LIGHT UP AND LEFT + +02519 +BOX DRAWINGS UP LIGHT AND LEFT HEAVY + +0251A +BOX DRAWINGS UP HEAVY AND LEFT LIGHT + +0251B +BOX DRAWINGS HEAVY UP AND LEFT + +0251C +BOX DRAWINGS LIGHT VERTICAL AND RIGHT + +0251D +BOX DRAWINGS VERTICAL LIGHT AND RIGHT HEAVY + +0251E +BOX DRAWINGS UP HEAVY AND RIGHT DOWN LIGHT + +0251F +BOX DRAWINGS DOWN HEAVY AND RIGHT UP LIGHT + +02520 +BOX DRAWINGS VERTICAL HEAVY AND RIGHT LIGHT + +02521 +BOX DRAWINGS DOWN LIGHT AND RIGHT UP HEAVY + +02522 +BOX DRAWINGS UP LIGHT AND RIGHT DOWN HEAVY + +02523 +BOX DRAWINGS HEAVY VERTICAL AND RIGHT + +02524 +BOX DRAWINGS LIGHT VERTICAL AND LEFT + +02525 +BOX DRAWINGS VERTICAL LIGHT AND LEFT HEAVY + +02526 +BOX DRAWINGS UP HEAVY AND LEFT DOWN LIGHT + +02527 +BOX DRAWINGS DOWN HEAVY AND LEFT UP LIGHT + +02528 +BOX DRAWINGS VERTICAL HEAVY AND LEFT LIGHT + +02529 +BOX DRAWINGS DOWN LIGHT AND LEFT UP HEAVY + +0252A +BOX DRAWINGS UP LIGHT AND LEFT DOWN HEAVY + +0252B +BOX DRAWINGS HEAVY VERTICAL AND LEFT + +0252C +BOX DRAWINGS LIGHT DOWN AND HORIZONTAL + +0252D +BOX DRAWINGS LEFT HEAVY AND RIGHT DOWN LIGHT + +0252E +BOX DRAWINGS RIGHT HEAVY AND LEFT DOWN LIGHT + +0252F +BOX DRAWINGS DOWN LIGHT AND HORIZONTAL HEAVY + +02530 +BOX DRAWINGS DOWN HEAVY AND HORIZONTAL LIGHT + +02531 +BOX DRAWINGS RIGHT LIGHT AND LEFT DOWN HEAVY + +02532 +BOX DRAWINGS LEFT LIGHT AND RIGHT DOWN HEAVY + +02533 +BOX DRAWINGS HEAVY DOWN AND HORIZONTAL + +02534 +BOX DRAWINGS LIGHT UP AND HORIZONTAL + +02535 +BOX DRAWINGS LEFT HEAVY AND RIGHT UP LIGHT + +02536 +BOX DRAWINGS RIGHT HEAVY AND LEFT UP LIGHT + +02537 +BOX DRAWINGS UP LIGHT AND HORIZONTAL HEAVY + +02538 +BOX DRAWINGS UP HEAVY AND HORIZONTAL LIGHT + +02539 +BOX DRAWINGS RIGHT LIGHT AND LEFT UP HEAVY + +0253A +BOX DRAWINGS LEFT LIGHT AND RIGHT UP HEAVY + +0253B +BOX DRAWINGS HEAVY UP AND HORIZONTAL + +0253C +BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL + +0253D +BOX DRAWINGS LEFT HEAVY AND RIGHT VERTICAL LIGHT + +0253E +BOX DRAWINGS RIGHT HEAVY AND LEFT VERTICAL LIGHT + +0253F +BOX DRAWINGS VERTICAL LIGHT AND HORIZONTAL HEAVY + +02540 +BOX DRAWINGS UP HEAVY AND DOWN HORIZONTAL LIGHT + +02541 +BOX DRAWINGS DOWN HEAVY AND UP HORIZONTAL LIGHT + +02542 +BOX DRAWINGS VERTICAL HEAVY AND HORIZONTAL LIGHT + +02543 +BOX DRAWINGS LEFT UP HEAVY AND RIGHT DOWN LIGHT + +02544 +BOX DRAWINGS RIGHT UP HEAVY AND LEFT DOWN LIGHT + +02545 +BOX DRAWINGS LEFT DOWN HEAVY AND RIGHT UP LIGHT + +02546 +BOX DRAWINGS RIGHT DOWN HEAVY AND LEFT UP LIGHT + +02547 +BOX DRAWINGS DOWN LIGHT AND UP HORIZONTAL HEAVY + +02548 +BOX DRAWINGS UP LIGHT AND DOWN HORIZONTAL HEAVY + +02549 +BOX DRAWINGS RIGHT LIGHT AND LEFT VERTICAL HEAVY + +0254A +BOX DRAWINGS LEFT LIGHT AND RIGHT VERTICAL HEAVY + +0254B +BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL + +0254C +BOX DRAWINGS LIGHT DOUBLE DASH HORIZONTAL + +0254D +BOX DRAWINGS HEAVY DOUBLE DASH HORIZONTAL + +0254E +BOX DRAWINGS LIGHT DOUBLE DASH VERTICAL + +0254F +BOX DRAWINGS HEAVY DOUBLE DASH VERTICAL + +02550 +BOX DRAWINGS DOUBLE HORIZONTAL + +02551 +BOX DRAWINGS DOUBLE VERTICAL + +02552 +BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE + +02553 +BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE + +02554 +BOX DRAWINGS DOUBLE DOWN AND RIGHT + +02555 +BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE + +02556 +BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE + +02557 +BOX DRAWINGS DOUBLE DOWN AND LEFT + +02558 +BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE + +02559 +BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE + +0255A +BOX DRAWINGS DOUBLE UP AND RIGHT + +0255B +BOX DRAWINGS UP SINGLE AND LEFT DOUBLE + +0255C +BOX DRAWINGS UP DOUBLE AND LEFT SINGLE + +0255D +BOX DRAWINGS DOUBLE UP AND LEFT + +0255E +BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE + +0255F +BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE + +02560 +BOX DRAWINGS DOUBLE VERTICAL AND RIGHT + +02561 +BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE + +02562 +BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE + +02563 +BOX DRAWINGS DOUBLE VERTICAL AND LEFT + +02564 +BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE + +02565 +BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE + +02566 +BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL + +02567 +BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE + +02568 +BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE + +02569 +BOX DRAWINGS DOUBLE UP AND HORIZONTAL + +0256A +BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE + +0256B +BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE + +0256C +BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL + +0256D +BOX DRAWINGS LIGHT ARC DOWN AND RIGHT + +0256E +BOX DRAWINGS LIGHT ARC DOWN AND LEFT + +0256F +BOX DRAWINGS LIGHT ARC UP AND LEFT + +02570 +BOX DRAWINGS LIGHT ARC UP AND RIGHT + +02571 +BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT + +02572 +BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT + +02573 +BOX DRAWINGS LIGHT DIAGONAL CROSS + +02574 +BOX DRAWINGS LIGHT LEFT + +02575 +BOX DRAWINGS LIGHT UP + +02576 +BOX DRAWINGS LIGHT RIGHT + +02577 +BOX DRAWINGS LIGHT DOWN + +02578 +BOX DRAWINGS HEAVY LEFT + +02579 +BOX DRAWINGS HEAVY UP + +0257A +BOX DRAWINGS HEAVY RIGHT + +0257B +BOX DRAWINGS HEAVY DOWN + +0257C +BOX DRAWINGS LIGHT LEFT AND HEAVY RIGHT + +0257D +BOX DRAWINGS LIGHT UP AND HEAVY DOWN + +0257E +BOX DRAWINGS HEAVY LEFT AND LIGHT RIGHT + +0257F +BOX DRAWINGS HEAVY UP AND LIGHT DOWN + +02580 +UPPER HALF BLOCK + +02581 +LOWER ONE EIGHTH BLOCK + +02582 +LOWER ONE QUARTER BLOCK + +02583 +LOWER THREE EIGHTHS BLOCK + +02584 +LOWER HALF BLOCK + +02585 +LOWER FIVE EIGHTHS BLOCK + +02586 +LOWER THREE QUARTERS BLOCK + +02587 +LOWER SEVEN EIGHTHS BLOCK + +02588 +FULL BLOCK + +02589 +LEFT SEVEN EIGHTHS BLOCK + +0258A +LEFT THREE QUARTERS BLOCK + +0258B +LEFT FIVE EIGHTHS BLOCK + +0258C +LEFT HALF BLOCK + +0258D +LEFT THREE EIGHTHS BLOCK + +0258E +LEFT ONE QUARTER BLOCK + +0258F +LEFT ONE EIGHTH BLOCK + +02590 +RIGHT HALF BLOCK + +02591 +LIGHT SHADE + +02592 +MEDIUM SHADE + +02593 +DARK SHADE + +02594 +UPPER ONE EIGHTH BLOCK + +02595 +RIGHT ONE EIGHTH BLOCK + +02596 +QUADRANT LOWER LEFT + +02597 +QUADRANT LOWER RIGHT + +02598 +QUADRANT UPPER LEFT + +02599 +QUADRANT UPPER LEFT AND LOWER LEFT AND LOWER RIGHT + +0259A +QUADRANT UPPER LEFT AND LOWER RIGHT + +0259B +QUADRANT UPPER LEFT AND UPPER RIGHT AND LOWER LEFT + +0259C +QUADRANT UPPER LEFT AND UPPER RIGHT AND LOWER RIGHT + +0259D +QUADRANT UPPER RIGHT + +0259E +QUADRANT UPPER RIGHT AND LOWER LEFT + +0259F +QUADRANT UPPER RIGHT AND LOWER LEFT AND LOWER RIGHT + +025A0 +BLACK SQUARE + +025A1 +WHITE SQUARE + +025A2 +WHITE SQUARE WITH ROUNDED CORNERS + +025A3 +WHITE SQUARE CONTAINING BLACK SMALL SQUARE + +025A4 +SQUARE WITH HORIZONTAL FILL + +025A5 +SQUARE WITH VERTICAL FILL + +025A6 +SQUARE WITH ORTHOGONAL CROSSHATCH FILL + +025A7 +SQUARE WITH UPPER LEFT TO LOWER RIGHT FILL + +025A8 +SQUARE WITH UPPER RIGHT TO LOWER LEFT FILL + +025A9 +SQUARE WITH DIAGONAL CROSSHATCH FILL + +025AA +BLACK SMALL SQUARE + +025AB +WHITE SMALL SQUARE + +025AC +BLACK RECTANGLE + +025AD +WHITE RECTANGLE + +025AE +BLACK VERTICAL RECTANGLE + +025AF +WHITE VERTICAL RECTANGLE + +025B0 +BLACK PARALLELOGRAM + +025B1 +WHITE PARALLELOGRAM + +025B2 +BLACK UP-POINTING TRIANGLE + +025B3 +WHITE UP-POINTING TRIANGLE + +025B4 +BLACK UP-POINTING SMALL TRIANGLE + +025B5 +WHITE UP-POINTING SMALL TRIANGLE + +025B6 +BLACK RIGHT-POINTING TRIANGLE + +025B7 +WHITE RIGHT-POINTING TRIANGLE + +025B8 +BLACK RIGHT-POINTING SMALL TRIANGLE + +025B9 +WHITE RIGHT-POINTING SMALL TRIANGLE + +025BA +BLACK RIGHT-POINTING POINTER + +025BB +WHITE RIGHT-POINTING POINTER + +025BC +BLACK DOWN-POINTING TRIANGLE + +025BD +WHITE DOWN-POINTING TRIANGLE + +025BE +BLACK DOWN-POINTING SMALL TRIANGLE + +025BF +WHITE DOWN-POINTING SMALL TRIANGLE + +025C0 +BLACK LEFT-POINTING TRIANGLE + +025C1 +WHITE LEFT-POINTING TRIANGLE + +025C2 +BLACK LEFT-POINTING SMALL TRIANGLE + +025C3 +WHITE LEFT-POINTING SMALL TRIANGLE + +025C4 +BLACK LEFT-POINTING POINTER + +025C5 +WHITE LEFT-POINTING POINTER + +025C6 +BLACK DIAMOND + +025C7 +WHITE DIAMOND + +025C8 +WHITE DIAMOND CONTAINING BLACK SMALL DIAMOND + +025C9 +FISHEYE + +025CA +LOZENGE + +025CB +WHITE CIRCLE + +025CC +DOTTED CIRCLE + +025CD +CIRCLE WITH VERTICAL FILL + +025CE +BULLSEYE + +025CF +BLACK CIRCLE + +025D0 +CIRCLE WITH LEFT HALF BLACK + +025D1 +CIRCLE WITH RIGHT HALF BLACK + +025D2 +CIRCLE WITH LOWER HALF BLACK + +025D3 +CIRCLE WITH UPPER HALF BLACK + +025D4 +CIRCLE WITH UPPER RIGHT QUADRANT BLACK + +025D5 +CIRCLE WITH ALL BUT UPPER LEFT QUADRANT BLACK + +025D6 +LEFT HALF BLACK CIRCLE + +025D7 +RIGHT HALF BLACK CIRCLE + +025D8 +INVERSE BULLET + +025D9 +INVERSE WHITE CIRCLE + +025DA +UPPER HALF INVERSE WHITE CIRCLE + +025DB +LOWER HALF INVERSE WHITE CIRCLE + +025DC +UPPER LEFT QUADRANT CIRCULAR ARC + +025DD +UPPER RIGHT QUADRANT CIRCULAR ARC + +025DE +LOWER RIGHT QUADRANT CIRCULAR ARC + +025DF +LOWER LEFT QUADRANT CIRCULAR ARC + +025E0 +UPPER HALF CIRCLE + +025E1 +LOWER HALF CIRCLE + +025E2 +BLACK LOWER RIGHT TRIANGLE + +025E3 +BLACK LOWER LEFT TRIANGLE + +025E4 +BLACK UPPER LEFT TRIANGLE + +025E5 +BLACK UPPER RIGHT TRIANGLE + +025E6 +WHITE BULLET + +025E7 +SQUARE WITH LEFT HALF BLACK + +025E8 +SQUARE WITH RIGHT HALF BLACK + +025E9 +SQUARE WITH UPPER LEFT DIAGONAL HALF BLACK + +025EA +SQUARE WITH LOWER RIGHT DIAGONAL HALF BLACK + +025EB +WHITE SQUARE WITH VERTICAL BISECTING LINE + +025EC +WHITE UP-POINTING TRIANGLE WITH DOT + +025ED +UP-POINTING TRIANGLE WITH LEFT HALF BLACK + +025EE +UP-POINTING TRIANGLE WITH RIGHT HALF BLACK + +025EF +LARGE CIRCLE + +025F0 +WHITE SQUARE WITH UPPER LEFT QUADRANT + +025F1 +WHITE SQUARE WITH LOWER LEFT QUADRANT + +025F2 +WHITE SQUARE WITH LOWER RIGHT QUADRANT + +025F3 +WHITE SQUARE WITH UPPER RIGHT QUADRANT + +025F4 +WHITE CIRCLE WITH UPPER LEFT QUADRANT + +025F5 +WHITE CIRCLE WITH LOWER LEFT QUADRANT + +025F6 +WHITE CIRCLE WITH LOWER RIGHT QUADRANT + +025F7 +WHITE CIRCLE WITH UPPER RIGHT QUADRANT + +025F8 +UPPER LEFT TRIANGLE + +025F9 +UPPER RIGHT TRIANGLE + +025FA +LOWER LEFT TRIANGLE + +025FB +WHITE MEDIUM SQUARE + +025FC +BLACK MEDIUM SQUARE + +025FD +WHITE MEDIUM SMALL SQUARE + +025FE +BLACK MEDIUM SMALL SQUARE + +025FF +LOWER RIGHT TRIANGLE + +02600 +BLACK SUN WITH RAYS + +02601 +CLOUD + +02602 +UMBRELLA + +02603 +SNOWMAN + +02604 +COMET + +02605 +BLACK STAR + +02606 +WHITE STAR + +02607 +LIGHTNING + +02608 +THUNDERSTORM + +02609 +SUN + +0260A +ASCENDING NODE + +0260B +DESCENDING NODE + +0260C +CONJUNCTION + +0260D +OPPOSITION + +0260E +BLACK TELEPHONE + +0260F +WHITE TELEPHONE + +02610 +BALLOT BOX + +02611 +BALLOT BOX WITH CHECK + +02612 +BALLOT BOX WITH X + +02613 +SALTIRE + +02614 +UMBRELLA WITH RAIN DROPS + +02615 +HOT BEVERAGE + +02616 +WHITE SHOGI PIECE + +02617 +BLACK SHOGI PIECE + +02618 +SHAMROCK + +02619 +REVERSED ROTATED FLORAL HEART BULLET + +0261A +BLACK LEFT POINTING INDEX + +0261B +BLACK RIGHT POINTING INDEX + +0261C +WHITE LEFT POINTING INDEX + +0261D +WHITE UP POINTING INDEX + +0261E +WHITE RIGHT POINTING INDEX + +0261F +WHITE DOWN POINTING INDEX + +02620 +SKULL AND CROSSBONES + +02621 +CAUTION SIGN + +02622 +RADIOACTIVE SIGN + +02623 +BIOHAZARD SIGN + +02624 +CADUCEUS + +02625 +ANKH + +02626 +ORTHODOX CROSS + +02627 +CHI RHO + +02628 +CROSS OF LORRAINE + +02629 +CROSS OF JERUSALEM + +0262A +STAR AND CRESCENT + +0262B +FARSI SYMBOL + +0262C +ADI SHAKTI + +0262D +HAMMER AND SICKLE + +0262E +PEACE SYMBOL + +0262F +YIN YANG + +02630 +TRIGRAM FOR HEAVEN + +02631 +TRIGRAM FOR LAKE + +02632 +TRIGRAM FOR FIRE + +02633 +TRIGRAM FOR THUNDER + +02634 +TRIGRAM FOR WIND + +02635 +TRIGRAM FOR WATER + +02636 +TRIGRAM FOR MOUNTAIN + +02637 +TRIGRAM FOR EARTH + +02638 +WHEEL OF DHARMA + +02639 +WHITE FROWNING FACE + +0263A +WHITE SMILING FACE + +0263B +BLACK SMILING FACE + +0263C +WHITE SUN WITH RAYS + +0263D +FIRST QUARTER MOON + +0263E +LAST QUARTER MOON + +0263F +MERCURY + +02640 +FEMALE SIGN + +02641 +EARTH + +02642 +MALE SIGN + +02643 +JUPITER + +02644 +SATURN + +02645 +URANUS + +02646 +NEPTUNE + +02647 +PLUTO + +02648 +ARIES + +02649 +TAURUS + +0264A +GEMINI + +0264B +CANCER + +0264C +LEO + +0264D +VIRGO + +0264E +LIBRA + +0264F +SCORPIUS + +02650 +SAGITTARIUS + +02651 +CAPRICORN + +02652 +AQUARIUS + +02653 +PISCES + +02654 +WHITE CHESS KING + +02655 +WHITE CHESS QUEEN + +02656 +WHITE CHESS ROOK + +02657 +WHITE CHESS BISHOP + +02658 +WHITE CHESS KNIGHT + +02659 +WHITE CHESS PAWN + +0265A +BLACK CHESS KING + +0265B +BLACK CHESS QUEEN + +0265C +BLACK CHESS ROOK + +0265D +BLACK CHESS BISHOP + +0265E +BLACK CHESS KNIGHT + +0265F +BLACK CHESS PAWN + +02660 +BLACK SPADE SUIT + +02661 +WHITE HEART SUIT + +02662 +WHITE DIAMOND SUIT + +02663 +BLACK CLUB SUIT + +02664 +WHITE SPADE SUIT + +02665 +BLACK HEART SUIT + +02666 +BLACK DIAMOND SUIT + +02667 +WHITE CLUB SUIT + +02668 +HOT SPRINGS + +02669 +QUARTER NOTE + +0266A +EIGHTH NOTE + +0266B +BEAMED EIGHTH NOTES + +0266C +BEAMED SIXTEENTH NOTES + +0266D +MUSIC FLAT SIGN + +0266E +MUSIC NATURAL SIGN + +0266F +MUSIC SHARP SIGN + +02670 +WEST SYRIAC CROSS + +02671 +EAST SYRIAC CROSS + +02672 +UNIVERSAL RECYCLING SYMBOL + +02673 +RECYCLING SYMBOL FOR TYPE-1 PLASTICS + +02674 +RECYCLING SYMBOL FOR TYPE-2 PLASTICS + +02675 +RECYCLING SYMBOL FOR TYPE-3 PLASTICS + +02676 +RECYCLING SYMBOL FOR TYPE-4 PLASTICS + +02677 +RECYCLING SYMBOL FOR TYPE-5 PLASTICS + +02678 +RECYCLING SYMBOL FOR TYPE-6 PLASTICS + +02679 +RECYCLING SYMBOL FOR TYPE-7 PLASTICS + +0267A +RECYCLING SYMBOL FOR GENERIC MATERIALS + +0267B +BLACK UNIVERSAL RECYCLING SYMBOL + +0267C +RECYCLED PAPER SYMBOL + +0267D +PARTIALLY-RECYCLED PAPER SYMBOL + +0267E +PERMANENT PAPER SIGN + +0267F +WHEELCHAIR SYMBOL + +02680 +DIE FACE-1 + +02681 +DIE FACE-2 + +02682 +DIE FACE-3 + +02683 +DIE FACE-4 + +02684 +DIE FACE-5 + +02685 +DIE FACE-6 + +02686 +WHITE CIRCLE WITH DOT RIGHT + +02687 +WHITE CIRCLE WITH TWO DOTS + +02688 +BLACK CIRCLE WITH WHITE DOT RIGHT + +02689 +BLACK CIRCLE WITH TWO WHITE DOTS + +0268A +MONOGRAM FOR YANG + +0268B +MONOGRAM FOR YIN + +0268C +DIGRAM FOR GREATER YANG + +0268D +DIGRAM FOR LESSER YIN + +0268E +DIGRAM FOR LESSER YANG + +0268F +DIGRAM FOR GREATER YIN + +02690 +WHITE FLAG + +02691 +BLACK FLAG + +02692 +HAMMER AND PICK + +02693 +ANCHOR + +02694 +CROSSED SWORDS + +02695 +STAFF OF AESCULAPIUS + +02696 +SCALES + +02697 +ALEMBIC + +02698 +FLOWER + +02699 +GEAR + +0269A +STAFF OF HERMES + +0269B +ATOM SYMBOL + +0269C +FLEUR-DE-LIS + +0269D +OUTLINED WHITE STAR + +0269E +THREE LINES CONVERGING RIGHT + +0269F +THREE LINES CONVERGING LEFT + +026A0 +WARNING SIGN + +026A1 +HIGH VOLTAGE SIGN + +026A2 +DOUBLED FEMALE SIGN + +026A3 +DOUBLED MALE SIGN + +026A4 +INTERLOCKED FEMALE AND MALE SIGN + +026A5 +MALE AND FEMALE SIGN + +026A6 +MALE WITH STROKE SIGN + +026A7 +MALE WITH STROKE AND MALE AND FEMALE SIGN + +026A8 +VERTICAL MALE WITH STROKE SIGN + +026A9 +HORIZONTAL MALE WITH STROKE SIGN + +026AA +MEDIUM WHITE CIRCLE + +026AB +MEDIUM BLACK CIRCLE + +026AC +MEDIUM SMALL WHITE CIRCLE + +026AD +MARRIAGE SYMBOL + +026AE +DIVORCE SYMBOL + +026AF +UNMARRIED PARTNERSHIP SYMBOL + +026B0 +COFFIN + +026B1 +FUNERAL URN + +026B2 +NEUTER + +026B3 +CERES + +026B4 +PALLAS + +026B5 +JUNO + +026B6 +VESTA + +026B7 +CHIRON + +026B8 +BLACK MOON LILITH + +026B9 +SEXTILE + +026BA +SEMISEXTILE + +026BB +QUINCUNX + +026BC +SESQUIQUADRATE + +026BD +SOCCER BALL + +026BE +BASEBALL + +026BF +SQUARED KEY + +026C0 +WHITE DRAUGHTS MAN + +026C1 +WHITE DRAUGHTS KING + +026C2 +BLACK DRAUGHTS MAN + +026C3 +BLACK DRAUGHTS KING + +026C4 +SNOWMAN WITHOUT SNOW + +026C5 +SUN BEHIND CLOUD + +026C6 +RAIN + +026C7 +BLACK SNOWMAN + +026C8 +THUNDER CLOUD AND RAIN + +026C9 +TURNED WHITE SHOGI PIECE + +026CA +TURNED BLACK SHOGI PIECE + +026CB +WHITE DIAMOND IN SQUARE + +026CC +CROSSING LANES + +026CD +DISABLED CAR + +026CE +OPHIUCHUS + +026CF +PICK + +026D0 +CAR SLIDING + +026D1 +HELMET WITH WHITE CROSS + +026D2 +CIRCLED CROSSING LANES + +026D3 +CHAINS + +026D4 +NO ENTRY + +026D5 +ALTERNATE ONE-WAY LEFT WAY TRAFFIC + +026D6 +BLACK TWO-WAY LEFT WAY TRAFFIC + +026D7 +WHITE TWO-WAY LEFT WAY TRAFFIC + +026D8 +BLACK LEFT LANE MERGE + +026D9 +WHITE LEFT LANE MERGE + +026DA +DRIVE SLOW SIGN + +026DB +HEAVY WHITE DOWN-POINTING TRIANGLE + +026DC +LEFT CLOSED ENTRY + +026DD +SQUARED SALTIRE + +026DE +FALLING DIAGONAL IN WHITE CIRCLE IN BLACK SQUARE + +026DF +BLACK TRUCK + +026E0 +RESTRICTED LEFT ENTRY-1 + +026E1 +RESTRICTED LEFT ENTRY-2 + +026E2 +ASTRONOMICAL SYMBOL FOR URANUS + +026E3 +HEAVY CIRCLE WITH STROKE AND TWO DOTS ABOVE + +026E4 +PENTAGRAM + +026E5 +RIGHT-HANDED INTERLACED PENTAGRAM + +026E6 +LEFT-HANDED INTERLACED PENTAGRAM + +026E7 +INVERTED PENTAGRAM + +026E8 +BLACK CROSS ON SHIELD + +026E9 +SHINTO SHRINE + +026EA +CHURCH + +026EB +CASTLE + +026EC +HISTORIC SITE + +026ED +GEAR WITHOUT HUB + +026EE +GEAR WITH HANDLES + +026EF +MAP SYMBOL FOR LIGHTHOUSE + +026F0 +MOUNTAIN + +026F1 +UMBRELLA ON GROUND + +026F2 +FOUNTAIN + +026F3 +FLAG IN HOLE + +026F4 +FERRY + +026F5 +SAILBOAT + +026F6 +SQUARE FOUR CORNERS + +026F7 +SKIER + +026F8 +ICE SKATE + +026F9 +PERSON WITH BALL + +026FA +TENT + +026FB +JAPANESE BANK SYMBOL + +026FC +HEADSTONE GRAVEYARD SYMBOL + +026FD +FUEL PUMP + +026FE +CUP ON BLACK SQUARE + +026FF +WHITE FLAG WITH HORIZONTAL MIDDLE BLACK STRIPE + +02700 +BLACK SAFETY SCISSORS + +02701 +UPPER BLADE SCISSORS + +02702 +BLACK SCISSORS + +02703 +LOWER BLADE SCISSORS + +02704 +WHITE SCISSORS + +02705 +WHITE HEAVY CHECK MARK + +02706 +TELEPHONE LOCATION SIGN + +02707 +TAPE DRIVE + +02708 +AIRPLANE + +02709 +ENVELOPE + +0270A +RAISED FIST + +0270B +RAISED HAND + +0270C +VICTORY HAND + +0270D +WRITING HAND + +0270E +LOWER RIGHT PENCIL + +0270F +PENCIL + +02710 +UPPER RIGHT PENCIL + +02711 +WHITE NIB + +02712 +BLACK NIB + +02713 +CHECK MARK + +02714 +HEAVY CHECK MARK + +02715 +MULTIPLICATION X + +02716 +HEAVY MULTIPLICATION X + +02717 +BALLOT X + +02718 +HEAVY BALLOT X + +02719 +OUTLINED GREEK CROSS + +0271A +HEAVY GREEK CROSS + +0271B +OPEN CENTRE CROSS + +0271C +HEAVY OPEN CENTRE CROSS + +0271D +LATIN CROSS + +0271E +SHADOWED WHITE LATIN CROSS + +0271F +OUTLINED LATIN CROSS + +02720 +MALTESE CROSS + +02721 +STAR OF DAVID + +02722 +FOUR TEARDROP-SPOKED ASTERISK + +02723 +FOUR BALLOON-SPOKED ASTERISK + +02724 +HEAVY FOUR BALLOON-SPOKED ASTERISK + +02725 +FOUR CLUB-SPOKED ASTERISK + +02726 +BLACK FOUR POINTED STAR + +02727 +WHITE FOUR POINTED STAR + +02728 +SPARKLES + +02729 +STRESS OUTLINED WHITE STAR + +0272A +CIRCLED WHITE STAR + +0272B +OPEN CENTRE BLACK STAR + +0272C +BLACK CENTRE WHITE STAR + +0272D +OUTLINED BLACK STAR + +0272E +HEAVY OUTLINED BLACK STAR + +0272F +PINWHEEL STAR + +02730 +SHADOWED WHITE STAR + +02731 +HEAVY ASTERISK + +02732 +OPEN CENTRE ASTERISK + +02733 +EIGHT SPOKED ASTERISK + +02734 +EIGHT POINTED BLACK STAR + +02735 +EIGHT POINTED PINWHEEL STAR + +02736 +SIX POINTED BLACK STAR + +02737 +EIGHT POINTED RECTILINEAR BLACK STAR + +02738 +HEAVY EIGHT POINTED RECTILINEAR BLACK STAR + +02739 +TWELVE POINTED BLACK STAR + +0273A +SIXTEEN POINTED ASTERISK + +0273B +TEARDROP-SPOKED ASTERISK + +0273C +OPEN CENTRE TEARDROP-SPOKED ASTERISK + +0273D +HEAVY TEARDROP-SPOKED ASTERISK + +0273E +SIX PETALLED BLACK AND WHITE FLORETTE + +0273F +BLACK FLORETTE + +02740 +WHITE FLORETTE + +02741 +EIGHT PETALLED OUTLINED BLACK FLORETTE + +02742 +CIRCLED OPEN CENTRE EIGHT POINTED STAR + +02743 +HEAVY TEARDROP-SPOKED PINWHEEL ASTERISK + +02744 +SNOWFLAKE + +02745 +TIGHT TRIFOLIATE SNOWFLAKE + +02746 +HEAVY CHEVRON SNOWFLAKE + +02747 +SPARKLE + +02748 +HEAVY SPARKLE + +02749 +BALLOON-SPOKED ASTERISK + +0274A +EIGHT TEARDROP-SPOKED PROPELLER ASTERISK + +0274B +HEAVY EIGHT TEARDROP-SPOKED PROPELLER ASTERISK + +0274C +CROSS MARK + +0274D +SHADOWED WHITE CIRCLE + +0274E +NEGATIVE SQUARED CROSS MARK + +0274F +LOWER RIGHT DROP-SHADOWED WHITE SQUARE + +02750 +UPPER RIGHT DROP-SHADOWED WHITE SQUARE + +02751 +LOWER RIGHT SHADOWED WHITE SQUARE + +02752 +UPPER RIGHT SHADOWED WHITE SQUARE + +02753 +BLACK QUESTION MARK ORNAMENT + +02754 +WHITE QUESTION MARK ORNAMENT + +02755 +WHITE EXCLAMATION MARK ORNAMENT + +02756 +BLACK DIAMOND MINUS WHITE X + +02757 +HEAVY EXCLAMATION MARK SYMBOL + +02758 +LIGHT VERTICAL BAR + +02759 +MEDIUM VERTICAL BAR + +0275A +HEAVY VERTICAL BAR + +0275B +HEAVY SINGLE TURNED COMMA QUOTATION MARK ORNAMENT + +0275C +HEAVY SINGLE COMMA QUOTATION MARK ORNAMENT + +0275D +HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT + +0275E +HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT + +0275F +HEAVY LOW SINGLE COMMA QUOTATION MARK ORNAMENT + +02760 +HEAVY LOW DOUBLE COMMA QUOTATION MARK ORNAMENT + +02761 +CURVED STEM PARAGRAPH SIGN ORNAMENT + +02762 +HEAVY EXCLAMATION MARK ORNAMENT + +02763 +HEAVY HEART EXCLAMATION MARK ORNAMENT + +02764 +HEAVY BLACK HEART + +02765 +ROTATED HEAVY BLACK HEART BULLET + +02766 +FLORAL HEART + +02767 +ROTATED FLORAL HEART BULLET + +02768 +MEDIUM LEFT PARENTHESIS ORNAMENT + +02769 +MEDIUM RIGHT PARENTHESIS ORNAMENT + +0276A +MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT + +0276B +MEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT + +0276C +MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT + +0276D +MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT + +0276E +HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT + +0276F +HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT + +02770 +HEAVY LEFT-POINTING ANGLE BRACKET ORNAMENT + +02771 +HEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENT + +02772 +LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT + +02773 +LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT + +02774 +MEDIUM LEFT CURLY BRACKET ORNAMENT + +02775 +MEDIUM RIGHT CURLY BRACKET ORNAMENT + +02776 +DINGBAT NEGATIVE CIRCLED DIGIT ONE + +02777 +DINGBAT NEGATIVE CIRCLED DIGIT TWO + +02778 +DINGBAT NEGATIVE CIRCLED DIGIT THREE + +02779 +DINGBAT NEGATIVE CIRCLED DIGIT FOUR + +0277A +DINGBAT NEGATIVE CIRCLED DIGIT FIVE + +0277B +DINGBAT NEGATIVE CIRCLED DIGIT SIX + +0277C +DINGBAT NEGATIVE CIRCLED DIGIT SEVEN + +0277D +DINGBAT NEGATIVE CIRCLED DIGIT EIGHT + +0277E +DINGBAT NEGATIVE CIRCLED DIGIT NINE + +0277F +DINGBAT NEGATIVE CIRCLED NUMBER TEN + +02780 +DINGBAT CIRCLED SANS-SERIF DIGIT ONE + +02781 +DINGBAT CIRCLED SANS-SERIF DIGIT TWO + +02782 +DINGBAT CIRCLED SANS-SERIF DIGIT THREE + +02783 +DINGBAT CIRCLED SANS-SERIF DIGIT FOUR + +02784 +DINGBAT CIRCLED SANS-SERIF DIGIT FIVE + +02785 +DINGBAT CIRCLED SANS-SERIF DIGIT SIX + +02786 +DINGBAT CIRCLED SANS-SERIF DIGIT SEVEN + +02787 +DINGBAT CIRCLED SANS-SERIF DIGIT EIGHT + +02788 +DINGBAT CIRCLED SANS-SERIF DIGIT NINE + +02789 +DINGBAT CIRCLED SANS-SERIF NUMBER TEN + +0278A +DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ONE + +0278B +DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT TWO + +0278C +DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT THREE + +0278D +DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FOUR + +0278E +DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FIVE + +0278F +DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SIX + +02790 +DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SEVEN + +02791 +DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT EIGHT + +02792 +DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT NINE + +02793 +DINGBAT NEGATIVE CIRCLED SANS-SERIF NUMBER TEN + +02794 +HEAVY WIDE-HEADED RIGHTWARDS ARROW + +02795 +HEAVY PLUS SIGN + +02796 +HEAVY MINUS SIGN + +02797 +HEAVY DIVISION SIGN + +02798 +HEAVY SOUTH EAST ARROW + +02799 +HEAVY RIGHTWARDS ARROW + +0279A +HEAVY NORTH EAST ARROW + +0279B +DRAFTING POINT RIGHTWARDS ARROW + +0279C +HEAVY ROUND-TIPPED RIGHTWARDS ARROW + +0279D +TRIANGLE-HEADED RIGHTWARDS ARROW + +0279E +HEAVY TRIANGLE-HEADED RIGHTWARDS ARROW + +0279F +DASHED TRIANGLE-HEADED RIGHTWARDS ARROW + +027A0 +HEAVY DASHED TRIANGLE-HEADED RIGHTWARDS ARROW + +027A1 +BLACK RIGHTWARDS ARROW + +027A2 +THREE-D TOP-LIGHTED RIGHTWARDS ARROWHEAD + +027A3 +THREE-D BOTTOM-LIGHTED RIGHTWARDS ARROWHEAD + +027A4 +BLACK RIGHTWARDS ARROWHEAD + +027A5 +HEAVY BLACK CURVED DOWNWARDS AND RIGHTWARDS ARROW + +027A6 +HEAVY BLACK CURVED UPWARDS AND RIGHTWARDS ARROW + +027A7 +SQUAT BLACK RIGHTWARDS ARROW + +027A8 +HEAVY CONCAVE-POINTED BLACK RIGHTWARDS ARROW + +027A9 +RIGHT-SHADED WHITE RIGHTWARDS ARROW + +027AA +LEFT-SHADED WHITE RIGHTWARDS ARROW + +027AB +BACK-TILTED SHADOWED WHITE RIGHTWARDS ARROW + +027AC +FRONT-TILTED SHADOWED WHITE RIGHTWARDS ARROW + +027AD +HEAVY LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW + +027AE +HEAVY UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW + +027AF +NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW + +027B0 +CURLY LOOP + +027B1 +NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW + +027B2 +CIRCLED HEAVY WHITE RIGHTWARDS ARROW + +027B3 +WHITE-FEATHERED RIGHTWARDS ARROW + +027B4 +BLACK-FEATHERED SOUTH EAST ARROW + +027B5 +BLACK-FEATHERED RIGHTWARDS ARROW + +027B6 +BLACK-FEATHERED NORTH EAST ARROW + +027B7 +HEAVY BLACK-FEATHERED SOUTH EAST ARROW + +027B8 +HEAVY BLACK-FEATHERED RIGHTWARDS ARROW + +027B9 +HEAVY BLACK-FEATHERED NORTH EAST ARROW + +027BA +TEARDROP-BARBED RIGHTWARDS ARROW + +027BB +HEAVY TEARDROP-SHANKED RIGHTWARDS ARROW + +027BC +WEDGE-TAILED RIGHTWARDS ARROW + +027BD +HEAVY WEDGE-TAILED RIGHTWARDS ARROW + +027BE +OPEN-OUTLINED RIGHTWARDS ARROW + +027BF +DOUBLE CURLY LOOP + +027C0 +THREE DIMENSIONAL ANGLE + +027C1 +WHITE TRIANGLE CONTAINING SMALL WHITE TRIANGLE + +027C2 +PERPENDICULAR + +027C3 +OPEN SUBSET + +027C4 +OPEN SUPERSET + +027C5 +LEFT S-SHAPED BAG DELIMITER + +027C6 +RIGHT S-SHAPED BAG DELIMITER + +027C7 +OR WITH DOT INSIDE + +027C8 +REVERSE SOLIDUS PRECEDING SUBSET + +027C9 +SUPERSET PRECEDING SOLIDUS + +027CA +VERTICAL BAR WITH HORIZONTAL STROKE + +027CB +MATHEMATICAL RISING DIAGONAL + +027CC +LONG DIVISION + +027CD +MATHEMATICAL FALLING DIAGONAL + +027CE +SQUARED LOGICAL AND + +027CF +SQUARED LOGICAL OR + +027D0 +WHITE DIAMOND WITH CENTRED DOT + +027D1 +AND WITH DOT + +027D2 +ELEMENT OF OPENING UPWARDS + +027D3 +LOWER RIGHT CORNER WITH DOT + +027D4 +UPPER LEFT CORNER WITH DOT + +027D5 +LEFT OUTER JOIN + +027D6 +RIGHT OUTER JOIN + +027D7 +FULL OUTER JOIN + +027D8 +LARGE UP TACK + +027D9 +LARGE DOWN TACK + +027DA +LEFT AND RIGHT DOUBLE TURNSTILE + +027DB +LEFT AND RIGHT TACK + +027DC +LEFT MULTIMAP + +027DD +LONG RIGHT TACK + +027DE +LONG LEFT TACK + +027DF +UP TACK WITH CIRCLE ABOVE + +027E0 +LOZENGE DIVIDED BY HORIZONTAL RULE + +027E1 +WHITE CONCAVE-SIDED DIAMOND + +027E2 +WHITE CONCAVE-SIDED DIAMOND WITH LEFTWARDS TICK + +027E3 +WHITE CONCAVE-SIDED DIAMOND WITH RIGHTWARDS TICK + +027E4 +WHITE SQUARE WITH LEFTWARDS TICK + +027E5 +WHITE SQUARE WITH RIGHTWARDS TICK + +027E6 +MATHEMATICAL LEFT WHITE SQUARE BRACKET + +027E7 +MATHEMATICAL RIGHT WHITE SQUARE BRACKET + +027E8 +MATHEMATICAL LEFT ANGLE BRACKET + +027E9 +MATHEMATICAL RIGHT ANGLE BRACKET + +027EA +MATHEMATICAL LEFT DOUBLE ANGLE BRACKET + +027EB +MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET + +027EC +MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET + +027ED +MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET + +027EE +MATHEMATICAL LEFT FLATTENED PARENTHESIS + +027EF +MATHEMATICAL RIGHT FLATTENED PARENTHESIS + +027F0 +UPWARDS QUADRUPLE ARROW + +027F1 +DOWNWARDS QUADRUPLE ARROW + +027F2 +ANTICLOCKWISE GAPPED CIRCLE ARROW + +027F3 +CLOCKWISE GAPPED CIRCLE ARROW + +027F4 +RIGHT ARROW WITH CIRCLED PLUS + +027F5 +LONG LEFTWARDS ARROW + +027F6 +LONG RIGHTWARDS ARROW + +027F7 +LONG LEFT RIGHT ARROW + +027F8 +LONG LEFTWARDS DOUBLE ARROW + +027F9 +LONG RIGHTWARDS DOUBLE ARROW + +027FA +LONG LEFT RIGHT DOUBLE ARROW + +027FB +LONG LEFTWARDS ARROW FROM BAR + +027FC +LONG RIGHTWARDS ARROW FROM BAR + +027FD +LONG LEFTWARDS DOUBLE ARROW FROM BAR + +027FE +LONG RIGHTWARDS DOUBLE ARROW FROM BAR + +027FF +LONG RIGHTWARDS SQUIGGLE ARROW + +02800 +BRAILLE PATTERN BLANK + +02801 +BRAILLE PATTERN DOTS-1 + +02802 +BRAILLE PATTERN DOTS-2 + +02803 +BRAILLE PATTERN DOTS-12 + +02804 +BRAILLE PATTERN DOTS-3 + +02805 +BRAILLE PATTERN DOTS-13 + +02806 +BRAILLE PATTERN DOTS-23 + +02807 +BRAILLE PATTERN DOTS-123 + +02808 +BRAILLE PATTERN DOTS-4 + +02809 +BRAILLE PATTERN DOTS-14 + +0280A +BRAILLE PATTERN DOTS-24 + +0280B +BRAILLE PATTERN DOTS-124 + +0280C +BRAILLE PATTERN DOTS-34 + +0280D +BRAILLE PATTERN DOTS-134 + +0280E +BRAILLE PATTERN DOTS-234 + +0280F +BRAILLE PATTERN DOTS-1234 + +02810 +BRAILLE PATTERN DOTS-5 + +02811 +BRAILLE PATTERN DOTS-15 + +02812 +BRAILLE PATTERN DOTS-25 + +02813 +BRAILLE PATTERN DOTS-125 + +02814 +BRAILLE PATTERN DOTS-35 + +02815 +BRAILLE PATTERN DOTS-135 + +02816 +BRAILLE PATTERN DOTS-235 + +02817 +BRAILLE PATTERN DOTS-1235 + +02818 +BRAILLE PATTERN DOTS-45 + +02819 +BRAILLE PATTERN DOTS-145 + +0281A +BRAILLE PATTERN DOTS-245 + +0281B +BRAILLE PATTERN DOTS-1245 + +0281C +BRAILLE PATTERN DOTS-345 + +0281D +BRAILLE PATTERN DOTS-1345 + +0281E +BRAILLE PATTERN DOTS-2345 + +0281F +BRAILLE PATTERN DOTS-12345 + +02820 +BRAILLE PATTERN DOTS-6 + +02821 +BRAILLE PATTERN DOTS-16 + +02822 +BRAILLE PATTERN DOTS-26 + +02823 +BRAILLE PATTERN DOTS-126 + +02824 +BRAILLE PATTERN DOTS-36 + +02825 +BRAILLE PATTERN DOTS-136 + +02826 +BRAILLE PATTERN DOTS-236 + +02827 +BRAILLE PATTERN DOTS-1236 + +02828 +BRAILLE PATTERN DOTS-46 + +02829 +BRAILLE PATTERN DOTS-146 + +0282A +BRAILLE PATTERN DOTS-246 + +0282B +BRAILLE PATTERN DOTS-1246 + +0282C +BRAILLE PATTERN DOTS-346 + +0282D +BRAILLE PATTERN DOTS-1346 + +0282E +BRAILLE PATTERN DOTS-2346 + +0282F +BRAILLE PATTERN DOTS-12346 + +02830 +BRAILLE PATTERN DOTS-56 + +02831 +BRAILLE PATTERN DOTS-156 + +02832 +BRAILLE PATTERN DOTS-256 + +02833 +BRAILLE PATTERN DOTS-1256 + +02834 +BRAILLE PATTERN DOTS-356 + +02835 +BRAILLE PATTERN DOTS-1356 + +02836 +BRAILLE PATTERN DOTS-2356 + +02837 +BRAILLE PATTERN DOTS-12356 + +02838 +BRAILLE PATTERN DOTS-456 + +02839 +BRAILLE PATTERN DOTS-1456 + +0283A +BRAILLE PATTERN DOTS-2456 + +0283B +BRAILLE PATTERN DOTS-12456 + +0283C +BRAILLE PATTERN DOTS-3456 + +0283D +BRAILLE PATTERN DOTS-13456 + +0283E +BRAILLE PATTERN DOTS-23456 + +0283F +BRAILLE PATTERN DOTS-123456 + +02840 +BRAILLE PATTERN DOTS-7 + +02841 +BRAILLE PATTERN DOTS-17 + +02842 +BRAILLE PATTERN DOTS-27 + +02843 +BRAILLE PATTERN DOTS-127 + +02844 +BRAILLE PATTERN DOTS-37 + +02845 +BRAILLE PATTERN DOTS-137 + +02846 +BRAILLE PATTERN DOTS-237 + +02847 +BRAILLE PATTERN DOTS-1237 + +02848 +BRAILLE PATTERN DOTS-47 + +02849 +BRAILLE PATTERN DOTS-147 + +0284A +BRAILLE PATTERN DOTS-247 + +0284B +BRAILLE PATTERN DOTS-1247 + +0284C +BRAILLE PATTERN DOTS-347 + +0284D +BRAILLE PATTERN DOTS-1347 + +0284E +BRAILLE PATTERN DOTS-2347 + +0284F +BRAILLE PATTERN DOTS-12347 + +02850 +BRAILLE PATTERN DOTS-57 + +02851 +BRAILLE PATTERN DOTS-157 + +02852 +BRAILLE PATTERN DOTS-257 + +02853 +BRAILLE PATTERN DOTS-1257 + +02854 +BRAILLE PATTERN DOTS-357 + +02855 +BRAILLE PATTERN DOTS-1357 + +02856 +BRAILLE PATTERN DOTS-2357 + +02857 +BRAILLE PATTERN DOTS-12357 + +02858 +BRAILLE PATTERN DOTS-457 + +02859 +BRAILLE PATTERN DOTS-1457 + +0285A +BRAILLE PATTERN DOTS-2457 + +0285B +BRAILLE PATTERN DOTS-12457 + +0285C +BRAILLE PATTERN DOTS-3457 + +0285D +BRAILLE PATTERN DOTS-13457 + +0285E +BRAILLE PATTERN DOTS-23457 + +0285F +BRAILLE PATTERN DOTS-123457 + +02860 +BRAILLE PATTERN DOTS-67 + +02861 +BRAILLE PATTERN DOTS-167 + +02862 +BRAILLE PATTERN DOTS-267 + +02863 +BRAILLE PATTERN DOTS-1267 + +02864 +BRAILLE PATTERN DOTS-367 + +02865 +BRAILLE PATTERN DOTS-1367 + +02866 +BRAILLE PATTERN DOTS-2367 + +02867 +BRAILLE PATTERN DOTS-12367 + +02868 +BRAILLE PATTERN DOTS-467 + +02869 +BRAILLE PATTERN DOTS-1467 + +0286A +BRAILLE PATTERN DOTS-2467 + +0286B +BRAILLE PATTERN DOTS-12467 + +0286C +BRAILLE PATTERN DOTS-3467 + +0286D +BRAILLE PATTERN DOTS-13467 + +0286E +BRAILLE PATTERN DOTS-23467 + +0286F +BRAILLE PATTERN DOTS-123467 + +02870 +BRAILLE PATTERN DOTS-567 + +02871 +BRAILLE PATTERN DOTS-1567 + +02872 +BRAILLE PATTERN DOTS-2567 + +02873 +BRAILLE PATTERN DOTS-12567 + +02874 +BRAILLE PATTERN DOTS-3567 + +02875 +BRAILLE PATTERN DOTS-13567 + +02876 +BRAILLE PATTERN DOTS-23567 + +02877 +BRAILLE PATTERN DOTS-123567 + +02878 +BRAILLE PATTERN DOTS-4567 + +02879 +BRAILLE PATTERN DOTS-14567 + +0287A +BRAILLE PATTERN DOTS-24567 + +0287B +BRAILLE PATTERN DOTS-124567 + +0287C +BRAILLE PATTERN DOTS-34567 + +0287D +BRAILLE PATTERN DOTS-134567 + +0287E +BRAILLE PATTERN DOTS-234567 + +0287F +BRAILLE PATTERN DOTS-1234567 + +02880 +BRAILLE PATTERN DOTS-8 + +02881 +BRAILLE PATTERN DOTS-18 + +02882 +BRAILLE PATTERN DOTS-28 + +02883 +BRAILLE PATTERN DOTS-128 + +02884 +BRAILLE PATTERN DOTS-38 + +02885 +BRAILLE PATTERN DOTS-138 + +02886 +BRAILLE PATTERN DOTS-238 + +02887 +BRAILLE PATTERN DOTS-1238 + +02888 +BRAILLE PATTERN DOTS-48 + +02889 +BRAILLE PATTERN DOTS-148 + +0288A +BRAILLE PATTERN DOTS-248 + +0288B +BRAILLE PATTERN DOTS-1248 + +0288C +BRAILLE PATTERN DOTS-348 + +0288D +BRAILLE PATTERN DOTS-1348 + +0288E +BRAILLE PATTERN DOTS-2348 + +0288F +BRAILLE PATTERN DOTS-12348 + +02890 +BRAILLE PATTERN DOTS-58 + +02891 +BRAILLE PATTERN DOTS-158 + +02892 +BRAILLE PATTERN DOTS-258 + +02893 +BRAILLE PATTERN DOTS-1258 + +02894 +BRAILLE PATTERN DOTS-358 + +02895 +BRAILLE PATTERN DOTS-1358 + +02896 +BRAILLE PATTERN DOTS-2358 + +02897 +BRAILLE PATTERN DOTS-12358 + +02898 +BRAILLE PATTERN DOTS-458 + +02899 +BRAILLE PATTERN DOTS-1458 + +0289A +BRAILLE PATTERN DOTS-2458 + +0289B +BRAILLE PATTERN DOTS-12458 + +0289C +BRAILLE PATTERN DOTS-3458 + +0289D +BRAILLE PATTERN DOTS-13458 + +0289E +BRAILLE PATTERN DOTS-23458 + +0289F +BRAILLE PATTERN DOTS-123458 + +028A0 +BRAILLE PATTERN DOTS-68 + +028A1 +BRAILLE PATTERN DOTS-168 + +028A2 +BRAILLE PATTERN DOTS-268 + +028A3 +BRAILLE PATTERN DOTS-1268 + +028A4 +BRAILLE PATTERN DOTS-368 + +028A5 +BRAILLE PATTERN DOTS-1368 + +028A6 +BRAILLE PATTERN DOTS-2368 + +028A7 +BRAILLE PATTERN DOTS-12368 + +028A8 +BRAILLE PATTERN DOTS-468 + +028A9 +BRAILLE PATTERN DOTS-1468 + +028AA +BRAILLE PATTERN DOTS-2468 + +028AB +BRAILLE PATTERN DOTS-12468 + +028AC +BRAILLE PATTERN DOTS-3468 + +028AD +BRAILLE PATTERN DOTS-13468 + +028AE +BRAILLE PATTERN DOTS-23468 + +028AF +BRAILLE PATTERN DOTS-123468 + +028B0 +BRAILLE PATTERN DOTS-568 + +028B1 +BRAILLE PATTERN DOTS-1568 + +028B2 +BRAILLE PATTERN DOTS-2568 + +028B3 +BRAILLE PATTERN DOTS-12568 + +028B4 +BRAILLE PATTERN DOTS-3568 + +028B5 +BRAILLE PATTERN DOTS-13568 + +028B6 +BRAILLE PATTERN DOTS-23568 + +028B7 +BRAILLE PATTERN DOTS-123568 + +028B8 +BRAILLE PATTERN DOTS-4568 + +028B9 +BRAILLE PATTERN DOTS-14568 + +028BA +BRAILLE PATTERN DOTS-24568 + +028BB +BRAILLE PATTERN DOTS-124568 + +028BC +BRAILLE PATTERN DOTS-34568 + +028BD +BRAILLE PATTERN DOTS-134568 + +028BE +BRAILLE PATTERN DOTS-234568 + +028BF +BRAILLE PATTERN DOTS-1234568 + +028C0 +BRAILLE PATTERN DOTS-78 + +028C1 +BRAILLE PATTERN DOTS-178 + +028C2 +BRAILLE PATTERN DOTS-278 + +028C3 +BRAILLE PATTERN DOTS-1278 + +028C4 +BRAILLE PATTERN DOTS-378 + +028C5 +BRAILLE PATTERN DOTS-1378 + +028C6 +BRAILLE PATTERN DOTS-2378 + +028C7 +BRAILLE PATTERN DOTS-12378 + +028C8 +BRAILLE PATTERN DOTS-478 + +028C9 +BRAILLE PATTERN DOTS-1478 + +028CA +BRAILLE PATTERN DOTS-2478 + +028CB +BRAILLE PATTERN DOTS-12478 + +028CC +BRAILLE PATTERN DOTS-3478 + +028CD +BRAILLE PATTERN DOTS-13478 + +028CE +BRAILLE PATTERN DOTS-23478 + +028CF +BRAILLE PATTERN DOTS-123478 + +028D0 +BRAILLE PATTERN DOTS-578 + +028D1 +BRAILLE PATTERN DOTS-1578 + +028D2 +BRAILLE PATTERN DOTS-2578 + +028D3 +BRAILLE PATTERN DOTS-12578 + +028D4 +BRAILLE PATTERN DOTS-3578 + +028D5 +BRAILLE PATTERN DOTS-13578 + +028D6 +BRAILLE PATTERN DOTS-23578 + +028D7 +BRAILLE PATTERN DOTS-123578 + +028D8 +BRAILLE PATTERN DOTS-4578 + +028D9 +BRAILLE PATTERN DOTS-14578 + +028DA +BRAILLE PATTERN DOTS-24578 + +028DB +BRAILLE PATTERN DOTS-124578 + +028DC +BRAILLE PATTERN DOTS-34578 + +028DD +BRAILLE PATTERN DOTS-134578 + +028DE +BRAILLE PATTERN DOTS-234578 + +028DF +BRAILLE PATTERN DOTS-1234578 + +028E0 +BRAILLE PATTERN DOTS-678 + +028E1 +BRAILLE PATTERN DOTS-1678 + +028E2 +BRAILLE PATTERN DOTS-2678 + +028E3 +BRAILLE PATTERN DOTS-12678 + +028E4 +BRAILLE PATTERN DOTS-3678 + +028E5 +BRAILLE PATTERN DOTS-13678 + +028E6 +BRAILLE PATTERN DOTS-23678 + +028E7 +BRAILLE PATTERN DOTS-123678 + +028E8 +BRAILLE PATTERN DOTS-4678 + +028E9 +BRAILLE PATTERN DOTS-14678 + +028EA +BRAILLE PATTERN DOTS-24678 + +028EB +BRAILLE PATTERN DOTS-124678 + +028EC +BRAILLE PATTERN DOTS-34678 + +028ED +BRAILLE PATTERN DOTS-134678 + +028EE +BRAILLE PATTERN DOTS-234678 + +028EF +BRAILLE PATTERN DOTS-1234678 + +028F0 +BRAILLE PATTERN DOTS-5678 + +028F1 +BRAILLE PATTERN DOTS-15678 + +028F2 +BRAILLE PATTERN DOTS-25678 + +028F3 +BRAILLE PATTERN DOTS-125678 + +028F4 +BRAILLE PATTERN DOTS-35678 + +028F5 +BRAILLE PATTERN DOTS-135678 + +028F6 +BRAILLE PATTERN DOTS-235678 + +028F7 +BRAILLE PATTERN DOTS-1235678 + +028F8 +BRAILLE PATTERN DOTS-45678 + +028F9 +BRAILLE PATTERN DOTS-145678 + +028FA +BRAILLE PATTERN DOTS-245678 + +028FB +BRAILLE PATTERN DOTS-1245678 + +028FC +BRAILLE PATTERN DOTS-345678 + +028FD +BRAILLE PATTERN DOTS-1345678 + +028FE +BRAILLE PATTERN DOTS-2345678 + +028FF +BRAILLE PATTERN DOTS-12345678 + +02900 +RIGHTWARDS TWO-HEADED ARROW WITH VERTICAL STROKE + +02901 +RIGHTWARDS TWO-HEADED ARROW WITH DOUBLE VERTICAL STROKE + +02902 +LEFTWARDS DOUBLE ARROW WITH VERTICAL STROKE + +02903 +RIGHTWARDS DOUBLE ARROW WITH VERTICAL STROKE + +02904 +LEFT RIGHT DOUBLE ARROW WITH VERTICAL STROKE + +02905 +RIGHTWARDS TWO-HEADED ARROW FROM BAR + +02906 +LEFTWARDS DOUBLE ARROW FROM BAR + +02907 +RIGHTWARDS DOUBLE ARROW FROM BAR + +02908 +DOWNWARDS ARROW WITH HORIZONTAL STROKE + +02909 +UPWARDS ARROW WITH HORIZONTAL STROKE + +0290A +UPWARDS TRIPLE ARROW + +0290B +DOWNWARDS TRIPLE ARROW + +0290C +LEFTWARDS DOUBLE DASH ARROW + +0290D +RIGHTWARDS DOUBLE DASH ARROW + +0290E +LEFTWARDS TRIPLE DASH ARROW + +0290F +RIGHTWARDS TRIPLE DASH ARROW + +02910 +RIGHTWARDS TWO-HEADED TRIPLE DASH ARROW + +02911 +RIGHTWARDS ARROW WITH DOTTED STEM + +02912 +UPWARDS ARROW TO BAR + +02913 +DOWNWARDS ARROW TO BAR + +02914 +RIGHTWARDS ARROW WITH TAIL WITH VERTICAL STROKE + +02915 +RIGHTWARDS ARROW WITH TAIL WITH DOUBLE VERTICAL STROKE + +02916 +RIGHTWARDS TWO-HEADED ARROW WITH TAIL + +02917 +RIGHTWARDS TWO-HEADED ARROW WITH TAIL WITH VERTICAL STROKE + +02918 +RIGHTWARDS TWO-HEADED ARROW WITH TAIL WITH DOUBLE VERTICAL STROKE + +02919 +LEFTWARDS ARROW-TAIL + +0291A +RIGHTWARDS ARROW-TAIL + +0291B +LEFTWARDS DOUBLE ARROW-TAIL + +0291C +RIGHTWARDS DOUBLE ARROW-TAIL + +0291D +LEFTWARDS ARROW TO BLACK DIAMOND + +0291E +RIGHTWARDS ARROW TO BLACK DIAMOND + +0291F +LEFTWARDS ARROW FROM BAR TO BLACK DIAMOND + +02920 +RIGHTWARDS ARROW FROM BAR TO BLACK DIAMOND + +02921 +NORTH WEST AND SOUTH EAST ARROW + +02922 +NORTH EAST AND SOUTH WEST ARROW + +02923 +NORTH WEST ARROW WITH HOOK + +02924 +NORTH EAST ARROW WITH HOOK + +02925 +SOUTH EAST ARROW WITH HOOK + +02926 +SOUTH WEST ARROW WITH HOOK + +02927 +NORTH WEST ARROW AND NORTH EAST ARROW + +02928 +NORTH EAST ARROW AND SOUTH EAST ARROW + +02929 +SOUTH EAST ARROW AND SOUTH WEST ARROW + +0292A +SOUTH WEST ARROW AND NORTH WEST ARROW + +0292B +RISING DIAGONAL CROSSING FALLING DIAGONAL + +0292C +FALLING DIAGONAL CROSSING RISING DIAGONAL + +0292D +SOUTH EAST ARROW CROSSING NORTH EAST ARROW + +0292E +NORTH EAST ARROW CROSSING SOUTH EAST ARROW + +0292F +FALLING DIAGONAL CROSSING NORTH EAST ARROW + +02930 +RISING DIAGONAL CROSSING SOUTH EAST ARROW + +02931 +NORTH EAST ARROW CROSSING NORTH WEST ARROW + +02932 +NORTH WEST ARROW CROSSING NORTH EAST ARROW + +02933 +WAVE ARROW POINTING DIRECTLY RIGHT + +02934 +ARROW POINTING RIGHTWARDS THEN CURVING UPWARDS + +02935 +ARROW POINTING RIGHTWARDS THEN CURVING DOWNWARDS + +02936 +ARROW POINTING DOWNWARDS THEN CURVING LEFTWARDS + +02937 +ARROW POINTING DOWNWARDS THEN CURVING RIGHTWARDS + +02938 +RIGHT-SIDE ARC CLOCKWISE ARROW + +02939 +LEFT-SIDE ARC ANTICLOCKWISE ARROW + +0293A +TOP ARC ANTICLOCKWISE ARROW + +0293B +BOTTOM ARC ANTICLOCKWISE ARROW + +0293C +TOP ARC CLOCKWISE ARROW WITH MINUS + +0293D +TOP ARC ANTICLOCKWISE ARROW WITH PLUS + +0293E +LOWER RIGHT SEMICIRCULAR CLOCKWISE ARROW + +0293F +LOWER LEFT SEMICIRCULAR ANTICLOCKWISE ARROW + +02940 +ANTICLOCKWISE CLOSED CIRCLE ARROW + +02941 +CLOCKWISE CLOSED CIRCLE ARROW + +02942 +RIGHTWARDS ARROW ABOVE SHORT LEFTWARDS ARROW + +02943 +LEFTWARDS ARROW ABOVE SHORT RIGHTWARDS ARROW + +02944 +SHORT RIGHTWARDS ARROW ABOVE LEFTWARDS ARROW + +02945 +RIGHTWARDS ARROW WITH PLUS BELOW + +02946 +LEFTWARDS ARROW WITH PLUS BELOW + +02947 +RIGHTWARDS ARROW THROUGH X + +02948 +LEFT RIGHT ARROW THROUGH SMALL CIRCLE + +02949 +UPWARDS TWO-HEADED ARROW FROM SMALL CIRCLE + +0294A +LEFT BARB UP RIGHT BARB DOWN HARPOON + +0294B +LEFT BARB DOWN RIGHT BARB UP HARPOON + +0294C +UP BARB RIGHT DOWN BARB LEFT HARPOON + +0294D +UP BARB LEFT DOWN BARB RIGHT HARPOON + +0294E +LEFT BARB UP RIGHT BARB UP HARPOON + +0294F +UP BARB RIGHT DOWN BARB RIGHT HARPOON + +02950 +LEFT BARB DOWN RIGHT BARB DOWN HARPOON + +02951 +UP BARB LEFT DOWN BARB LEFT HARPOON + +02952 +LEFTWARDS HARPOON WITH BARB UP TO BAR + +02953 +RIGHTWARDS HARPOON WITH BARB UP TO BAR + +02954 +UPWARDS HARPOON WITH BARB RIGHT TO BAR + +02955 +DOWNWARDS HARPOON WITH BARB RIGHT TO BAR + +02956 +LEFTWARDS HARPOON WITH BARB DOWN TO BAR + +02957 +RIGHTWARDS HARPOON WITH BARB DOWN TO BAR + +02958 +UPWARDS HARPOON WITH BARB LEFT TO BAR + +02959 +DOWNWARDS HARPOON WITH BARB LEFT TO BAR + +0295A +LEFTWARDS HARPOON WITH BARB UP FROM BAR + +0295B +RIGHTWARDS HARPOON WITH BARB UP FROM BAR + +0295C +UPWARDS HARPOON WITH BARB RIGHT FROM BAR + +0295D +DOWNWARDS HARPOON WITH BARB RIGHT FROM BAR + +0295E +LEFTWARDS HARPOON WITH BARB DOWN FROM BAR + +0295F +RIGHTWARDS HARPOON WITH BARB DOWN FROM BAR + +02960 +UPWARDS HARPOON WITH BARB LEFT FROM BAR + +02961 +DOWNWARDS HARPOON WITH BARB LEFT FROM BAR + +02962 +LEFTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB DOWN + +02963 +UPWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT + +02964 +RIGHTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB DOWN + +02965 +DOWNWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT + +02966 +LEFTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB UP + +02967 +LEFTWARDS HARPOON WITH BARB DOWN ABOVE RIGHTWARDS HARPOON WITH BARB DOWN + +02968 +RIGHTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB UP + +02969 +RIGHTWARDS HARPOON WITH BARB DOWN ABOVE LEFTWARDS HARPOON WITH BARB DOWN + +0296A +LEFTWARDS HARPOON WITH BARB UP ABOVE LONG DASH + +0296B +LEFTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH + +0296C +RIGHTWARDS HARPOON WITH BARB UP ABOVE LONG DASH + +0296D +RIGHTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH + +0296E +UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT + +0296F +DOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT + +02970 +RIGHT DOUBLE ARROW WITH ROUNDED HEAD + +02971 +EQUALS SIGN ABOVE RIGHTWARDS ARROW + +02972 +TILDE OPERATOR ABOVE RIGHTWARDS ARROW + +02973 +LEFTWARDS ARROW ABOVE TILDE OPERATOR + +02974 +RIGHTWARDS ARROW ABOVE TILDE OPERATOR + +02975 +RIGHTWARDS ARROW ABOVE ALMOST EQUAL TO + +02976 +LESS-THAN ABOVE LEFTWARDS ARROW + +02977 +LEFTWARDS ARROW THROUGH LESS-THAN + +02978 +GREATER-THAN ABOVE RIGHTWARDS ARROW + +02979 +SUBSET ABOVE RIGHTWARDS ARROW + +0297A +LEFTWARDS ARROW THROUGH SUBSET + +0297B +SUPERSET ABOVE LEFTWARDS ARROW + +0297C +LEFT FISH TAIL + +0297D +RIGHT FISH TAIL + +0297E +UP FISH TAIL + +0297F +DOWN FISH TAIL + +02980 +TRIPLE VERTICAL BAR DELIMITER + +02981 +Z NOTATION SPOT + +02982 +Z NOTATION TYPE COLON + +02983 +LEFT WHITE CURLY BRACKET + +02984 +RIGHT WHITE CURLY BRACKET + +02985 +LEFT WHITE PARENTHESIS + +02986 +RIGHT WHITE PARENTHESIS + +02987 +Z NOTATION LEFT IMAGE BRACKET + +02988 +Z NOTATION RIGHT IMAGE BRACKET + +02989 +Z NOTATION LEFT BINDING BRACKET + +0298A +Z NOTATION RIGHT BINDING BRACKET + +0298B +LEFT SQUARE BRACKET WITH UNDERBAR + +0298C +RIGHT SQUARE BRACKET WITH UNDERBAR + +0298D +LEFT SQUARE BRACKET WITH TICK IN TOP CORNER + +0298E +RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER + +0298F +LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER + +02990 +RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER + +02991 +LEFT ANGLE BRACKET WITH DOT + +02992 +RIGHT ANGLE BRACKET WITH DOT + +02993 +LEFT ARC LESS-THAN BRACKET + +02994 +RIGHT ARC GREATER-THAN BRACKET + +02995 +DOUBLE LEFT ARC GREATER-THAN BRACKET + +02996 +DOUBLE RIGHT ARC LESS-THAN BRACKET + +02997 +LEFT BLACK TORTOISE SHELL BRACKET + +02998 +RIGHT BLACK TORTOISE SHELL BRACKET + +02999 +DOTTED FENCE + +0299A +VERTICAL ZIGZAG LINE + +0299B +MEASURED ANGLE OPENING LEFT + +0299C +RIGHT ANGLE VARIANT WITH SQUARE + +0299D +MEASURED RIGHT ANGLE WITH DOT + +0299E +ANGLE WITH S INSIDE + +0299F +ACUTE ANGLE + +029A0 +SPHERICAL ANGLE OPENING LEFT + +029A1 +SPHERICAL ANGLE OPENING UP + +029A2 +TURNED ANGLE + +029A3 +REVERSED ANGLE + +029A4 +ANGLE WITH UNDERBAR + +029A5 +REVERSED ANGLE WITH UNDERBAR + +029A6 +OBLIQUE ANGLE OPENING UP + +029A7 +OBLIQUE ANGLE OPENING DOWN + +029A8 +MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND RIGHT + +029A9 +MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND LEFT + +029AA +MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND RIGHT + +029AB +MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND LEFT + +029AC +MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND UP + +029AD +MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND UP + +029AE +MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND DOWN + +029AF +MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND DOWN + +029B0 +REVERSED EMPTY SET + +029B1 +EMPTY SET WITH OVERBAR + +029B2 +EMPTY SET WITH SMALL CIRCLE ABOVE + +029B3 +EMPTY SET WITH RIGHT ARROW ABOVE + +029B4 +EMPTY SET WITH LEFT ARROW ABOVE + +029B5 +CIRCLE WITH HORIZONTAL BAR + +029B6 +CIRCLED VERTICAL BAR + +029B7 +CIRCLED PARALLEL + +029B8 +CIRCLED REVERSE SOLIDUS + +029B9 +CIRCLED PERPENDICULAR + +029BA +CIRCLE DIVIDED BY HORIZONTAL BAR AND TOP HALF DIVIDED BY VERTICAL BAR + +029BB +CIRCLE WITH SUPERIMPOSED X + +029BC +CIRCLED ANTICLOCKWISE-ROTATED DIVISION SIGN + +029BD +UP ARROW THROUGH CIRCLE + +029BE +CIRCLED WHITE BULLET + +029BF +CIRCLED BULLET + +029C0 +CIRCLED LESS-THAN + +029C1 +CIRCLED GREATER-THAN + +029C2 +CIRCLE WITH SMALL CIRCLE TO THE RIGHT + +029C3 +CIRCLE WITH TWO HORIZONTAL STROKES TO THE RIGHT + +029C4 +SQUARED RISING DIAGONAL SLASH + +029C5 +SQUARED FALLING DIAGONAL SLASH + +029C6 +SQUARED ASTERISK + +029C7 +SQUARED SMALL CIRCLE + +029C8 +SQUARED SQUARE + +029C9 +TWO JOINED SQUARES + +029CA +TRIANGLE WITH DOT ABOVE + +029CB +TRIANGLE WITH UNDERBAR + +029CC +S IN TRIANGLE + +029CD +TRIANGLE WITH SERIFS AT BOTTOM + +029CE +RIGHT TRIANGLE ABOVE LEFT TRIANGLE + +029CF +LEFT TRIANGLE BESIDE VERTICAL BAR + +029D0 +VERTICAL BAR BESIDE RIGHT TRIANGLE + +029D1 +BOWTIE WITH LEFT HALF BLACK + +029D2 +BOWTIE WITH RIGHT HALF BLACK + +029D3 +BLACK BOWTIE + +029D4 +TIMES WITH LEFT HALF BLACK + +029D5 +TIMES WITH RIGHT HALF BLACK + +029D6 +WHITE HOURGLASS + +029D7 +BLACK HOURGLASS + +029D8 +LEFT WIGGLY FENCE + +029D9 +RIGHT WIGGLY FENCE + +029DA +LEFT DOUBLE WIGGLY FENCE + +029DB +RIGHT DOUBLE WIGGLY FENCE + +029DC +INCOMPLETE INFINITY + +029DD +TIE OVER INFINITY + +029DE +INFINITY NEGATED WITH VERTICAL BAR + +029DF +DOUBLE-ENDED MULTIMAP + +029E0 +SQUARE WITH CONTOURED OUTLINE + +029E1 +INCREASES AS + +029E2 +SHUFFLE PRODUCT + +029E3 +EQUALS SIGN AND SLANTED PARALLEL + +029E4 +EQUALS SIGN AND SLANTED PARALLEL WITH TILDE ABOVE + +029E5 +IDENTICAL TO AND SLANTED PARALLEL + +029E6 +GLEICH STARK + +029E7 +THERMODYNAMIC + +029E8 +DOWN-POINTING TRIANGLE WITH LEFT HALF BLACK + +029E9 +DOWN-POINTING TRIANGLE WITH RIGHT HALF BLACK + +029EA +BLACK DIAMOND WITH DOWN ARROW + +029EB +BLACK LOZENGE + +029EC +WHITE CIRCLE WITH DOWN ARROW + +029ED +BLACK CIRCLE WITH DOWN ARROW + +029EE +ERROR-BARRED WHITE SQUARE + +029EF +ERROR-BARRED BLACK SQUARE + +029F0 +ERROR-BARRED WHITE DIAMOND + +029F1 +ERROR-BARRED BLACK DIAMOND + +029F2 +ERROR-BARRED WHITE CIRCLE + +029F3 +ERROR-BARRED BLACK CIRCLE + +029F4 +RULE-DELAYED + +029F5 +REVERSE SOLIDUS OPERATOR + +029F6 +SOLIDUS WITH OVERBAR + +029F7 +REVERSE SOLIDUS WITH HORIZONTAL STROKE + +029F8 +BIG SOLIDUS + +029F9 +BIG REVERSE SOLIDUS + +029FA +DOUBLE PLUS + +029FB +TRIPLE PLUS + +029FC +LEFT-POINTING CURVED ANGLE BRACKET + +029FD +RIGHT-POINTING CURVED ANGLE BRACKET + +029FE +TINY + +029FF +MINY + +02A00 +N-ARY CIRCLED DOT OPERATOR + +02A01 +N-ARY CIRCLED PLUS OPERATOR + +02A02 +N-ARY CIRCLED TIMES OPERATOR + +02A03 +N-ARY UNION OPERATOR WITH DOT + +02A04 +N-ARY UNION OPERATOR WITH PLUS + +02A05 +N-ARY SQUARE INTERSECTION OPERATOR + +02A06 +N-ARY SQUARE UNION OPERATOR + +02A07 +TWO LOGICAL AND OPERATOR + +02A08 +TWO LOGICAL OR OPERATOR + +02A09 +N-ARY TIMES OPERATOR + +02A0A +MODULO TWO SUM + +02A0B +SUMMATION WITH INTEGRAL + +02A0C +QUADRUPLE INTEGRAL OPERATOR + +02A0D +FINITE PART INTEGRAL + +02A0E +INTEGRAL WITH DOUBLE STROKE + +02A0F +INTEGRAL AVERAGE WITH SLASH + +02A10 +CIRCULATION FUNCTION + +02A11 +ANTICLOCKWISE INTEGRATION + +02A12 +LINE INTEGRATION WITH RECTANGULAR PATH AROUND POLE + +02A13 +LINE INTEGRATION WITH SEMICIRCULAR PATH AROUND POLE + +02A14 +LINE INTEGRATION NOT INCLUDING THE POLE + +02A15 +INTEGRAL AROUND A POINT OPERATOR + +02A16 +QUATERNION INTEGRAL OPERATOR + +02A17 +INTEGRAL WITH LEFTWARDS ARROW WITH HOOK + +02A18 +INTEGRAL WITH TIMES SIGN + +02A19 +INTEGRAL WITH INTERSECTION + +02A1A +INTEGRAL WITH UNION + +02A1B +INTEGRAL WITH OVERBAR + +02A1C +INTEGRAL WITH UNDERBAR + +02A1D +JOIN + +02A1E +LARGE LEFT TRIANGLE OPERATOR + +02A1F +Z NOTATION SCHEMA COMPOSITION + +02A20 +Z NOTATION SCHEMA PIPING + +02A21 +Z NOTATION SCHEMA PROJECTION + +02A22 +PLUS SIGN WITH SMALL CIRCLE ABOVE + +02A23 +PLUS SIGN WITH CIRCUMFLEX ACCENT ABOVE + +02A24 +PLUS SIGN WITH TILDE ABOVE + +02A25 +PLUS SIGN WITH DOT BELOW + +02A26 +PLUS SIGN WITH TILDE BELOW + +02A27 +PLUS SIGN WITH SUBSCRIPT TWO + +02A28 +PLUS SIGN WITH BLACK TRIANGLE + +02A29 +MINUS SIGN WITH COMMA ABOVE + +02A2A +MINUS SIGN WITH DOT BELOW + +02A2B +MINUS SIGN WITH FALLING DOTS + +02A2C +MINUS SIGN WITH RISING DOTS + +02A2D +PLUS SIGN IN LEFT HALF CIRCLE + +02A2E +PLUS SIGN IN RIGHT HALF CIRCLE + +02A2F +VECTOR OR CROSS PRODUCT + +02A30 +MULTIPLICATION SIGN WITH DOT ABOVE + +02A31 +MULTIPLICATION SIGN WITH UNDERBAR + +02A32 +SEMIDIRECT PRODUCT WITH BOTTOM CLOSED + +02A33 +SMASH PRODUCT + +02A34 +MULTIPLICATION SIGN IN LEFT HALF CIRCLE + +02A35 +MULTIPLICATION SIGN IN RIGHT HALF CIRCLE + +02A36 +CIRCLED MULTIPLICATION SIGN WITH CIRCUMFLEX ACCENT + +02A37 +MULTIPLICATION SIGN IN DOUBLE CIRCLE + +02A38 +CIRCLED DIVISION SIGN + +02A39 +PLUS SIGN IN TRIANGLE + +02A3A +MINUS SIGN IN TRIANGLE + +02A3B +MULTIPLICATION SIGN IN TRIANGLE + +02A3C +INTERIOR PRODUCT + +02A3D +RIGHTHAND INTERIOR PRODUCT + +02A3E +Z NOTATION RELATIONAL COMPOSITION + +02A3F +AMALGAMATION OR COPRODUCT + +02A40 +INTERSECTION WITH DOT + +02A41 +UNION WITH MINUS SIGN + +02A42 +UNION WITH OVERBAR + +02A43 +INTERSECTION WITH OVERBAR + +02A44 +INTERSECTION WITH LOGICAL AND + +02A45 +UNION WITH LOGICAL OR + +02A46 +UNION ABOVE INTERSECTION + +02A47 +INTERSECTION ABOVE UNION + +02A48 +UNION ABOVE BAR ABOVE INTERSECTION + +02A49 +INTERSECTION ABOVE BAR ABOVE UNION + +02A4A +UNION BESIDE AND JOINED WITH UNION + +02A4B +INTERSECTION BESIDE AND JOINED WITH INTERSECTION + +02A4C +CLOSED UNION WITH SERIFS + +02A4D +CLOSED INTERSECTION WITH SERIFS + +02A4E +DOUBLE SQUARE INTERSECTION + +02A4F +DOUBLE SQUARE UNION + +02A50 +CLOSED UNION WITH SERIFS AND SMASH PRODUCT + +02A51 +LOGICAL AND WITH DOT ABOVE + +02A52 +LOGICAL OR WITH DOT ABOVE + +02A53 +DOUBLE LOGICAL AND + +02A54 +DOUBLE LOGICAL OR + +02A55 +TWO INTERSECTING LOGICAL AND + +02A56 +TWO INTERSECTING LOGICAL OR + +02A57 +SLOPING LARGE OR + +02A58 +SLOPING LARGE AND + +02A59 +LOGICAL OR OVERLAPPING LOGICAL AND + +02A5A +LOGICAL AND WITH MIDDLE STEM + +02A5B +LOGICAL OR WITH MIDDLE STEM + +02A5C +LOGICAL AND WITH HORIZONTAL DASH + +02A5D +LOGICAL OR WITH HORIZONTAL DASH + +02A5E +LOGICAL AND WITH DOUBLE OVERBAR + +02A5F +LOGICAL AND WITH UNDERBAR + +02A60 +LOGICAL AND WITH DOUBLE UNDERBAR + +02A61 +SMALL VEE WITH UNDERBAR + +02A62 +LOGICAL OR WITH DOUBLE OVERBAR + +02A63 +LOGICAL OR WITH DOUBLE UNDERBAR + +02A64 +Z NOTATION DOMAIN ANTIRESTRICTION + +02A65 +Z NOTATION RANGE ANTIRESTRICTION + +02A66 +EQUALS SIGN WITH DOT BELOW + +02A67 +IDENTICAL WITH DOT ABOVE + +02A68 +TRIPLE HORIZONTAL BAR WITH DOUBLE VERTICAL STROKE + +02A69 +TRIPLE HORIZONTAL BAR WITH TRIPLE VERTICAL STROKE + +02A6A +TILDE OPERATOR WITH DOT ABOVE + +02A6B +TILDE OPERATOR WITH RISING DOTS + +02A6C +SIMILAR MINUS SIMILAR + +02A6D +CONGRUENT WITH DOT ABOVE + +02A6E +EQUALS WITH ASTERISK + +02A6F +ALMOST EQUAL TO WITH CIRCUMFLEX ACCENT + +02A70 +APPROXIMATELY EQUAL OR EQUAL TO + +02A71 +EQUALS SIGN ABOVE PLUS SIGN + +02A72 +PLUS SIGN ABOVE EQUALS SIGN + +02A73 +EQUALS SIGN ABOVE TILDE OPERATOR + +02A74 +DOUBLE COLON EQUAL + +02A75 +TWO CONSECUTIVE EQUALS SIGNS + +02A76 +THREE CONSECUTIVE EQUALS SIGNS + +02A77 +EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW + +02A78 +EQUIVALENT WITH FOUR DOTS ABOVE + +02A79 +LESS-THAN WITH CIRCLE INSIDE + +02A7A +GREATER-THAN WITH CIRCLE INSIDE + +02A7B +LESS-THAN WITH QUESTION MARK ABOVE + +02A7C +GREATER-THAN WITH QUESTION MARK ABOVE + +02A7D +LESS-THAN OR SLANTED EQUAL TO + +02A7E +GREATER-THAN OR SLANTED EQUAL TO + +02A7F +LESS-THAN OR SLANTED EQUAL TO WITH DOT INSIDE + +02A80 +GREATER-THAN OR SLANTED EQUAL TO WITH DOT INSIDE + +02A81 +LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE + +02A82 +GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE + +02A83 +LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE RIGHT + +02A84 +GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE LEFT + +02A85 +LESS-THAN OR APPROXIMATE + +02A86 +GREATER-THAN OR APPROXIMATE + +02A87 +LESS-THAN AND SINGLE-LINE NOT EQUAL TO + +02A88 +GREATER-THAN AND SINGLE-LINE NOT EQUAL TO + +02A89 +LESS-THAN AND NOT APPROXIMATE + +02A8A +GREATER-THAN AND NOT APPROXIMATE + +02A8B +LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN + +02A8C +GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN + +02A8D +LESS-THAN ABOVE SIMILAR OR EQUAL + +02A8E +GREATER-THAN ABOVE SIMILAR OR EQUAL + +02A8F +LESS-THAN ABOVE SIMILAR ABOVE GREATER-THAN + +02A90 +GREATER-THAN ABOVE SIMILAR ABOVE LESS-THAN + +02A91 +LESS-THAN ABOVE GREATER-THAN ABOVE DOUBLE-LINE EQUAL + +02A92 +GREATER-THAN ABOVE LESS-THAN ABOVE DOUBLE-LINE EQUAL + +02A93 +LESS-THAN ABOVE SLANTED EQUAL ABOVE GREATER-THAN ABOVE SLANTED EQUAL + +02A94 +GREATER-THAN ABOVE SLANTED EQUAL ABOVE LESS-THAN ABOVE SLANTED EQUAL + +02A95 +SLANTED EQUAL TO OR LESS-THAN + +02A96 +SLANTED EQUAL TO OR GREATER-THAN + +02A97 +SLANTED EQUAL TO OR LESS-THAN WITH DOT INSIDE + +02A98 +SLANTED EQUAL TO OR GREATER-THAN WITH DOT INSIDE + +02A99 +DOUBLE-LINE EQUAL TO OR LESS-THAN + +02A9A +DOUBLE-LINE EQUAL TO OR GREATER-THAN + +02A9B +DOUBLE-LINE SLANTED EQUAL TO OR LESS-THAN + +02A9C +DOUBLE-LINE SLANTED EQUAL TO OR GREATER-THAN + +02A9D +SIMILAR OR LESS-THAN + +02A9E +SIMILAR OR GREATER-THAN + +02A9F +SIMILAR ABOVE LESS-THAN ABOVE EQUALS SIGN + +02AA0 +SIMILAR ABOVE GREATER-THAN ABOVE EQUALS SIGN + +02AA1 +DOUBLE NESTED LESS-THAN + +02AA2 +DOUBLE NESTED GREATER-THAN + +02AA3 +DOUBLE NESTED LESS-THAN WITH UNDERBAR + +02AA4 +GREATER-THAN OVERLAPPING LESS-THAN + +02AA5 +GREATER-THAN BESIDE LESS-THAN + +02AA6 +LESS-THAN CLOSED BY CURVE + +02AA7 +GREATER-THAN CLOSED BY CURVE + +02AA8 +LESS-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL + +02AA9 +GREATER-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL + +02AAA +SMALLER THAN + +02AAB +LARGER THAN + +02AAC +SMALLER THAN OR EQUAL TO + +02AAD +LARGER THAN OR EQUAL TO + +02AAE +EQUALS SIGN WITH BUMPY ABOVE + +02AAF +PRECEDES ABOVE SINGLE-LINE EQUALS SIGN + +02AB0 +SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN + +02AB1 +PRECEDES ABOVE SINGLE-LINE NOT EQUAL TO + +02AB2 +SUCCEEDS ABOVE SINGLE-LINE NOT EQUAL TO + +02AB3 +PRECEDES ABOVE EQUALS SIGN + +02AB4 +SUCCEEDS ABOVE EQUALS SIGN + +02AB5 +PRECEDES ABOVE NOT EQUAL TO + +02AB6 +SUCCEEDS ABOVE NOT EQUAL TO + +02AB7 +PRECEDES ABOVE ALMOST EQUAL TO + +02AB8 +SUCCEEDS ABOVE ALMOST EQUAL TO + +02AB9 +PRECEDES ABOVE NOT ALMOST EQUAL TO + +02ABA +SUCCEEDS ABOVE NOT ALMOST EQUAL TO + +02ABB +DOUBLE PRECEDES + +02ABC +DOUBLE SUCCEEDS + +02ABD +SUBSET WITH DOT + +02ABE +SUPERSET WITH DOT + +02ABF +SUBSET WITH PLUS SIGN BELOW + +02AC0 +SUPERSET WITH PLUS SIGN BELOW + +02AC1 +SUBSET WITH MULTIPLICATION SIGN BELOW + +02AC2 +SUPERSET WITH MULTIPLICATION SIGN BELOW + +02AC3 +SUBSET OF OR EQUAL TO WITH DOT ABOVE + +02AC4 +SUPERSET OF OR EQUAL TO WITH DOT ABOVE + +02AC5 +SUBSET OF ABOVE EQUALS SIGN + +02AC6 +SUPERSET OF ABOVE EQUALS SIGN + +02AC7 +SUBSET OF ABOVE TILDE OPERATOR + +02AC8 +SUPERSET OF ABOVE TILDE OPERATOR + +02AC9 +SUBSET OF ABOVE ALMOST EQUAL TO + +02ACA +SUPERSET OF ABOVE ALMOST EQUAL TO + +02ACB +SUBSET OF ABOVE NOT EQUAL TO + +02ACC +SUPERSET OF ABOVE NOT EQUAL TO + +02ACD +SQUARE LEFT OPEN BOX OPERATOR + +02ACE +SQUARE RIGHT OPEN BOX OPERATOR + +02ACF +CLOSED SUBSET + +02AD0 +CLOSED SUPERSET + +02AD1 +CLOSED SUBSET OR EQUAL TO + +02AD2 +CLOSED SUPERSET OR EQUAL TO + +02AD3 +SUBSET ABOVE SUPERSET + +02AD4 +SUPERSET ABOVE SUBSET + +02AD5 +SUBSET ABOVE SUBSET + +02AD6 +SUPERSET ABOVE SUPERSET + +02AD7 +SUPERSET BESIDE SUBSET + +02AD8 +SUPERSET BESIDE AND JOINED BY DASH WITH SUBSET + +02AD9 +ELEMENT OF OPENING DOWNWARDS + +02ADA +PITCHFORK WITH TEE TOP + +02ADB +TRANSVERSAL INTERSECTION + +02ADC +FORKING + +02ADD +NONFORKING + +02ADE +SHORT LEFT TACK + +02ADF +SHORT DOWN TACK + +02AE0 +SHORT UP TACK + +02AE1 +PERPENDICULAR WITH S + +02AE2 +VERTICAL BAR TRIPLE RIGHT TURNSTILE + +02AE3 +DOUBLE VERTICAL BAR LEFT TURNSTILE + +02AE4 +VERTICAL BAR DOUBLE LEFT TURNSTILE + +02AE5 +DOUBLE VERTICAL BAR DOUBLE LEFT TURNSTILE + +02AE6 +LONG DASH FROM LEFT MEMBER OF DOUBLE VERTICAL + +02AE7 +SHORT DOWN TACK WITH OVERBAR + +02AE8 +SHORT UP TACK WITH UNDERBAR + +02AE9 +SHORT UP TACK ABOVE SHORT DOWN TACK + +02AEA +DOUBLE DOWN TACK + +02AEB +DOUBLE UP TACK + +02AEC +DOUBLE STROKE NOT SIGN + +02AED +REVERSED DOUBLE STROKE NOT SIGN + +02AEE +DOES NOT DIVIDE WITH REVERSED NEGATION SLASH + +02AEF +VERTICAL LINE WITH CIRCLE ABOVE + +02AF0 +VERTICAL LINE WITH CIRCLE BELOW + +02AF1 +DOWN TACK WITH CIRCLE BELOW + +02AF2 +PARALLEL WITH HORIZONTAL STROKE + +02AF3 +PARALLEL WITH TILDE OPERATOR + +02AF4 +TRIPLE VERTICAL BAR BINARY RELATION + +02AF5 +TRIPLE VERTICAL BAR WITH HORIZONTAL STROKE + +02AF6 +TRIPLE COLON OPERATOR + +02AF7 +TRIPLE NESTED LESS-THAN + +02AF8 +TRIPLE NESTED GREATER-THAN + +02AF9 +DOUBLE-LINE SLANTED LESS-THAN OR EQUAL TO + +02AFA +DOUBLE-LINE SLANTED GREATER-THAN OR EQUAL TO + +02AFB +TRIPLE SOLIDUS BINARY RELATION + +02AFC +LARGE TRIPLE VERTICAL BAR OPERATOR + +02AFD +DOUBLE SOLIDUS OPERATOR + +02AFE +WHITE VERTICAL BAR + +02AFF +N-ARY WHITE VERTICAL BAR + +02B00 +NORTH EAST WHITE ARROW + +02B01 +NORTH WEST WHITE ARROW + +02B02 +SOUTH EAST WHITE ARROW + +02B03 +SOUTH WEST WHITE ARROW + +02B04 +LEFT RIGHT WHITE ARROW + +02B05 +LEFTWARDS BLACK ARROW + +02B06 +UPWARDS BLACK ARROW + +02B07 +DOWNWARDS BLACK ARROW + +02B08 +NORTH EAST BLACK ARROW + +02B09 +NORTH WEST BLACK ARROW + +02B0A +SOUTH EAST BLACK ARROW + +02B0B +SOUTH WEST BLACK ARROW + +02B0C +LEFT RIGHT BLACK ARROW + +02B0D +UP DOWN BLACK ARROW + +02B0E +RIGHTWARDS ARROW WITH TIP DOWNWARDS + +02B0F +RIGHTWARDS ARROW WITH TIP UPWARDS + +02B10 +LEFTWARDS ARROW WITH TIP DOWNWARDS + +02B11 +LEFTWARDS ARROW WITH TIP UPWARDS + +02B12 +SQUARE WITH TOP HALF BLACK + +02B13 +SQUARE WITH BOTTOM HALF BLACK + +02B14 +SQUARE WITH UPPER RIGHT DIAGONAL HALF BLACK + +02B15 +SQUARE WITH LOWER LEFT DIAGONAL HALF BLACK + +02B16 +DIAMOND WITH LEFT HALF BLACK + +02B17 +DIAMOND WITH RIGHT HALF BLACK + +02B18 +DIAMOND WITH TOP HALF BLACK + +02B19 +DIAMOND WITH BOTTOM HALF BLACK + +02B1A +DOTTED SQUARE + +02B1B +BLACK LARGE SQUARE + +02B1C +WHITE LARGE SQUARE + +02B1D +BLACK VERY SMALL SQUARE + +02B1E +WHITE VERY SMALL SQUARE + +02B1F +BLACK PENTAGON + +02B20 +WHITE PENTAGON + +02B21 +WHITE HEXAGON + +02B22 +BLACK HEXAGON + +02B23 +HORIZONTAL BLACK HEXAGON + +02B24 +BLACK LARGE CIRCLE + +02B25 +BLACK MEDIUM DIAMOND + +02B26 +WHITE MEDIUM DIAMOND + +02B27 +BLACK MEDIUM LOZENGE + +02B28 +WHITE MEDIUM LOZENGE + +02B29 +BLACK SMALL DIAMOND + +02B2A +BLACK SMALL LOZENGE + +02B2B +WHITE SMALL LOZENGE + +02B2C +BLACK HORIZONTAL ELLIPSE + +02B2D +WHITE HORIZONTAL ELLIPSE + +02B2E +BLACK VERTICAL ELLIPSE + +02B2F +WHITE VERTICAL ELLIPSE + +02B30 +LEFT ARROW WITH SMALL CIRCLE + +02B31 +THREE LEFTWARDS ARROWS + +02B32 +LEFT ARROW WITH CIRCLED PLUS + +02B33 +LONG LEFTWARDS SQUIGGLE ARROW + +02B34 +LEFTWARDS TWO-HEADED ARROW WITH VERTICAL STROKE + +02B35 +LEFTWARDS TWO-HEADED ARROW WITH DOUBLE VERTICAL STROKE + +02B36 +LEFTWARDS TWO-HEADED ARROW FROM BAR + +02B37 +LEFTWARDS TWO-HEADED TRIPLE DASH ARROW + +02B38 +LEFTWARDS ARROW WITH DOTTED STEM + +02B39 +LEFTWARDS ARROW WITH TAIL WITH VERTICAL STROKE + +02B3A +LEFTWARDS ARROW WITH TAIL WITH DOUBLE VERTICAL STROKE + +02B3B +LEFTWARDS TWO-HEADED ARROW WITH TAIL + +02B3C +LEFTWARDS TWO-HEADED ARROW WITH TAIL WITH VERTICAL STROKE + +02B3D +LEFTWARDS TWO-HEADED ARROW WITH TAIL WITH DOUBLE VERTICAL STROKE + +02B3E +LEFTWARDS ARROW THROUGH X + +02B3F +WAVE ARROW POINTING DIRECTLY LEFT + +02B40 +EQUALS SIGN ABOVE LEFTWARDS ARROW + +02B41 +REVERSE TILDE OPERATOR ABOVE LEFTWARDS ARROW + +02B42 +LEFTWARDS ARROW ABOVE REVERSE ALMOST EQUAL TO + +02B43 +RIGHTWARDS ARROW THROUGH GREATER-THAN + +02B44 +RIGHTWARDS ARROW THROUGH SUPERSET + +02B45 +LEFTWARDS QUADRUPLE ARROW + +02B46 +RIGHTWARDS QUADRUPLE ARROW + +02B47 +REVERSE TILDE OPERATOR ABOVE RIGHTWARDS ARROW + +02B48 +RIGHTWARDS ARROW ABOVE REVERSE ALMOST EQUAL TO + +02B49 +TILDE OPERATOR ABOVE LEFTWARDS ARROW + +02B4A +LEFTWARDS ARROW ABOVE ALMOST EQUAL TO + +02B4B +LEFTWARDS ARROW ABOVE REVERSE TILDE OPERATOR + +02B4C +RIGHTWARDS ARROW ABOVE REVERSE TILDE OPERATOR + +02B4D +DOWNWARDS TRIANGLE-HEADED ZIGZAG ARROW + +02B4E +SHORT SLANTED NORTH ARROW + +02B4F +SHORT BACKSLANTED SOUTH ARROW + +02B50 +WHITE MEDIUM STAR + +02B51 +BLACK SMALL STAR + +02B52 +WHITE SMALL STAR + +02B53 +BLACK RIGHT-POINTING PENTAGON + +02B54 +WHITE RIGHT-POINTING PENTAGON + +02B55 +HEAVY LARGE CIRCLE + +02B56 +HEAVY OVAL WITH OVAL INSIDE + +02B57 +HEAVY CIRCLE WITH CIRCLE INSIDE + +02B58 +HEAVY CIRCLE + +02B59 +HEAVY CIRCLED SALTIRE + +02B5A +SLANTED NORTH ARROW WITH HOOKED HEAD + +02B5B +BACKSLANTED SOUTH ARROW WITH HOOKED TAIL + +02B5C +SLANTED NORTH ARROW WITH HORIZONTAL TAIL + +02B5D +BACKSLANTED SOUTH ARROW WITH HORIZONTAL TAIL + +02B5E +BENT ARROW POINTING DOWNWARDS THEN NORTH EAST + +02B5F +SHORT BENT ARROW POINTING DOWNWARDS THEN NORTH EAST + +02B60 +LEFTWARDS TRIANGLE-HEADED ARROW + +02B61 +UPWARDS TRIANGLE-HEADED ARROW + +02B62 +RIGHTWARDS TRIANGLE-HEADED ARROW + +02B63 +DOWNWARDS TRIANGLE-HEADED ARROW + +02B64 +LEFT RIGHT TRIANGLE-HEADED ARROW + +02B65 +UP DOWN TRIANGLE-HEADED ARROW + +02B66 +NORTH WEST TRIANGLE-HEADED ARROW + +02B67 +NORTH EAST TRIANGLE-HEADED ARROW + +02B68 +SOUTH EAST TRIANGLE-HEADED ARROW + +02B69 +SOUTH WEST TRIANGLE-HEADED ARROW + +02B6A +LEFTWARDS TRIANGLE-HEADED DASHED ARROW + +02B6B +UPWARDS TRIANGLE-HEADED DASHED ARROW + +02B6C +RIGHTWARDS TRIANGLE-HEADED DASHED ARROW + +02B6D +DOWNWARDS TRIANGLE-HEADED DASHED ARROW + +02B6E +CLOCKWISE TRIANGLE-HEADED OPEN CIRCLE ARROW + +02B6F +ANTICLOCKWISE TRIANGLE-HEADED OPEN CIRCLE ARROW + +02B70 +LEFTWARDS TRIANGLE-HEADED ARROW TO BAR + +02B71 +UPWARDS TRIANGLE-HEADED ARROW TO BAR + +02B72 +RIGHTWARDS TRIANGLE-HEADED ARROW TO BAR + +02B73 +DOWNWARDS TRIANGLE-HEADED ARROW TO BAR + +02B76 +NORTH WEST TRIANGLE-HEADED ARROW TO BAR + +02B77 +NORTH EAST TRIANGLE-HEADED ARROW TO BAR + +02B78 +SOUTH EAST TRIANGLE-HEADED ARROW TO BAR + +02B79 +SOUTH WEST TRIANGLE-HEADED ARROW TO BAR + +02B7A +LEFTWARDS TRIANGLE-HEADED ARROW WITH DOUBLE VERTICAL STROKE + +02B7A +LEFTWARDS TRIANGLE-HEADED ARROW WITH DOUBLE HORIZONTAL STROKE + +02B7B +UPWARDS TRIANGLE-HEADED ARROW WITH DOUBLE HORIZONTAL STROKE + +02B7C +RIGHTWARDS TRIANGLE-HEADED ARROW WITH DOUBLE VERTICAL STROKE + +02B7C +RIGHTWARDS TRIANGLE-HEADED ARROW WITH DOUBLE HORIZONTAL STROKE + +02B7D +DOWNWARDS TRIANGLE-HEADED ARROW WITH DOUBLE HORIZONTAL STROKE + +02B7E +HORIZONTAL TAB KEY + +02B7F +VERTICAL TAB KEY + +02B80 +LEFTWARDS TRIANGLE-HEADED ARROW OVER RIGHTWARDS TRIANGLE-HEADED ARROW + +02B81 +UPWARDS TRIANGLE-HEADED ARROW LEFTWARDS OF DOWNWARDS TRIANGLE-HEADED ARROW + +02B82 +RIGHTWARDS TRIANGLE-HEADED ARROW OVER LEFTWARDS TRIANGLE-HEADED ARROW + +02B83 +DOWNWARDS TRIANGLE-HEADED ARROW LEFTWARDS OF UPWARDS TRIANGLE-HEADED ARROW + +02B84 +LEFTWARDS TRIANGLE-HEADED PAIRED ARROWS + +02B85 +UPWARDS TRIANGLE-HEADED PAIRED ARROWS + +02B86 +RIGHTWARDS TRIANGLE-HEADED PAIRED ARROWS + +02B87 +DOWNWARDS TRIANGLE-HEADED PAIRED ARROWS + +02B88 +LEFTWARDS BLACK CIRCLED WHITE ARROW + +02B89 +UPWARDS BLACK CIRCLED WHITE ARROW + +02B8A +RIGHTWARDS BLACK CIRCLED WHITE ARROW + +02B8B +DOWNWARDS BLACK CIRCLED WHITE ARROW + +02B8C +ANTICLOCKWISE TRIANGLE-HEADED RIGHT U-SHAPED ARROW + +02B8D +ANTICLOCKWISE TRIANGLE-HEADED BOTTOM U-SHAPED ARROW + +02B8E +ANTICLOCKWISE TRIANGLE-HEADED LEFT U-SHAPED ARROW + +02B8F +ANTICLOCKWISE TRIANGLE-HEADED TOP U-SHAPED ARROW + +02B90 +RETURN LEFT + +02B91 +RETURN RIGHT + +02B92 +NEWLINE LEFT + +02B93 +NEWLINE RIGHT + +02B94 +FOUR CORNER ARROWS CIRCLING ANTICLOCKWISE + +02B95 +RIGHTWARDS BLACK ARROW + +02B96 +EQUALS SIGN WITH INFINITY ABOVE + +02B97 +SYMBOL FOR TYPE A ELECTRONICS + +02B98 +THREE-D TOP-LIGHTED LEFTWARDS EQUILATERAL ARROWHEAD + +02B99 +THREE-D RIGHT-LIGHTED UPWARDS EQUILATERAL ARROWHEAD + +02B9A +THREE-D TOP-LIGHTED RIGHTWARDS EQUILATERAL ARROWHEAD + +02B9B +THREE-D LEFT-LIGHTED DOWNWARDS EQUILATERAL ARROWHEAD + +02B9C +BLACK LEFTWARDS EQUILATERAL ARROWHEAD + +02B9D +BLACK UPWARDS EQUILATERAL ARROWHEAD + +02B9E +BLACK RIGHTWARDS EQUILATERAL ARROWHEAD + +02B9F +BLACK DOWNWARDS EQUILATERAL ARROWHEAD + +02BA0 +DOWNWARDS TRIANGLE-HEADED ARROW WITH LONG TIP LEFTWARDS + +02BA1 +DOWNWARDS TRIANGLE-HEADED ARROW WITH LONG TIP RIGHTWARDS + +02BA2 +UPWARDS TRIANGLE-HEADED ARROW WITH LONG TIP LEFTWARDS + +02BA3 +UPWARDS TRIANGLE-HEADED ARROW WITH LONG TIP RIGHTWARDS + +02BA4 +LEFTWARDS TRIANGLE-HEADED ARROW WITH LONG TIP UPWARDS + +02BA5 +RIGHTWARDS TRIANGLE-HEADED ARROW WITH LONG TIP UPWARDS + +02BA6 +LEFTWARDS TRIANGLE-HEADED ARROW WITH LONG TIP DOWNWARDS + +02BA7 +RIGHTWARDS TRIANGLE-HEADED ARROW WITH LONG TIP DOWNWARDS + +02BA8 +BLACK CURVED DOWNWARDS AND LEFTWARDS ARROW + +02BA9 +BLACK CURVED DOWNWARDS AND RIGHTWARDS ARROW + +02BAA +BLACK CURVED UPWARDS AND LEFTWARDS ARROW + +02BAB +BLACK CURVED UPWARDS AND RIGHTWARDS ARROW + +02BAC +BLACK CURVED LEFTWARDS AND UPWARDS ARROW + +02BAD +BLACK CURVED RIGHTWARDS AND UPWARDS ARROW + +02BAE +BLACK CURVED LEFTWARDS AND DOWNWARDS ARROW + +02BAF +BLACK CURVED RIGHTWARDS AND DOWNWARDS ARROW + +02BB0 +RIBBON ARROW DOWN LEFT + +02BB1 +RIBBON ARROW DOWN RIGHT + +02BB2 +RIBBON ARROW UP LEFT + +02BB3 +RIBBON ARROW UP RIGHT + +02BB4 +RIBBON ARROW LEFT UP + +02BB5 +RIBBON ARROW RIGHT UP + +02BB6 +RIBBON ARROW LEFT DOWN + +02BB7 +RIBBON ARROW RIGHT DOWN + +02BB8 +UPWARDS WHITE ARROW FROM BAR WITH HORIZONTAL BAR + +02BB9 +UP ARROWHEAD IN A RECTANGLE BOX + +02BBA +OVERLAPPING WHITE SQUARES + +02BBB +OVERLAPPING WHITE AND BLACK SQUARES + +02BBC +OVERLAPPING BLACK SQUARES + +02BBD +BALLOT BOX WITH LIGHT X + +02BBE +CIRCLED X + +02BBF +CIRCLED BOLD X + +02BC0 +BLACK SQUARE CENTRED + +02BC1 +BLACK DIAMOND CENTRED + +02BC2 +TURNED BLACK PENTAGON + +02BC3 +HORIZONTAL BLACK OCTAGON + +02BC4 +BLACK OCTAGON + +02BC5 +BLACK MEDIUM UP-POINTING TRIANGLE CENTRED + +02BC6 +BLACK MEDIUM DOWN-POINTING TRIANGLE CENTRED + +02BC7 +BLACK MEDIUM LEFT-POINTING TRIANGLE CENTRED + +02BC8 +BLACK MEDIUM RIGHT-POINTING TRIANGLE CENTRED + +02BC9 +NEPTUNE FORM TWO + +02BCA +TOP HALF BLACK CIRCLE + +02BCB +BOTTOM HALF BLACK CIRCLE + +02BCC +LIGHT FOUR POINTED BLACK CUSP + +02BCD +ROTATED LIGHT FOUR POINTED BLACK CUSP + +02BCE +WHITE FOUR POINTED CUSP + +02BCF +ROTATED WHITE FOUR POINTED CUSP + +02BD0 +SQUARE POSITION INDICATOR + +02BD1 +UNCERTAINTY SIGN + +02BD2 +GROUP MARK + +02BD3 +PLUTO FORM TWO + +02BD4 +PLUTO FORM THREE + +02BD5 +PLUTO FORM FOUR + +02BD6 +PLUTO FORM FIVE + +02BD7 +TRANSPLUTO + +02BD8 +PROSERPINA + +02BD9 +ASTRAEA + +02BDA +HYGIEA + +02BDB +PHOLUS + +02BDC +NESSUS + +02BDD +WHITE MOON SELENA + +02BDE +BLACK DIAMOND ON CROSS + +02BDF +TRUE LIGHT MOON ARTA + +02BE0 +CUPIDO + +02BE1 +HADES + +02BE2 +ZEUS + +02BE3 +KRONOS + +02BE4 +APOLLON + +02BE5 +ADMETOS + +02BE6 +VULCANUS + +02BE7 +POSEIDON + +02BE8 +LEFT HALF BLACK STAR + +02BE9 +RIGHT HALF BLACK STAR + +02BEA +STAR WITH LEFT HALF BLACK + +02BEB +STAR WITH RIGHT HALF BLACK + +02BEC +LEFTWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS + +02BED +UPWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS + +02BEE +RIGHTWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS + +02BEF +DOWNWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS + +02BF0 +ERIS FORM ONE + +02BF1 +ERIS FORM TWO + +02BF2 +SEDNA + +02BF3 +RUSSIAN ASTROLOGICAL SYMBOL VIGINTILE + +02BF4 +RUSSIAN ASTROLOGICAL SYMBOL NOVILE + +02BF5 +RUSSIAN ASTROLOGICAL SYMBOL QUINTILE + +02BF6 +RUSSIAN ASTROLOGICAL SYMBOL BINOVILE + +02BF7 +RUSSIAN ASTROLOGICAL SYMBOL SENTAGON + +02BF8 +RUSSIAN ASTROLOGICAL SYMBOL TREDECILE + +02BF9 +EQUALS SIGN WITH INFINITY BELOW + +02BFA +UNITED SYMBOL + +02BFB +SEPARATED SYMBOL + +02BFC +DOUBLED SYMBOL + +02BFD +PASSED SYMBOL + +02BFE +REVERSED RIGHT ANGLE + +02BFF +HELLSCHREIBER PAUSE SYMBOL + +02C00 +GLAGOLITIC CAPITAL LETTER AZU + +02C01 +GLAGOLITIC CAPITAL LETTER BUKY + +02C02 +GLAGOLITIC CAPITAL LETTER VEDE + +02C03 +GLAGOLITIC CAPITAL LETTER GLAGOLI + +02C04 +GLAGOLITIC CAPITAL LETTER DOBRO + +02C05 +GLAGOLITIC CAPITAL LETTER YESTU + +02C06 +GLAGOLITIC CAPITAL LETTER ZHIVETE + +02C07 +GLAGOLITIC CAPITAL LETTER DZELO + +02C08 +GLAGOLITIC CAPITAL LETTER ZEMLJA + +02C09 +GLAGOLITIC CAPITAL LETTER IZHE + +02C0A +GLAGOLITIC CAPITAL LETTER INITIAL IZHE + +02C0B +GLAGOLITIC CAPITAL LETTER I + +02C0C +GLAGOLITIC CAPITAL LETTER DJERVI + +02C0D +GLAGOLITIC CAPITAL LETTER KAKO + +02C0E +GLAGOLITIC CAPITAL LETTER LJUDIJE + +02C0F +GLAGOLITIC CAPITAL LETTER MYSLITE + +02C10 +GLAGOLITIC CAPITAL LETTER NASHI + +02C11 +GLAGOLITIC CAPITAL LETTER ONU + +02C12 +GLAGOLITIC CAPITAL LETTER POKOJI + +02C13 +GLAGOLITIC CAPITAL LETTER RITSI + +02C14 +GLAGOLITIC CAPITAL LETTER SLOVO + +02C15 +GLAGOLITIC CAPITAL LETTER TVRIDO + +02C16 +GLAGOLITIC CAPITAL LETTER UKU + +02C17 +GLAGOLITIC CAPITAL LETTER FRITU + +02C18 +GLAGOLITIC CAPITAL LETTER HERU + +02C19 +GLAGOLITIC CAPITAL LETTER OTU + +02C1A +GLAGOLITIC CAPITAL LETTER PE + +02C1B +GLAGOLITIC CAPITAL LETTER SHTA + +02C1C +GLAGOLITIC CAPITAL LETTER TSI + +02C1D +GLAGOLITIC CAPITAL LETTER CHRIVI + +02C1E +GLAGOLITIC CAPITAL LETTER SHA + +02C1F +GLAGOLITIC CAPITAL LETTER YERU + +02C20 +GLAGOLITIC CAPITAL LETTER YERI + +02C21 +GLAGOLITIC CAPITAL LETTER YATI + +02C22 +GLAGOLITIC CAPITAL LETTER SPIDERY HA + +02C23 +GLAGOLITIC CAPITAL LETTER YU + +02C24 +GLAGOLITIC CAPITAL LETTER SMALL YUS + +02C25 +GLAGOLITIC CAPITAL LETTER SMALL YUS WITH TAIL + +02C26 +GLAGOLITIC CAPITAL LETTER YO + +02C27 +GLAGOLITIC CAPITAL LETTER IOTATED SMALL YUS + +02C28 +GLAGOLITIC CAPITAL LETTER BIG YUS + +02C29 +GLAGOLITIC CAPITAL LETTER IOTATED BIG YUS + +02C2A +GLAGOLITIC CAPITAL LETTER FITA + +02C2B +GLAGOLITIC CAPITAL LETTER IZHITSA + +02C2C +GLAGOLITIC CAPITAL LETTER SHTAPIC + +02C2D +GLAGOLITIC CAPITAL LETTER TROKUTASTI A + +02C2E +GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE + +02C2F +GLAGOLITIC CAPITAL LETTER CAUDATE CHRIVI + +02C30 +GLAGOLITIC SMALL LETTER AZU + +02C31 +GLAGOLITIC SMALL LETTER BUKY + +02C32 +GLAGOLITIC SMALL LETTER VEDE + +02C33 +GLAGOLITIC SMALL LETTER GLAGOLI + +02C34 +GLAGOLITIC SMALL LETTER DOBRO + +02C35 +GLAGOLITIC SMALL LETTER YESTU + +02C36 +GLAGOLITIC SMALL LETTER ZHIVETE + +02C37 +GLAGOLITIC SMALL LETTER DZELO + +02C38 +GLAGOLITIC SMALL LETTER ZEMLJA + +02C39 +GLAGOLITIC SMALL LETTER IZHE + +02C3A +GLAGOLITIC SMALL LETTER INITIAL IZHE + +02C3B +GLAGOLITIC SMALL LETTER I + +02C3C +GLAGOLITIC SMALL LETTER DJERVI + +02C3D +GLAGOLITIC SMALL LETTER KAKO + +02C3E +GLAGOLITIC SMALL LETTER LJUDIJE + +02C3F +GLAGOLITIC SMALL LETTER MYSLITE + +02C40 +GLAGOLITIC SMALL LETTER NASHI + +02C41 +GLAGOLITIC SMALL LETTER ONU + +02C42 +GLAGOLITIC SMALL LETTER POKOJI + +02C43 +GLAGOLITIC SMALL LETTER RITSI + +02C44 +GLAGOLITIC SMALL LETTER SLOVO + +02C45 +GLAGOLITIC SMALL LETTER TVRIDO + +02C46 +GLAGOLITIC SMALL LETTER UKU + +02C47 +GLAGOLITIC SMALL LETTER FRITU + +02C48 +GLAGOLITIC SMALL LETTER HERU + +02C49 +GLAGOLITIC SMALL LETTER OTU + +02C4A +GLAGOLITIC SMALL LETTER PE + +02C4B +GLAGOLITIC SMALL LETTER SHTA + +02C4C +GLAGOLITIC SMALL LETTER TSI + +02C4D +GLAGOLITIC SMALL LETTER CHRIVI + +02C4E +GLAGOLITIC SMALL LETTER SHA + +02C4F +GLAGOLITIC SMALL LETTER YERU + +02C50 +GLAGOLITIC SMALL LETTER YERI + +02C51 +GLAGOLITIC SMALL LETTER YATI + +02C52 +GLAGOLITIC SMALL LETTER SPIDERY HA + +02C53 +GLAGOLITIC SMALL LETTER YU + +02C54 +GLAGOLITIC SMALL LETTER SMALL YUS + +02C55 +GLAGOLITIC SMALL LETTER SMALL YUS WITH TAIL + +02C56 +GLAGOLITIC SMALL LETTER YO + +02C57 +GLAGOLITIC SMALL LETTER IOTATED SMALL YUS + +02C58 +GLAGOLITIC SMALL LETTER BIG YUS + +02C59 +GLAGOLITIC SMALL LETTER IOTATED BIG YUS + +02C5A +GLAGOLITIC SMALL LETTER FITA + +02C5B +GLAGOLITIC SMALL LETTER IZHITSA + +02C5C +GLAGOLITIC SMALL LETTER SHTAPIC + +02C5D +GLAGOLITIC SMALL LETTER TROKUTASTI A + +02C5E +GLAGOLITIC SMALL LETTER LATINATE MYSLITE + +02C5F +GLAGOLITIC SMALL LETTER CAUDATE CHRIVI + +02C60 +LATIN CAPITAL LETTER L WITH DOUBLE BAR + +02C61 +LATIN SMALL LETTER L WITH DOUBLE BAR + +02C62 +LATIN CAPITAL LETTER L WITH MIDDLE TILDE + +02C63 +LATIN CAPITAL LETTER P WITH STROKE + +02C64 +LATIN CAPITAL LETTER R WITH TAIL + +02C65 +LATIN SMALL LETTER A WITH STROKE + +02C66 +LATIN SMALL LETTER T WITH DIAGONAL STROKE + +02C67 +LATIN CAPITAL LETTER H WITH DESCENDER + +02C68 +LATIN SMALL LETTER H WITH DESCENDER + +02C69 +LATIN CAPITAL LETTER K WITH DESCENDER + +02C6A +LATIN SMALL LETTER K WITH DESCENDER + +02C6B +LATIN CAPITAL LETTER Z WITH DESCENDER + +02C6C +LATIN SMALL LETTER Z WITH DESCENDER + +02C6D +LATIN CAPITAL LETTER ALPHA + +02C6E +LATIN CAPITAL LETTER M WITH HOOK + +02C6F +LATIN CAPITAL LETTER TURNED A + +02C70 +LATIN CAPITAL LETTER TURNED ALPHA + +02C71 +LATIN SMALL LETTER V WITH RIGHT HOOK + +02C72 +LATIN CAPITAL LETTER W WITH HOOK + +02C73 +LATIN SMALL LETTER W WITH HOOK + +02C74 +LATIN SMALL LETTER V WITH CURL + +02C75 +LATIN CAPITAL LETTER HALF H + +02C76 +LATIN SMALL LETTER HALF H + +02C77 +LATIN SMALL LETTER TAILLESS PHI + +02C78 +LATIN SMALL LETTER E WITH NOTCH + +02C79 +LATIN SMALL LETTER TURNED R WITH TAIL + +02C7A +LATIN SMALL LETTER O WITH LOW RING INSIDE + +02C7B +LATIN LETTER SMALL CAPITAL TURNED E + +02C7C +LATIN SUBSCRIPT SMALL LETTER J + +02C7D +MODIFIER LETTER CAPITAL V + +02C7E +LATIN CAPITAL LETTER S WITH SWASH TAIL + +02C7F +LATIN CAPITAL LETTER Z WITH SWASH TAIL + +02C80 +COPTIC CAPITAL LETTER ALFA + +02C81 +COPTIC SMALL LETTER ALFA + +02C82 +COPTIC CAPITAL LETTER VIDA + +02C83 +COPTIC SMALL LETTER VIDA + +02C84 +COPTIC CAPITAL LETTER GAMMA + +02C85 +COPTIC SMALL LETTER GAMMA + +02C86 +COPTIC CAPITAL LETTER DALDA + +02C87 +COPTIC SMALL LETTER DALDA + +02C88 +COPTIC CAPITAL LETTER EIE + +02C89 +COPTIC SMALL LETTER EIE + +02C8A +COPTIC CAPITAL LETTER SOU + +02C8B +COPTIC SMALL LETTER SOU + +02C8C +COPTIC CAPITAL LETTER ZATA + +02C8D +COPTIC SMALL LETTER ZATA + +02C8E +COPTIC CAPITAL LETTER HATE + +02C8F +COPTIC SMALL LETTER HATE + +02C90 +COPTIC CAPITAL LETTER THETHE + +02C91 +COPTIC SMALL LETTER THETHE + +02C92 +COPTIC CAPITAL LETTER IAUDA + +02C93 +COPTIC SMALL LETTER IAUDA + +02C94 +COPTIC CAPITAL LETTER KAPA + +02C95 +COPTIC SMALL LETTER KAPA + +02C96 +COPTIC CAPITAL LETTER LAULA + +02C97 +COPTIC SMALL LETTER LAULA + +02C98 +COPTIC CAPITAL LETTER MI + +02C99 +COPTIC SMALL LETTER MI + +02C9A +COPTIC CAPITAL LETTER NI + +02C9B +COPTIC SMALL LETTER NI + +02C9C +COPTIC CAPITAL LETTER KSI + +02C9D +COPTIC SMALL LETTER KSI + +02C9E +COPTIC CAPITAL LETTER O + +02C9F +COPTIC SMALL LETTER O + +02CA0 +COPTIC CAPITAL LETTER PI + +02CA1 +COPTIC SMALL LETTER PI + +02CA2 +COPTIC CAPITAL LETTER RO + +02CA3 +COPTIC SMALL LETTER RO + +02CA4 +COPTIC CAPITAL LETTER SIMA + +02CA5 +COPTIC SMALL LETTER SIMA + +02CA6 +COPTIC CAPITAL LETTER TAU + +02CA7 +COPTIC SMALL LETTER TAU + +02CA8 +COPTIC CAPITAL LETTER UA + +02CA9 +COPTIC SMALL LETTER UA + +02CAA +COPTIC CAPITAL LETTER FI + +02CAB +COPTIC SMALL LETTER FI + +02CAC +COPTIC CAPITAL LETTER KHI + +02CAD +COPTIC SMALL LETTER KHI + +02CAE +COPTIC CAPITAL LETTER PSI + +02CAF +COPTIC SMALL LETTER PSI + +02CB0 +COPTIC CAPITAL LETTER OOU + +02CB1 +COPTIC SMALL LETTER OOU + +02CB2 +COPTIC CAPITAL LETTER DIALECT-P ALEF + +02CB3 +COPTIC SMALL LETTER DIALECT-P ALEF + +02CB4 +COPTIC CAPITAL LETTER OLD COPTIC AIN + +02CB5 +COPTIC SMALL LETTER OLD COPTIC AIN + +02CB6 +COPTIC CAPITAL LETTER CRYPTOGRAMMIC EIE + +02CB7 +COPTIC SMALL LETTER CRYPTOGRAMMIC EIE + +02CB8 +COPTIC CAPITAL LETTER DIALECT-P KAPA + +02CB9 +COPTIC SMALL LETTER DIALECT-P KAPA + +02CBA +COPTIC CAPITAL LETTER DIALECT-P NI + +02CBB +COPTIC SMALL LETTER DIALECT-P NI + +02CBC +COPTIC CAPITAL LETTER CRYPTOGRAMMIC NI + +02CBD +COPTIC SMALL LETTER CRYPTOGRAMMIC NI + +02CBE +COPTIC CAPITAL LETTER OLD COPTIC OOU + +02CBF +COPTIC SMALL LETTER OLD COPTIC OOU + +02CC0 +COPTIC CAPITAL LETTER SAMPI + +02CC1 +COPTIC SMALL LETTER SAMPI + +02CC2 +COPTIC CAPITAL LETTER CROSSED SHEI + +02CC3 +COPTIC SMALL LETTER CROSSED SHEI + +02CC4 +COPTIC CAPITAL LETTER OLD COPTIC SHEI + +02CC5 +COPTIC SMALL LETTER OLD COPTIC SHEI + +02CC6 +COPTIC CAPITAL LETTER OLD COPTIC ESH + +02CC7 +COPTIC SMALL LETTER OLD COPTIC ESH + +02CC8 +COPTIC CAPITAL LETTER AKHMIMIC KHEI + +02CC9 +COPTIC SMALL LETTER AKHMIMIC KHEI + +02CCA +COPTIC CAPITAL LETTER DIALECT-P HORI + +02CCB +COPTIC SMALL LETTER DIALECT-P HORI + +02CCC +COPTIC CAPITAL LETTER OLD COPTIC HORI + +02CCD +COPTIC SMALL LETTER OLD COPTIC HORI + +02CCE +COPTIC CAPITAL LETTER OLD COPTIC HA + +02CCF +COPTIC SMALL LETTER OLD COPTIC HA + +02CD0 +COPTIC CAPITAL LETTER L-SHAPED HA + +02CD1 +COPTIC SMALL LETTER L-SHAPED HA + +02CD2 +COPTIC CAPITAL LETTER OLD COPTIC HEI + +02CD3 +COPTIC SMALL LETTER OLD COPTIC HEI + +02CD4 +COPTIC CAPITAL LETTER OLD COPTIC HAT + +02CD5 +COPTIC SMALL LETTER OLD COPTIC HAT + +02CD6 +COPTIC CAPITAL LETTER OLD COPTIC GANGIA + +02CD7 +COPTIC SMALL LETTER OLD COPTIC GANGIA + +02CD8 +COPTIC CAPITAL LETTER OLD COPTIC DJA + +02CD9 +COPTIC SMALL LETTER OLD COPTIC DJA + +02CDA +COPTIC CAPITAL LETTER OLD COPTIC SHIMA + +02CDB +COPTIC SMALL LETTER OLD COPTIC SHIMA + +02CDC +COPTIC CAPITAL LETTER OLD NUBIAN SHIMA + +02CDD +COPTIC SMALL LETTER OLD NUBIAN SHIMA + +02CDE +COPTIC CAPITAL LETTER OLD NUBIAN NGI + +02CDF +COPTIC SMALL LETTER OLD NUBIAN NGI + +02CE0 +COPTIC CAPITAL LETTER OLD NUBIAN NYI + +02CE1 +COPTIC SMALL LETTER OLD NUBIAN NYI + +02CE2 +COPTIC CAPITAL LETTER OLD NUBIAN WAU + +02CE3 +COPTIC SMALL LETTER OLD NUBIAN WAU + +02CE4 +COPTIC SYMBOL KAI + +02CE5 +COPTIC SYMBOL MI RO + +02CE6 +COPTIC SYMBOL PI RO + +02CE7 +COPTIC SYMBOL STAUROS + +02CE8 +COPTIC SYMBOL TAU RO + +02CE9 +COPTIC SYMBOL KHI RO + +02CEA +COPTIC SYMBOL SHIMA SIMA + +02CEB +COPTIC CAPITAL LETTER CRYPTOGRAMMIC SHEI + +02CEC +COPTIC SMALL LETTER CRYPTOGRAMMIC SHEI + +02CED +COPTIC CAPITAL LETTER CRYPTOGRAMMIC GANGIA + +02CEE +COPTIC SMALL LETTER CRYPTOGRAMMIC GANGIA + +02CEF +COPTIC COMBINING NI ABOVE + +02CF0 +COPTIC COMBINING SPIRITUS ASPER + +02CF1 +COPTIC COMBINING SPIRITUS LENIS + +02CF2 +COPTIC CAPITAL LETTER BOHAIRIC KHEI + +02CF3 +COPTIC SMALL LETTER BOHAIRIC KHEI + +02CF9 +COPTIC OLD NUBIAN FULL STOP + +02CFA +COPTIC OLD NUBIAN DIRECT QUESTION MARK + +02CFB +COPTIC OLD NUBIAN INDIRECT QUESTION MARK + +02CFC +COPTIC OLD NUBIAN VERSE DIVIDER + +02CFD +COPTIC FRACTION ONE HALF + +02CFE +COPTIC FULL STOP + +02CFF +COPTIC MORPHOLOGICAL DIVIDER + +02D00 +GEORGIAN SMALL LETTER AN + +02D01 +GEORGIAN SMALL LETTER BAN + +02D02 +GEORGIAN SMALL LETTER GAN + +02D03 +GEORGIAN SMALL LETTER DON + +02D04 +GEORGIAN SMALL LETTER EN + +02D05 +GEORGIAN SMALL LETTER VIN + +02D06 +GEORGIAN SMALL LETTER ZEN + +02D07 +GEORGIAN SMALL LETTER TAN + +02D08 +GEORGIAN SMALL LETTER IN + +02D09 +GEORGIAN SMALL LETTER KAN + +02D0A +GEORGIAN SMALL LETTER LAS + +02D0B +GEORGIAN SMALL LETTER MAN + +02D0C +GEORGIAN SMALL LETTER NAR + +02D0D +GEORGIAN SMALL LETTER ON + +02D0E +GEORGIAN SMALL LETTER PAR + +02D0F +GEORGIAN SMALL LETTER ZHAR + +02D10 +GEORGIAN SMALL LETTER RAE + +02D11 +GEORGIAN SMALL LETTER SAN + +02D12 +GEORGIAN SMALL LETTER TAR + +02D13 +GEORGIAN SMALL LETTER UN + +02D14 +GEORGIAN SMALL LETTER PHAR + +02D15 +GEORGIAN SMALL LETTER KHAR + +02D16 +GEORGIAN SMALL LETTER GHAN + +02D17 +GEORGIAN SMALL LETTER QAR + +02D18 +GEORGIAN SMALL LETTER SHIN + +02D19 +GEORGIAN SMALL LETTER CHIN + +02D1A +GEORGIAN SMALL LETTER CAN + +02D1B +GEORGIAN SMALL LETTER JIL + +02D1C +GEORGIAN SMALL LETTER CIL + +02D1D +GEORGIAN SMALL LETTER CHAR + +02D1E +GEORGIAN SMALL LETTER XAN + +02D1F +GEORGIAN SMALL LETTER JHAN + +02D20 +GEORGIAN SMALL LETTER HAE + +02D21 +GEORGIAN SMALL LETTER HE + +02D22 +GEORGIAN SMALL LETTER HIE + +02D23 +GEORGIAN SMALL LETTER WE + +02D24 +GEORGIAN SMALL LETTER HAR + +02D25 +GEORGIAN SMALL LETTER HOE + +02D27 +GEORGIAN SMALL LETTER YN + +02D2D +GEORGIAN SMALL LETTER AEN + +02D30 +TIFINAGH LETTER YA + +02D31 +TIFINAGH LETTER YAB + +02D32 +TIFINAGH LETTER YABH + +02D33 +TIFINAGH LETTER YAG + +02D34 +TIFINAGH LETTER YAGHH + +02D35 +TIFINAGH LETTER BERBER ACADEMY YAJ + +02D36 +TIFINAGH LETTER YAJ + +02D37 +TIFINAGH LETTER YAD + +02D38 +TIFINAGH LETTER YADH + +02D39 +TIFINAGH LETTER YADD + +02D3A +TIFINAGH LETTER YADDH + +02D3B +TIFINAGH LETTER YEY + +02D3C +TIFINAGH LETTER YAF + +02D3D +TIFINAGH LETTER YAK + +02D3E +TIFINAGH LETTER TUAREG YAK + +02D3F +TIFINAGH LETTER YAKHH + +02D40 +TIFINAGH LETTER YAH + +02D41 +TIFINAGH LETTER BERBER ACADEMY YAH + +02D42 +TIFINAGH LETTER TUAREG YAH + +02D43 +TIFINAGH LETTER YAHH + +02D44 +TIFINAGH LETTER YAA + +02D45 +TIFINAGH LETTER YAKH + +02D46 +TIFINAGH LETTER TUAREG YAKH + +02D47 +TIFINAGH LETTER YAQ + +02D48 +TIFINAGH LETTER TUAREG YAQ + +02D49 +TIFINAGH LETTER YI + +02D4A +TIFINAGH LETTER YAZH + +02D4B +TIFINAGH LETTER AHAGGAR YAZH + +02D4C +TIFINAGH LETTER TUAREG YAZH + +02D4D +TIFINAGH LETTER YAL + +02D4E +TIFINAGH LETTER YAM + +02D4F +TIFINAGH LETTER YAN + +02D50 +TIFINAGH LETTER TUAREG YAGN + +02D51 +TIFINAGH LETTER TUAREG YANG + +02D52 +TIFINAGH LETTER YAP + +02D53 +TIFINAGH LETTER YU + +02D54 +TIFINAGH LETTER YAR + +02D55 +TIFINAGH LETTER YARR + +02D56 +TIFINAGH LETTER YAGH + +02D57 +TIFINAGH LETTER TUAREG YAGH + +02D58 +TIFINAGH LETTER AYER YAGH + +02D59 +TIFINAGH LETTER YAS + +02D5A +TIFINAGH LETTER YASS + +02D5B +TIFINAGH LETTER YASH + +02D5C +TIFINAGH LETTER YAT + +02D5D +TIFINAGH LETTER YATH + +02D5E +TIFINAGH LETTER YACH + +02D5F +TIFINAGH LETTER YATT + +02D60 +TIFINAGH LETTER YAV + +02D61 +TIFINAGH LETTER YAW + +02D62 +TIFINAGH LETTER YAY + +02D63 +TIFINAGH LETTER YAZ + +02D64 +TIFINAGH LETTER TAWELLEMET YAZ + +02D65 +TIFINAGH LETTER YAZZ + +02D66 +TIFINAGH LETTER YE + +02D67 +TIFINAGH LETTER YO + +02D6F +TIFINAGH MODIFIER LETTER LABIALIZATION MARK + +02D70 +TIFINAGH SEPARATOR MARK + +02D7F +TIFINAGH CONSONANT JOINER + +02D80 +ETHIOPIC SYLLABLE LOA + +02D81 +ETHIOPIC SYLLABLE MOA + +02D82 +ETHIOPIC SYLLABLE ROA + +02D83 +ETHIOPIC SYLLABLE SOA + +02D84 +ETHIOPIC SYLLABLE SHOA + +02D85 +ETHIOPIC SYLLABLE BOA + +02D86 +ETHIOPIC SYLLABLE TOA + +02D87 +ETHIOPIC SYLLABLE COA + +02D88 +ETHIOPIC SYLLABLE NOA + +02D89 +ETHIOPIC SYLLABLE NYOA + +02D8A +ETHIOPIC SYLLABLE GLOTTAL OA + +02D8B +ETHIOPIC SYLLABLE ZOA + +02D8C +ETHIOPIC SYLLABLE DOA + +02D8D +ETHIOPIC SYLLABLE DDOA + +02D8E +ETHIOPIC SYLLABLE JOA + +02D8F +ETHIOPIC SYLLABLE THOA + +02D90 +ETHIOPIC SYLLABLE CHOA + +02D91 +ETHIOPIC SYLLABLE PHOA + +02D92 +ETHIOPIC SYLLABLE POA + +02D93 +ETHIOPIC SYLLABLE GGWA + +02D94 +ETHIOPIC SYLLABLE GGWI + +02D95 +ETHIOPIC SYLLABLE GGWEE + +02D96 +ETHIOPIC SYLLABLE GGWE + +02DA0 +ETHIOPIC SYLLABLE SSA + +02DA1 +ETHIOPIC SYLLABLE SSU + +02DA2 +ETHIOPIC SYLLABLE SSI + +02DA3 +ETHIOPIC SYLLABLE SSAA + +02DA4 +ETHIOPIC SYLLABLE SSEE + +02DA5 +ETHIOPIC SYLLABLE SSE + +02DA6 +ETHIOPIC SYLLABLE SSO + +02DA8 +ETHIOPIC SYLLABLE CCA + +02DA9 +ETHIOPIC SYLLABLE CCU + +02DAA +ETHIOPIC SYLLABLE CCI + +02DAB +ETHIOPIC SYLLABLE CCAA + +02DAC +ETHIOPIC SYLLABLE CCEE + +02DAD +ETHIOPIC SYLLABLE CCE + +02DAE +ETHIOPIC SYLLABLE CCO + +02DB0 +ETHIOPIC SYLLABLE ZZA + +02DB1 +ETHIOPIC SYLLABLE ZZU + +02DB2 +ETHIOPIC SYLLABLE ZZI + +02DB3 +ETHIOPIC SYLLABLE ZZAA + +02DB4 +ETHIOPIC SYLLABLE ZZEE + +02DB5 +ETHIOPIC SYLLABLE ZZE + +02DB6 +ETHIOPIC SYLLABLE ZZO + +02DB8 +ETHIOPIC SYLLABLE CCHA + +02DB9 +ETHIOPIC SYLLABLE CCHU + +02DBA +ETHIOPIC SYLLABLE CCHI + +02DBB +ETHIOPIC SYLLABLE CCHAA + +02DBC +ETHIOPIC SYLLABLE CCHEE + +02DBD +ETHIOPIC SYLLABLE CCHE + +02DBE +ETHIOPIC SYLLABLE CCHO + +02DC0 +ETHIOPIC SYLLABLE QYA + +02DC1 +ETHIOPIC SYLLABLE QYU + +02DC2 +ETHIOPIC SYLLABLE QYI + +02DC3 +ETHIOPIC SYLLABLE QYAA + +02DC4 +ETHIOPIC SYLLABLE QYEE + +02DC5 +ETHIOPIC SYLLABLE QYE + +02DC6 +ETHIOPIC SYLLABLE QYO + +02DC8 +ETHIOPIC SYLLABLE KYA + +02DC9 +ETHIOPIC SYLLABLE KYU + +02DCA +ETHIOPIC SYLLABLE KYI + +02DCB +ETHIOPIC SYLLABLE KYAA + +02DCC +ETHIOPIC SYLLABLE KYEE + +02DCD +ETHIOPIC SYLLABLE KYE + +02DCE +ETHIOPIC SYLLABLE KYO + +02DD0 +ETHIOPIC SYLLABLE XYA + +02DD1 +ETHIOPIC SYLLABLE XYU + +02DD2 +ETHIOPIC SYLLABLE XYI + +02DD3 +ETHIOPIC SYLLABLE XYAA + +02DD4 +ETHIOPIC SYLLABLE XYEE + +02DD5 +ETHIOPIC SYLLABLE XYE + +02DD6 +ETHIOPIC SYLLABLE XYO + +02DD8 +ETHIOPIC SYLLABLE GYA + +02DD9 +ETHIOPIC SYLLABLE GYU + +02DDA +ETHIOPIC SYLLABLE GYI + +02DDB +ETHIOPIC SYLLABLE GYAA + +02DDC +ETHIOPIC SYLLABLE GYEE + +02DDD +ETHIOPIC SYLLABLE GYE + +02DDE +ETHIOPIC SYLLABLE GYO + +02DE0 +COMBINING CYRILLIC LETTER BE + +02DE1 +COMBINING CYRILLIC LETTER VE + +02DE2 +COMBINING CYRILLIC LETTER GHE + +02DE3 +COMBINING CYRILLIC LETTER DE + +02DE4 +COMBINING CYRILLIC LETTER ZHE + +02DE5 +COMBINING CYRILLIC LETTER ZE + +02DE6 +COMBINING CYRILLIC LETTER KA + +02DE7 +COMBINING CYRILLIC LETTER EL + +02DE8 +COMBINING CYRILLIC LETTER EM + +02DE9 +COMBINING CYRILLIC LETTER EN + +02DEA +COMBINING CYRILLIC LETTER O + +02DEB +COMBINING CYRILLIC LETTER PE + +02DEC +COMBINING CYRILLIC LETTER ER + +02DED +COMBINING CYRILLIC LETTER ES + +02DEE +COMBINING CYRILLIC LETTER TE + +02DEF +COMBINING CYRILLIC LETTER HA + +02DF0 +COMBINING CYRILLIC LETTER TSE + +02DF1 +COMBINING CYRILLIC LETTER CHE + +02DF2 +COMBINING CYRILLIC LETTER SHA + +02DF3 +COMBINING CYRILLIC LETTER SHCHA + +02DF4 +COMBINING CYRILLIC LETTER FITA + +02DF5 +COMBINING CYRILLIC LETTER ES-TE + +02DF6 +COMBINING CYRILLIC LETTER A + +02DF7 +COMBINING CYRILLIC LETTER IE + +02DF8 +COMBINING CYRILLIC LETTER DJERV + +02DF9 +COMBINING CYRILLIC LETTER MONOGRAPH UK + +02DFA +COMBINING CYRILLIC LETTER YAT + +02DFB +COMBINING CYRILLIC LETTER YU + +02DFC +COMBINING CYRILLIC LETTER IOTIFIED A + +02DFD +COMBINING CYRILLIC LETTER LITTLE YUS + +02DFE +COMBINING CYRILLIC LETTER BIG YUS + +02DFF +COMBINING CYRILLIC LETTER IOTIFIED BIG YUS + +02E00 +RIGHT ANGLE SUBSTITUTION MARKER + +02E01 +RIGHT ANGLE DOTTED SUBSTITUTION MARKER + +02E02 +LEFT SUBSTITUTION BRACKET + +02E03 +RIGHT SUBSTITUTION BRACKET + +02E04 +LEFT DOTTED SUBSTITUTION BRACKET + +02E05 +RIGHT DOTTED SUBSTITUTION BRACKET + +02E06 +RAISED INTERPOLATION MARKER + +02E07 +RAISED DOTTED INTERPOLATION MARKER + +02E08 +DOTTED TRANSPOSITION MARKER + +02E09 +LEFT TRANSPOSITION BRACKET + +02E0A +RIGHT TRANSPOSITION BRACKET + +02E0B +RAISED SQUARE + +02E0C +LEFT RAISED OMISSION BRACKET + +02E0D +RIGHT RAISED OMISSION BRACKET + +02E0E +EDITORIAL CORONIS + +02E0F +PARAGRAPHOS + +02E10 +FORKED PARAGRAPHOS + +02E11 +REVERSED FORKED PARAGRAPHOS + +02E12 +HYPODIASTOLE + +02E13 +DOTTED OBELOS + +02E14 +DOWNWARDS ANCORA + +02E15 +UPWARDS ANCORA + +02E16 +DOTTED RIGHT-POINTING ANGLE + +02E17 +DOUBLE OBLIQUE HYPHEN + +02E18 +INVERTED INTERROBANG + +02E19 +PALM BRANCH + +02E1A +HYPHEN WITH DIAERESIS + +02E1B +TILDE WITH RING ABOVE + +02E1C +LEFT LOW PARAPHRASE BRACKET + +02E1D +RIGHT LOW PARAPHRASE BRACKET + +02E1E +TILDE WITH DOT ABOVE + +02E1F +TILDE WITH DOT BELOW + +02E20 +LEFT VERTICAL BAR WITH QUILL + +02E21 +RIGHT VERTICAL BAR WITH QUILL + +02E22 +TOP LEFT HALF BRACKET + +02E23 +TOP RIGHT HALF BRACKET + +02E24 +BOTTOM LEFT HALF BRACKET + +02E25 +BOTTOM RIGHT HALF BRACKET + +02E26 +LEFT SIDEWAYS U BRACKET + +02E27 +RIGHT SIDEWAYS U BRACKET + +02E28 +LEFT DOUBLE PARENTHESIS + +02E29 +RIGHT DOUBLE PARENTHESIS + +02E2A +TWO DOTS OVER ONE DOT PUNCTUATION + +02E2B +ONE DOT OVER TWO DOTS PUNCTUATION + +02E2C +SQUARED FOUR DOT PUNCTUATION + +02E2D +FIVE DOT MARK + +02E2E +REVERSED QUESTION MARK + +02E2F +VERTICAL TILDE + +02E30 +RING POINT + +02E31 +WORD SEPARATOR MIDDLE DOT + +02E32 +TURNED COMMA + +02E33 +RAISED DOT + +02E34 +RAISED COMMA + +02E35 +TURNED SEMICOLON + +02E36 +DAGGER WITH LEFT GUARD + +02E37 +DAGGER WITH RIGHT GUARD + +02E38 +TURNED DAGGER + +02E39 +TOP HALF SECTION SIGN + +02E3A +TWO-EM DASH + +02E3B +THREE-EM DASH + +02E3C +STENOGRAPHIC FULL STOP + +02E3D +VERTICAL SIX DOTS + +02E3E +WIGGLY VERTICAL LINE + +02E3F +CAPITULUM + +02E40 +DOUBLE HYPHEN + +02E41 +REVERSED COMMA + +02E42 +DOUBLE LOW-REVERSED-9 QUOTATION MARK + +02E43 +DASH WITH LEFT UPTURN + +02E44 +DOUBLE SUSPENSION MARK + +02E45 +INVERTED LOW KAVYKA + +02E46 +INVERTED LOW KAVYKA WITH KAVYKA ABOVE + +02E47 +LOW KAVYKA + +02E48 +LOW KAVYKA WITH DOT + +02E49 +DOUBLE STACKED COMMA + +02E4A +DOTTED SOLIDUS + +02E4B +TRIPLE DAGGER + +02E4C +MEDIEVAL COMMA + +02E4D +PARAGRAPHUS MARK + +02E4E +PUNCTUS ELEVATUS MARK + +02E4F +CORNISH VERSE DIVIDER + +02E50 +CROSS PATTY WITH RIGHT CROSSBAR + +02E51 +CROSS PATTY WITH LEFT CROSSBAR + +02E52 +TIRONIAN SIGN CAPITAL ET + +02E53 +MEDIEVAL EXCLAMATION MARK + +02E54 +MEDIEVAL QUESTION MARK + +02E55 +LEFT SQUARE BRACKET WITH STROKE + +02E56 +RIGHT SQUARE BRACKET WITH STROKE + +02E57 +LEFT SQUARE BRACKET WITH DOUBLE STROKE + +02E58 +RIGHT SQUARE BRACKET WITH DOUBLE STROKE + +02E59 +TOP HALF LEFT PARENTHESIS + +02E5A +TOP HALF RIGHT PARENTHESIS + +02E5B +BOTTOM HALF LEFT PARENTHESIS + +02E5C +BOTTOM HALF RIGHT PARENTHESIS + +02E5D +OBLIQUE HYPHEN + +02E80 +CJK RADICAL REPEAT + +02E81 +CJK RADICAL CLIFF + +02E82 +CJK RADICAL SECOND ONE + +02E83 +CJK RADICAL SECOND TWO + +02E84 +CJK RADICAL SECOND THREE + +02E85 +CJK RADICAL PERSON + +02E86 +CJK RADICAL BOX + +02E87 +CJK RADICAL TABLE + +02E88 +CJK RADICAL KNIFE ONE + +02E89 +CJK RADICAL KNIFE TWO + +02E8A +CJK RADICAL DIVINATION + +02E8B +CJK RADICAL SEAL + +02E8C +CJK RADICAL SMALL ONE + +02E8D +CJK RADICAL SMALL TWO + +02E8E +CJK RADICAL LAME ONE + +02E8F +CJK RADICAL LAME TWO + +02E90 +CJK RADICAL LAME THREE + +02E91 +CJK RADICAL LAME FOUR + +02E92 +CJK RADICAL SNAKE + +02E93 +CJK RADICAL THREAD + +02E94 +CJK RADICAL SNOUT ONE + +02E95 +CJK RADICAL SNOUT TWO + +02E96 +CJK RADICAL HEART ONE + +02E97 +CJK RADICAL HEART TWO + +02E98 +CJK RADICAL HAND + +02E99 +CJK RADICAL RAP + +02E9B +CJK RADICAL CHOKE + +02E9C +CJK RADICAL SUN + +02E9D +CJK RADICAL MOON + +02E9E +CJK RADICAL DEATH + +02E9F +CJK RADICAL MOTHER + +02EA0 +CJK RADICAL CIVILIAN + +02EA1 +CJK RADICAL WATER ONE + +02EA2 +CJK RADICAL WATER TWO + +02EA3 +CJK RADICAL FIRE + +02EA4 +CJK RADICAL PAW ONE + +02EA5 +CJK RADICAL PAW TWO + +02EA6 +CJK RADICAL SIMPLIFIED HALF TREE TRUNK + +02EA7 +CJK RADICAL COW + +02EA8 +CJK RADICAL DOG + +02EA9 +CJK RADICAL JADE + +02EAA +CJK RADICAL BOLT OF CLOTH + +02EAB +CJK RADICAL EYE + +02EAC +CJK RADICAL SPIRIT ONE + +02EAD +CJK RADICAL SPIRIT TWO + +02EAE +CJK RADICAL BAMBOO + +02EAF +CJK RADICAL SILK + +02EB0 +CJK RADICAL C-SIMPLIFIED SILK + +02EB1 +CJK RADICAL NET ONE + +02EB2 +CJK RADICAL NET TWO + +02EB3 +CJK RADICAL NET THREE + +02EB4 +CJK RADICAL NET FOUR + +02EB5 +CJK RADICAL MESH + +02EB6 +CJK RADICAL SHEEP + +02EB7 +CJK RADICAL RAM + +02EB8 +CJK RADICAL EWE + +02EB9 +CJK RADICAL OLD + +02EBA +CJK RADICAL BRUSH ONE + +02EBB +CJK RADICAL BRUSH TWO + +02EBC +CJK RADICAL MEAT + +02EBD +CJK RADICAL MORTAR + +02EBE +CJK RADICAL GRASS ONE + +02EBF +CJK RADICAL GRASS TWO + +02EC0 +CJK RADICAL GRASS THREE + +02EC1 +CJK RADICAL TIGER + +02EC2 +CJK RADICAL CLOTHES + +02EC3 +CJK RADICAL WEST ONE + +02EC4 +CJK RADICAL WEST TWO + +02EC5 +CJK RADICAL C-SIMPLIFIED SEE + +02EC6 +CJK RADICAL SIMPLIFIED HORN + +02EC7 +CJK RADICAL HORN + +02EC8 +CJK RADICAL C-SIMPLIFIED SPEECH + +02EC9 +CJK RADICAL C-SIMPLIFIED SHELL + +02ECA +CJK RADICAL FOOT + +02ECB +CJK RADICAL C-SIMPLIFIED CART + +02ECC +CJK RADICAL SIMPLIFIED WALK + +02ECD +CJK RADICAL WALK ONE + +02ECE +CJK RADICAL WALK TWO + +02ECF +CJK RADICAL CITY + +02ED0 +CJK RADICAL C-SIMPLIFIED GOLD + +02ED1 +CJK RADICAL LONG ONE + +02ED2 +CJK RADICAL LONG TWO + +02ED3 +CJK RADICAL C-SIMPLIFIED LONG + +02ED4 +CJK RADICAL C-SIMPLIFIED GATE + +02ED5 +CJK RADICAL MOUND ONE + +02ED6 +CJK RADICAL MOUND TWO + +02ED7 +CJK RADICAL RAIN + +02ED8 +CJK RADICAL BLUE + +02ED9 +CJK RADICAL C-SIMPLIFIED TANNED LEATHER + +02EDA +CJK RADICAL C-SIMPLIFIED LEAF + +02EDB +CJK RADICAL C-SIMPLIFIED WIND + +02EDC +CJK RADICAL C-SIMPLIFIED FLY + +02EDD +CJK RADICAL EAT ONE + +02EDE +CJK RADICAL EAT TWO + +02EDF +CJK RADICAL EAT THREE + +02EE0 +CJK RADICAL C-SIMPLIFIED EAT + +02EE1 +CJK RADICAL HEAD + +02EE2 +CJK RADICAL C-SIMPLIFIED HORSE + +02EE3 +CJK RADICAL BONE + +02EE4 +CJK RADICAL GHOST + +02EE5 +CJK RADICAL C-SIMPLIFIED FISH + +02EE6 +CJK RADICAL C-SIMPLIFIED BIRD + +02EE7 +CJK RADICAL C-SIMPLIFIED SALT + +02EE8 +CJK RADICAL SIMPLIFIED WHEAT + +02EE9 +CJK RADICAL SIMPLIFIED YELLOW + +02EEA +CJK RADICAL C-SIMPLIFIED FROG + +02EEB +CJK RADICAL J-SIMPLIFIED EVEN + +02EEC +CJK RADICAL C-SIMPLIFIED EVEN + +02EED +CJK RADICAL J-SIMPLIFIED TOOTH + +02EEE +CJK RADICAL C-SIMPLIFIED TOOTH + +02EEF +CJK RADICAL J-SIMPLIFIED DRAGON + +02EF0 +CJK RADICAL C-SIMPLIFIED DRAGON + +02EF1 +CJK RADICAL TURTLE + +02EF2 +CJK RADICAL J-SIMPLIFIED TURTLE + +02EF3 +CJK RADICAL C-SIMPLIFIED TURTLE + +02F00 +KANGXI RADICAL ONE + +02F01 +KANGXI RADICAL LINE + +02F02 +KANGXI RADICAL DOT + +02F03 +KANGXI RADICAL SLASH + +02F04 +KANGXI RADICAL SECOND + +02F05 +KANGXI RADICAL HOOK + +02F06 +KANGXI RADICAL TWO + +02F07 +KANGXI RADICAL LID + +02F08 +KANGXI RADICAL MAN + +02F09 +KANGXI RADICAL LEGS + +02F0A +KANGXI RADICAL ENTER + +02F0B +KANGXI RADICAL EIGHT + +02F0C +KANGXI RADICAL DOWN BOX + +02F0D +KANGXI RADICAL COVER + +02F0E +KANGXI RADICAL ICE + +02F0F +KANGXI RADICAL TABLE + +02F10 +KANGXI RADICAL OPEN BOX + +02F11 +KANGXI RADICAL KNIFE + +02F12 +KANGXI RADICAL POWER + +02F13 +KANGXI RADICAL WRAP + +02F14 +KANGXI RADICAL SPOON + +02F15 +KANGXI RADICAL RIGHT OPEN BOX + +02F16 +KANGXI RADICAL HIDING ENCLOSURE + +02F17 +KANGXI RADICAL TEN + +02F18 +KANGXI RADICAL DIVINATION + +02F19 +KANGXI RADICAL SEAL + +02F1A +KANGXI RADICAL CLIFF + +02F1B +KANGXI RADICAL PRIVATE + +02F1C +KANGXI RADICAL AGAIN + +02F1D +KANGXI RADICAL MOUTH + +02F1E +KANGXI RADICAL ENCLOSURE + +02F1F +KANGXI RADICAL EARTH + +02F20 +KANGXI RADICAL SCHOLAR + +02F21 +KANGXI RADICAL GO + +02F22 +KANGXI RADICAL GO SLOWLY + +02F23 +KANGXI RADICAL EVENING + +02F24 +KANGXI RADICAL BIG + +02F25 +KANGXI RADICAL WOMAN + +02F26 +KANGXI RADICAL CHILD + +02F27 +KANGXI RADICAL ROOF + +02F28 +KANGXI RADICAL INCH + +02F29 +KANGXI RADICAL SMALL + +02F2A +KANGXI RADICAL LAME + +02F2B +KANGXI RADICAL CORPSE + +02F2C +KANGXI RADICAL SPROUT + +02F2D +KANGXI RADICAL MOUNTAIN + +02F2E +KANGXI RADICAL RIVER + +02F2F +KANGXI RADICAL WORK + +02F30 +KANGXI RADICAL ONESELF + +02F31 +KANGXI RADICAL TURBAN + +02F32 +KANGXI RADICAL DRY + +02F33 +KANGXI RADICAL SHORT THREAD + +02F34 +KANGXI RADICAL DOTTED CLIFF + +02F35 +KANGXI RADICAL LONG STRIDE + +02F36 +KANGXI RADICAL TWO HANDS + +02F37 +KANGXI RADICAL SHOOT + +02F38 +KANGXI RADICAL BOW + +02F39 +KANGXI RADICAL SNOUT + +02F3A +KANGXI RADICAL BRISTLE + +02F3B +KANGXI RADICAL STEP + +02F3C +KANGXI RADICAL HEART + +02F3D +KANGXI RADICAL HALBERD + +02F3E +KANGXI RADICAL DOOR + +02F3F +KANGXI RADICAL HAND + +02F40 +KANGXI RADICAL BRANCH + +02F41 +KANGXI RADICAL RAP + +02F42 +KANGXI RADICAL SCRIPT + +02F43 +KANGXI RADICAL DIPPER + +02F44 +KANGXI RADICAL AXE + +02F45 +KANGXI RADICAL SQUARE + +02F46 +KANGXI RADICAL NOT + +02F47 +KANGXI RADICAL SUN + +02F48 +KANGXI RADICAL SAY + +02F49 +KANGXI RADICAL MOON + +02F4A +KANGXI RADICAL TREE + +02F4B +KANGXI RADICAL LACK + +02F4C +KANGXI RADICAL STOP + +02F4D +KANGXI RADICAL DEATH + +02F4E +KANGXI RADICAL WEAPON + +02F4F +KANGXI RADICAL DO NOT + +02F50 +KANGXI RADICAL COMPARE + +02F51 +KANGXI RADICAL FUR + +02F52 +KANGXI RADICAL CLAN + +02F53 +KANGXI RADICAL STEAM + +02F54 +KANGXI RADICAL WATER + +02F55 +KANGXI RADICAL FIRE + +02F56 +KANGXI RADICAL CLAW + +02F57 +KANGXI RADICAL FATHER + +02F58 +KANGXI RADICAL DOUBLE X + +02F59 +KANGXI RADICAL HALF TREE TRUNK + +02F5A +KANGXI RADICAL SLICE + +02F5B +KANGXI RADICAL FANG + +02F5C +KANGXI RADICAL COW + +02F5D +KANGXI RADICAL DOG + +02F5E +KANGXI RADICAL PROFOUND + +02F5F +KANGXI RADICAL JADE + +02F60 +KANGXI RADICAL MELON + +02F61 +KANGXI RADICAL TILE + +02F62 +KANGXI RADICAL SWEET + +02F63 +KANGXI RADICAL LIFE + +02F64 +KANGXI RADICAL USE + +02F65 +KANGXI RADICAL FIELD + +02F66 +KANGXI RADICAL BOLT OF CLOTH + +02F67 +KANGXI RADICAL SICKNESS + +02F68 +KANGXI RADICAL DOTTED TENT + +02F69 +KANGXI RADICAL WHITE + +02F6A +KANGXI RADICAL SKIN + +02F6B +KANGXI RADICAL DISH + +02F6C +KANGXI RADICAL EYE + +02F6D +KANGXI RADICAL SPEAR + +02F6E +KANGXI RADICAL ARROW + +02F6F +KANGXI RADICAL STONE + +02F70 +KANGXI RADICAL SPIRIT + +02F71 +KANGXI RADICAL TRACK + +02F72 +KANGXI RADICAL GRAIN + +02F73 +KANGXI RADICAL CAVE + +02F74 +KANGXI RADICAL STAND + +02F75 +KANGXI RADICAL BAMBOO + +02F76 +KANGXI RADICAL RICE + +02F77 +KANGXI RADICAL SILK + +02F78 +KANGXI RADICAL JAR + +02F79 +KANGXI RADICAL NET + +02F7A +KANGXI RADICAL SHEEP + +02F7B +KANGXI RADICAL FEATHER + +02F7C +KANGXI RADICAL OLD + +02F7D +KANGXI RADICAL AND + +02F7E +KANGXI RADICAL PLOW + +02F7F +KANGXI RADICAL EAR + +02F80 +KANGXI RADICAL BRUSH + +02F81 +KANGXI RADICAL MEAT + +02F82 +KANGXI RADICAL MINISTER + +02F83 +KANGXI RADICAL SELF + +02F84 +KANGXI RADICAL ARRIVE + +02F85 +KANGXI RADICAL MORTAR + +02F86 +KANGXI RADICAL TONGUE + +02F87 +KANGXI RADICAL OPPOSE + +02F88 +KANGXI RADICAL BOAT + +02F89 +KANGXI RADICAL STOPPING + +02F8A +KANGXI RADICAL COLOR + +02F8B +KANGXI RADICAL GRASS + +02F8C +KANGXI RADICAL TIGER + +02F8D +KANGXI RADICAL INSECT + +02F8E +KANGXI RADICAL BLOOD + +02F8F +KANGXI RADICAL WALK ENCLOSURE + +02F90 +KANGXI RADICAL CLOTHES + +02F91 +KANGXI RADICAL WEST + +02F92 +KANGXI RADICAL SEE + +02F93 +KANGXI RADICAL HORN + +02F94 +KANGXI RADICAL SPEECH + +02F95 +KANGXI RADICAL VALLEY + +02F96 +KANGXI RADICAL BEAN + +02F97 +KANGXI RADICAL PIG + +02F98 +KANGXI RADICAL BADGER + +02F99 +KANGXI RADICAL SHELL + +02F9A +KANGXI RADICAL RED + +02F9B +KANGXI RADICAL RUN + +02F9C +KANGXI RADICAL FOOT + +02F9D +KANGXI RADICAL BODY + +02F9E +KANGXI RADICAL CART + +02F9F +KANGXI RADICAL BITTER + +02FA0 +KANGXI RADICAL MORNING + +02FA1 +KANGXI RADICAL WALK + +02FA2 +KANGXI RADICAL CITY + +02FA3 +KANGXI RADICAL WINE + +02FA4 +KANGXI RADICAL DISTINGUISH + +02FA5 +KANGXI RADICAL VILLAGE + +02FA6 +KANGXI RADICAL GOLD + +02FA7 +KANGXI RADICAL LONG + +02FA8 +KANGXI RADICAL GATE + +02FA9 +KANGXI RADICAL MOUND + +02FAA +KANGXI RADICAL SLAVE + +02FAB +KANGXI RADICAL SHORT TAILED BIRD + +02FAC +KANGXI RADICAL RAIN + +02FAD +KANGXI RADICAL BLUE + +02FAE +KANGXI RADICAL WRONG + +02FAF +KANGXI RADICAL FACE + +02FB0 +KANGXI RADICAL LEATHER + +02FB1 +KANGXI RADICAL TANNED LEATHER + +02FB2 +KANGXI RADICAL LEEK + +02FB3 +KANGXI RADICAL SOUND + +02FB4 +KANGXI RADICAL LEAF + +02FB5 +KANGXI RADICAL WIND + +02FB6 +KANGXI RADICAL FLY + +02FB7 +KANGXI RADICAL EAT + +02FB8 +KANGXI RADICAL HEAD + +02FB9 +KANGXI RADICAL FRAGRANT + +02FBA +KANGXI RADICAL HORSE + +02FBB +KANGXI RADICAL BONE + +02FBC +KANGXI RADICAL TALL + +02FBD +KANGXI RADICAL HAIR + +02FBE +KANGXI RADICAL FIGHT + +02FBF +KANGXI RADICAL SACRIFICIAL WINE + +02FC0 +KANGXI RADICAL CAULDRON + +02FC1 +KANGXI RADICAL GHOST + +02FC2 +KANGXI RADICAL FISH + +02FC3 +KANGXI RADICAL BIRD + +02FC4 +KANGXI RADICAL SALT + +02FC5 +KANGXI RADICAL DEER + +02FC6 +KANGXI RADICAL WHEAT + +02FC7 +KANGXI RADICAL HEMP + +02FC8 +KANGXI RADICAL YELLOW + +02FC9 +KANGXI RADICAL MILLET + +02FCA +KANGXI RADICAL BLACK + +02FCB +KANGXI RADICAL EMBROIDERY + +02FCC +KANGXI RADICAL FROG + +02FCD +KANGXI RADICAL TRIPOD + +02FCE +KANGXI RADICAL DRUM + +02FCF +KANGXI RADICAL RAT + +02FD0 +KANGXI RADICAL NOSE + +02FD1 +KANGXI RADICAL EVEN + +02FD2 +KANGXI RADICAL TOOTH + +02FD3 +KANGXI RADICAL DRAGON + +02FD4 +KANGXI RADICAL TURTLE + +02FD5 +KANGXI RADICAL FLUTE + +02FF0 +IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHT + +02FF1 +IDEOGRAPHIC DESCRIPTION CHARACTER ABOVE TO BELOW + +02FF2 +IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO MIDDLE AND RIGHT + +02FF3 +IDEOGRAPHIC DESCRIPTION CHARACTER ABOVE TO MIDDLE AND BELOW + +02FF4 +IDEOGRAPHIC DESCRIPTION CHARACTER FULL SURROUND + +02FF5 +IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM ABOVE + +02FF6 +IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM BELOW + +02FF7 +IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM LEFT + +02FF8 +IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM UPPER LEFT + +02FF9 +IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM UPPER RIGHT + +02FFA +IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM LOWER LEFT + +02FFB +IDEOGRAPHIC DESCRIPTION CHARACTER OVERLAID + +02FFC +IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM RIGHT + +02FFD +IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM LOWER RIGHT + +02FFE +IDEOGRAPHIC DESCRIPTION CHARACTER HORIZONTAL REFLECTION + +02FFF +IDEOGRAPHIC DESCRIPTION CHARACTER ROTATION + +03000 +IDEOGRAPHIC SPACE + +03001 +IDEOGRAPHIC COMMA + +03002 +IDEOGRAPHIC FULL STOP + +03003 +DITTO MARK + +03004 +JAPANESE INDUSTRIAL STANDARD SYMBOL + +03005 +IDEOGRAPHIC ITERATION MARK + +03006 +IDEOGRAPHIC CLOSING MARK + +03007 +IDEOGRAPHIC NUMBER ZERO + +03008 +LEFT ANGLE BRACKET + +03009 +RIGHT ANGLE BRACKET + +0300A +LEFT DOUBLE ANGLE BRACKET + +0300B +RIGHT DOUBLE ANGLE BRACKET + +0300C +LEFT CORNER BRACKET + +0300D +RIGHT CORNER BRACKET + +0300E +LEFT WHITE CORNER BRACKET + +0300F +RIGHT WHITE CORNER BRACKET + +03010 +LEFT BLACK LENTICULAR BRACKET + +03011 +RIGHT BLACK LENTICULAR BRACKET + +03012 +POSTAL MARK + +03013 +GETA MARK + +03014 +LEFT TORTOISE SHELL BRACKET + +03015 +RIGHT TORTOISE SHELL BRACKET + +03016 +LEFT WHITE LENTICULAR BRACKET + +03017 +RIGHT WHITE LENTICULAR BRACKET + +03018 +LEFT WHITE TORTOISE SHELL BRACKET + +03019 +RIGHT WHITE TORTOISE SHELL BRACKET + +0301A +LEFT WHITE SQUARE BRACKET + +0301B +RIGHT WHITE SQUARE BRACKET + +0301C +WAVE DASH + +0301D +REVERSED DOUBLE PRIME QUOTATION MARK + +0301E +DOUBLE PRIME QUOTATION MARK + +0301F +LOW DOUBLE PRIME QUOTATION MARK + +03020 +POSTAL MARK FACE + +03021 +HANGZHOU NUMERAL ONE + +03022 +HANGZHOU NUMERAL TWO + +03023 +HANGZHOU NUMERAL THREE + +03024 +HANGZHOU NUMERAL FOUR + +03025 +HANGZHOU NUMERAL FIVE + +03026 +HANGZHOU NUMERAL SIX + +03027 +HANGZHOU NUMERAL SEVEN + +03028 +HANGZHOU NUMERAL EIGHT + +03029 +HANGZHOU NUMERAL NINE + +0302A +IDEOGRAPHIC LEVEL TONE MARK + +0302B +IDEOGRAPHIC RISING TONE MARK + +0302C +IDEOGRAPHIC DEPARTING TONE MARK + +0302D +IDEOGRAPHIC ENTERING TONE MARK + +0302E +HANGUL SINGLE DOT TONE MARK + +0302F +HANGUL DOUBLE DOT TONE MARK + +03030 +WAVY DASH + +03031 +VERTICAL KANA REPEAT MARK + +03032 +VERTICAL KANA REPEAT WITH VOICED SOUND MARK + +03033 +VERTICAL KANA REPEAT MARK UPPER HALF + +03034 +VERTICAL KANA REPEAT WITH VOICED SOUND MARK UPPER HALF + +03035 +VERTICAL KANA REPEAT MARK LOWER HALF + +03036 +CIRCLED POSTAL MARK + +03037 +IDEOGRAPHIC TELEGRAPH LINE FEED SEPARATOR SYMBOL + +03038 +HANGZHOU NUMERAL TEN + +03039 +HANGZHOU NUMERAL TWENTY + +0303A +HANGZHOU NUMERAL THIRTY + +0303B +VERTICAL IDEOGRAPHIC ITERATION MARK + +0303C +MASU MARK + +0303D +PART ALTERNATION MARK + +0303E +IDEOGRAPHIC VARIATION INDICATOR + +0303F +IDEOGRAPHIC HALF FILL SPACE + +03041 +HIRAGANA LETTER SMALL A + +03042 +HIRAGANA LETTER A + +03043 +HIRAGANA LETTER SMALL I + +03044 +HIRAGANA LETTER I + +03045 +HIRAGANA LETTER SMALL U + +03046 +HIRAGANA LETTER U + +03047 +HIRAGANA LETTER SMALL E + +03048 +HIRAGANA LETTER E + +03049 +HIRAGANA LETTER SMALL O + +0304A +HIRAGANA LETTER O + +0304B +HIRAGANA LETTER KA + +0304C +HIRAGANA LETTER GA + +0304D +HIRAGANA LETTER KI + +0304E +HIRAGANA LETTER GI + +0304F +HIRAGANA LETTER KU + +03050 +HIRAGANA LETTER GU + +03051 +HIRAGANA LETTER KE + +03052 +HIRAGANA LETTER GE + +03053 +HIRAGANA LETTER KO + +03054 +HIRAGANA LETTER GO + +03055 +HIRAGANA LETTER SA + +03056 +HIRAGANA LETTER ZA + +03057 +HIRAGANA LETTER SI + +03058 +HIRAGANA LETTER ZI + +03059 +HIRAGANA LETTER SU + +0305A +HIRAGANA LETTER ZU + +0305B +HIRAGANA LETTER SE + +0305C +HIRAGANA LETTER ZE + +0305D +HIRAGANA LETTER SO + +0305E +HIRAGANA LETTER ZO + +0305F +HIRAGANA LETTER TA + +03060 +HIRAGANA LETTER DA + +03061 +HIRAGANA LETTER TI + +03062 +HIRAGANA LETTER DI + +03063 +HIRAGANA LETTER SMALL TU + +03064 +HIRAGANA LETTER TU + +03065 +HIRAGANA LETTER DU + +03066 +HIRAGANA LETTER TE + +03067 +HIRAGANA LETTER DE + +03068 +HIRAGANA LETTER TO + +03069 +HIRAGANA LETTER DO + +0306A +HIRAGANA LETTER NA + +0306B +HIRAGANA LETTER NI + +0306C +HIRAGANA LETTER NU + +0306D +HIRAGANA LETTER NE + +0306E +HIRAGANA LETTER NO + +0306F +HIRAGANA LETTER HA + +03070 +HIRAGANA LETTER BA + +03071 +HIRAGANA LETTER PA + +03072 +HIRAGANA LETTER HI + +03073 +HIRAGANA LETTER BI + +03074 +HIRAGANA LETTER PI + +03075 +HIRAGANA LETTER HU + +03076 +HIRAGANA LETTER BU + +03077 +HIRAGANA LETTER PU + +03078 +HIRAGANA LETTER HE + +03079 +HIRAGANA LETTER BE + +0307A +HIRAGANA LETTER PE + +0307B +HIRAGANA LETTER HO + +0307C +HIRAGANA LETTER BO + +0307D +HIRAGANA LETTER PO + +0307E +HIRAGANA LETTER MA + +0307F +HIRAGANA LETTER MI + +03080 +HIRAGANA LETTER MU + +03081 +HIRAGANA LETTER ME + +03082 +HIRAGANA LETTER MO + +03083 +HIRAGANA LETTER SMALL YA + +03084 +HIRAGANA LETTER YA + +03085 +HIRAGANA LETTER SMALL YU + +03086 +HIRAGANA LETTER YU + +03087 +HIRAGANA LETTER SMALL YO + +03088 +HIRAGANA LETTER YO + +03089 +HIRAGANA LETTER RA + +0308A +HIRAGANA LETTER RI + +0308B +HIRAGANA LETTER RU + +0308C +HIRAGANA LETTER RE + +0308D +HIRAGANA LETTER RO + +0308E +HIRAGANA LETTER SMALL WA + +0308F +HIRAGANA LETTER WA + +03090 +HIRAGANA LETTER WI + +03091 +HIRAGANA LETTER WE + +03092 +HIRAGANA LETTER WO + +03093 +HIRAGANA LETTER N + +03094 +HIRAGANA LETTER VU + +03095 +HIRAGANA LETTER SMALL KA + +03096 +HIRAGANA LETTER SMALL KE + +03099 +COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK + +0309A +COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK + +0309B +KATAKANA-HIRAGANA VOICED SOUND MARK + +0309C +KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK + +0309D +HIRAGANA ITERATION MARK + +0309E +HIRAGANA VOICED ITERATION MARK + +0309F +HIRAGANA DIGRAPH YORI + +030A0 +KATAKANA-HIRAGANA DOUBLE HYPHEN + +030A1 +KATAKANA LETTER SMALL A + +030A2 +KATAKANA LETTER A + +030A3 +KATAKANA LETTER SMALL I + +030A4 +KATAKANA LETTER I + +030A5 +KATAKANA LETTER SMALL U + +030A6 +KATAKANA LETTER U + +030A7 +KATAKANA LETTER SMALL E + +030A8 +KATAKANA LETTER E + +030A9 +KATAKANA LETTER SMALL O + +030AA +KATAKANA LETTER O + +030AB +KATAKANA LETTER KA + +030AC +KATAKANA LETTER GA + +030AD +KATAKANA LETTER KI + +030AE +KATAKANA LETTER GI + +030AF +KATAKANA LETTER KU + +030B0 +KATAKANA LETTER GU + +030B1 +KATAKANA LETTER KE + +030B2 +KATAKANA LETTER GE + +030B3 +KATAKANA LETTER KO + +030B4 +KATAKANA LETTER GO + +030B5 +KATAKANA LETTER SA + +030B6 +KATAKANA LETTER ZA + +030B7 +KATAKANA LETTER SI + +030B8 +KATAKANA LETTER ZI + +030B9 +KATAKANA LETTER SU + +030BA +KATAKANA LETTER ZU + +030BB +KATAKANA LETTER SE + +030BC +KATAKANA LETTER ZE + +030BD +KATAKANA LETTER SO + +030BE +KATAKANA LETTER ZO + +030BF +KATAKANA LETTER TA + +030C0 +KATAKANA LETTER DA + +030C1 +KATAKANA LETTER TI + +030C2 +KATAKANA LETTER DI + +030C3 +KATAKANA LETTER SMALL TU + +030C4 +KATAKANA LETTER TU + +030C5 +KATAKANA LETTER DU + +030C6 +KATAKANA LETTER TE + +030C7 +KATAKANA LETTER DE + +030C8 +KATAKANA LETTER TO + +030C9 +KATAKANA LETTER DO + +030CA +KATAKANA LETTER NA + +030CB +KATAKANA LETTER NI + +030CC +KATAKANA LETTER NU + +030CD +KATAKANA LETTER NE + +030CE +KATAKANA LETTER NO + +030CF +KATAKANA LETTER HA + +030D0 +KATAKANA LETTER BA + +030D1 +KATAKANA LETTER PA + +030D2 +KATAKANA LETTER HI + +030D3 +KATAKANA LETTER BI + +030D4 +KATAKANA LETTER PI + +030D5 +KATAKANA LETTER HU + +030D6 +KATAKANA LETTER BU + +030D7 +KATAKANA LETTER PU + +030D8 +KATAKANA LETTER HE + +030D9 +KATAKANA LETTER BE + +030DA +KATAKANA LETTER PE + +030DB +KATAKANA LETTER HO + +030DC +KATAKANA LETTER BO + +030DD +KATAKANA LETTER PO + +030DE +KATAKANA LETTER MA + +030DF +KATAKANA LETTER MI + +030E0 +KATAKANA LETTER MU + +030E1 +KATAKANA LETTER ME + +030E2 +KATAKANA LETTER MO + +030E3 +KATAKANA LETTER SMALL YA + +030E4 +KATAKANA LETTER YA + +030E5 +KATAKANA LETTER SMALL YU + +030E6 +KATAKANA LETTER YU + +030E7 +KATAKANA LETTER SMALL YO + +030E8 +KATAKANA LETTER YO + +030E9 +KATAKANA LETTER RA + +030EA +KATAKANA LETTER RI + +030EB +KATAKANA LETTER RU + +030EC +KATAKANA LETTER RE + +030ED +KATAKANA LETTER RO + +030EE +KATAKANA LETTER SMALL WA + +030EF +KATAKANA LETTER WA + +030F0 +KATAKANA LETTER WI + +030F1 +KATAKANA LETTER WE + +030F2 +KATAKANA LETTER WO + +030F3 +KATAKANA LETTER N + +030F4 +KATAKANA LETTER VU + +030F5 +KATAKANA LETTER SMALL KA + +030F6 +KATAKANA LETTER SMALL KE + +030F7 +KATAKANA LETTER VA + +030F8 +KATAKANA LETTER VI + +030F9 +KATAKANA LETTER VE + +030FA +KATAKANA LETTER VO + +030FB +KATAKANA MIDDLE DOT + +030FC +KATAKANA-HIRAGANA PROLONGED SOUND MARK + +030FD +KATAKANA ITERATION MARK + +030FE +KATAKANA VOICED ITERATION MARK + +030FF +KATAKANA DIGRAPH KOTO + +03105 +BOPOMOFO LETTER B + +03106 +BOPOMOFO LETTER P + +03107 +BOPOMOFO LETTER M + +03108 +BOPOMOFO LETTER F + +03109 +BOPOMOFO LETTER D + +0310A +BOPOMOFO LETTER T + +0310B +BOPOMOFO LETTER N + +0310C +BOPOMOFO LETTER L + +0310D +BOPOMOFO LETTER G + +0310E +BOPOMOFO LETTER K + +0310F +BOPOMOFO LETTER H + +03110 +BOPOMOFO LETTER J + +03111 +BOPOMOFO LETTER Q + +03112 +BOPOMOFO LETTER X + +03113 +BOPOMOFO LETTER ZH + +03114 +BOPOMOFO LETTER CH + +03115 +BOPOMOFO LETTER SH + +03116 +BOPOMOFO LETTER R + +03117 +BOPOMOFO LETTER Z + +03118 +BOPOMOFO LETTER C + +03119 +BOPOMOFO LETTER S + +0311A +BOPOMOFO LETTER A + +0311B +BOPOMOFO LETTER O + +0311C +BOPOMOFO LETTER E + +0311D +BOPOMOFO LETTER EH + +0311E +BOPOMOFO LETTER AI + +0311F +BOPOMOFO LETTER EI + +03120 +BOPOMOFO LETTER AU + +03121 +BOPOMOFO LETTER OU + +03122 +BOPOMOFO LETTER AN + +03123 +BOPOMOFO LETTER EN + +03124 +BOPOMOFO LETTER ANG + +03125 +BOPOMOFO LETTER ENG + +03126 +BOPOMOFO LETTER ER + +03127 +BOPOMOFO LETTER I + +03128 +BOPOMOFO LETTER U + +03129 +BOPOMOFO LETTER IU + +0312A +BOPOMOFO LETTER V + +0312B +BOPOMOFO LETTER NG + +0312C +BOPOMOFO LETTER GN + +0312D +BOPOMOFO LETTER IH + +0312E +BOPOMOFO LETTER O WITH DOT ABOVE + +0312F +BOPOMOFO LETTER NN + +03131 +HANGUL LETTER KIYEOK + +03132 +HANGUL LETTER SSANGKIYEOK + +03133 +HANGUL LETTER KIYEOK-SIOS + +03134 +HANGUL LETTER NIEUN + +03135 +HANGUL LETTER NIEUN-CIEUC + +03136 +HANGUL LETTER NIEUN-HIEUH + +03137 +HANGUL LETTER TIKEUT + +03138 +HANGUL LETTER SSANGTIKEUT + +03139 +HANGUL LETTER RIEUL + +0313A +HANGUL LETTER RIEUL-KIYEOK + +0313B +HANGUL LETTER RIEUL-MIEUM + +0313C +HANGUL LETTER RIEUL-PIEUP + +0313D +HANGUL LETTER RIEUL-SIOS + +0313E +HANGUL LETTER RIEUL-THIEUTH + +0313F +HANGUL LETTER RIEUL-PHIEUPH + +03140 +HANGUL LETTER RIEUL-HIEUH + +03141 +HANGUL LETTER MIEUM + +03142 +HANGUL LETTER PIEUP + +03143 +HANGUL LETTER SSANGPIEUP + +03144 +HANGUL LETTER PIEUP-SIOS + +03145 +HANGUL LETTER SIOS + +03146 +HANGUL LETTER SSANGSIOS + +03147 +HANGUL LETTER IEUNG + +03148 +HANGUL LETTER CIEUC + +03149 +HANGUL LETTER SSANGCIEUC + +0314A +HANGUL LETTER CHIEUCH + +0314B +HANGUL LETTER KHIEUKH + +0314C +HANGUL LETTER THIEUTH + +0314D +HANGUL LETTER PHIEUPH + +0314E +HANGUL LETTER HIEUH + +0314F +HANGUL LETTER A + +03150 +HANGUL LETTER AE + +03151 +HANGUL LETTER YA + +03152 +HANGUL LETTER YAE + +03153 +HANGUL LETTER EO + +03154 +HANGUL LETTER E + +03155 +HANGUL LETTER YEO + +03156 +HANGUL LETTER YE + +03157 +HANGUL LETTER O + +03158 +HANGUL LETTER WA + +03159 +HANGUL LETTER WAE + +0315A +HANGUL LETTER OE + +0315B +HANGUL LETTER YO + +0315C +HANGUL LETTER U + +0315D +HANGUL LETTER WEO + +0315E +HANGUL LETTER WE + +0315F +HANGUL LETTER WI + +03160 +HANGUL LETTER YU + +03161 +HANGUL LETTER EU + +03162 +HANGUL LETTER YI + +03163 +HANGUL LETTER I + +03164 +HANGUL FILLER + +03165 +HANGUL LETTER SSANGNIEUN + +03166 +HANGUL LETTER NIEUN-TIKEUT + +03167 +HANGUL LETTER NIEUN-SIOS + +03168 +HANGUL LETTER NIEUN-PANSIOS + +03169 +HANGUL LETTER RIEUL-KIYEOK-SIOS + +0316A +HANGUL LETTER RIEUL-TIKEUT + +0316B +HANGUL LETTER RIEUL-PIEUP-SIOS + +0316C +HANGUL LETTER RIEUL-PANSIOS + +0316D +HANGUL LETTER RIEUL-YEORINHIEUH + +0316E +HANGUL LETTER MIEUM-PIEUP + +0316F +HANGUL LETTER MIEUM-SIOS + +03170 +HANGUL LETTER MIEUM-PANSIOS + +03171 +HANGUL LETTER KAPYEOUNMIEUM + +03172 +HANGUL LETTER PIEUP-KIYEOK + +03173 +HANGUL LETTER PIEUP-TIKEUT + +03174 +HANGUL LETTER PIEUP-SIOS-KIYEOK + +03175 +HANGUL LETTER PIEUP-SIOS-TIKEUT + +03176 +HANGUL LETTER PIEUP-CIEUC + +03177 +HANGUL LETTER PIEUP-THIEUTH + +03178 +HANGUL LETTER KAPYEOUNPIEUP + +03179 +HANGUL LETTER KAPYEOUNSSANGPIEUP + +0317A +HANGUL LETTER SIOS-KIYEOK + +0317B +HANGUL LETTER SIOS-NIEUN + +0317C +HANGUL LETTER SIOS-TIKEUT + +0317D +HANGUL LETTER SIOS-PIEUP + +0317E +HANGUL LETTER SIOS-CIEUC + +0317F +HANGUL LETTER PANSIOS + +03180 +HANGUL LETTER SSANGIEUNG + +03181 +HANGUL LETTER YESIEUNG + +03182 +HANGUL LETTER YESIEUNG-SIOS + +03183 +HANGUL LETTER YESIEUNG-PANSIOS + +03184 +HANGUL LETTER KAPYEOUNPHIEUPH + +03185 +HANGUL LETTER SSANGHIEUH + +03186 +HANGUL LETTER YEORINHIEUH + +03187 +HANGUL LETTER YO-YA + +03188 +HANGUL LETTER YO-YAE + +03189 +HANGUL LETTER YO-I + +0318A +HANGUL LETTER YU-YEO + +0318B +HANGUL LETTER YU-YE + +0318C +HANGUL LETTER YU-I + +0318D +HANGUL LETTER ARAEA + +0318E +HANGUL LETTER ARAEAE + +03190 +IDEOGRAPHIC ANNOTATION LINKING MARK + +03191 +IDEOGRAPHIC ANNOTATION REVERSE MARK + +03192 +IDEOGRAPHIC ANNOTATION ONE MARK + +03193 +IDEOGRAPHIC ANNOTATION TWO MARK + +03194 +IDEOGRAPHIC ANNOTATION THREE MARK + +03195 +IDEOGRAPHIC ANNOTATION FOUR MARK + +03196 +IDEOGRAPHIC ANNOTATION TOP MARK + +03197 +IDEOGRAPHIC ANNOTATION MIDDLE MARK + +03198 +IDEOGRAPHIC ANNOTATION BOTTOM MARK + +03199 +IDEOGRAPHIC ANNOTATION FIRST MARK + +0319A +IDEOGRAPHIC ANNOTATION SECOND MARK + +0319B +IDEOGRAPHIC ANNOTATION THIRD MARK + +0319C +IDEOGRAPHIC ANNOTATION FOURTH MARK + +0319D +IDEOGRAPHIC ANNOTATION HEAVEN MARK + +0319E +IDEOGRAPHIC ANNOTATION EARTH MARK + +0319F +IDEOGRAPHIC ANNOTATION MAN MARK + +031A0 +BOPOMOFO LETTER BU + +031A1 +BOPOMOFO LETTER ZI + +031A2 +BOPOMOFO LETTER JI + +031A3 +BOPOMOFO LETTER GU + +031A4 +BOPOMOFO LETTER EE + +031A5 +BOPOMOFO LETTER ENN + +031A6 +BOPOMOFO LETTER OO + +031A7 +BOPOMOFO LETTER ONN + +031A8 +BOPOMOFO LETTER IR + +031A9 +BOPOMOFO LETTER ANN + +031AA +BOPOMOFO LETTER INN + +031AB +BOPOMOFO LETTER UNN + +031AC +BOPOMOFO LETTER IM + +031AD +BOPOMOFO LETTER NGG + +031AE +BOPOMOFO LETTER AINN + +031AF +BOPOMOFO LETTER AUNN + +031B0 +BOPOMOFO LETTER AM + +031B1 +BOPOMOFO LETTER OM + +031B2 +BOPOMOFO LETTER ONG + +031B3 +BOPOMOFO LETTER INNN + +031B4 +BOPOMOFO FINAL LETTER P + +031B5 +BOPOMOFO FINAL LETTER T + +031B6 +BOPOMOFO FINAL LETTER K + +031B7 +BOPOMOFO FINAL LETTER H + +031B8 +BOPOMOFO LETTER GH + +031B9 +BOPOMOFO LETTER LH + +031BA +BOPOMOFO LETTER ZY + +031BB +BOPOMOFO FINAL LETTER G + +031BC +BOPOMOFO LETTER GW + +031BD +BOPOMOFO LETTER KW + +031BE +BOPOMOFO LETTER OE + +031BF +BOPOMOFO LETTER AH + +031C0 +CJK STROKE T + +031C1 +CJK STROKE WG + +031C2 +CJK STROKE XG + +031C3 +CJK STROKE BXG + +031C4 +CJK STROKE SW + +031C5 +CJK STROKE HZZ + +031C6 +CJK STROKE HZG + +031C7 +CJK STROKE HP + +031C8 +CJK STROKE HZWG + +031C9 +CJK STROKE SZWG + +031CA +CJK STROKE HZT + +031CB +CJK STROKE HZZP + +031CC +CJK STROKE HPWG + +031CD +CJK STROKE HZW + +031CE +CJK STROKE HZZZ + +031CF +CJK STROKE N + +031D0 +CJK STROKE H + +031D1 +CJK STROKE S + +031D2 +CJK STROKE P + +031D3 +CJK STROKE SP + +031D4 +CJK STROKE D + +031D5 +CJK STROKE HZ + +031D6 +CJK STROKE HG + +031D7 +CJK STROKE SZ + +031D8 +CJK STROKE SWZ + +031D9 +CJK STROKE ST + +031DA +CJK STROKE SG + +031DB +CJK STROKE PD + +031DC +CJK STROKE PZ + +031DD +CJK STROKE TN + +031DE +CJK STROKE SZZ + +031DF +CJK STROKE SWG + +031E0 +CJK STROKE HXWG + +031E1 +CJK STROKE HZZZG + +031E2 +CJK STROKE PG + +031E3 +CJK STROKE Q + +031E4 +CJK STROKE HXG + +031E5 +CJK STROKE SZP + +031EF +IDEOGRAPHIC DESCRIPTION CHARACTER SUBTRACTION + +031F0 +KATAKANA LETTER SMALL KU + +031F1 +KATAKANA LETTER SMALL SI + +031F2 +KATAKANA LETTER SMALL SU + +031F3 +KATAKANA LETTER SMALL TO + +031F4 +KATAKANA LETTER SMALL NU + +031F5 +KATAKANA LETTER SMALL HA + +031F6 +KATAKANA LETTER SMALL HI + +031F7 +KATAKANA LETTER SMALL HU + +031F8 +KATAKANA LETTER SMALL HE + +031F9 +KATAKANA LETTER SMALL HO + +031FA +KATAKANA LETTER SMALL MU + +031FB +KATAKANA LETTER SMALL RA + +031FC +KATAKANA LETTER SMALL RI + +031FD +KATAKANA LETTER SMALL RU + +031FE +KATAKANA LETTER SMALL RE + +031FF +KATAKANA LETTER SMALL RO + +03200 +PARENTHESIZED HANGUL KIYEOK + +03201 +PARENTHESIZED HANGUL NIEUN + +03202 +PARENTHESIZED HANGUL TIKEUT + +03203 +PARENTHESIZED HANGUL RIEUL + +03204 +PARENTHESIZED HANGUL MIEUM + +03205 +PARENTHESIZED HANGUL PIEUP + +03206 +PARENTHESIZED HANGUL SIOS + +03207 +PARENTHESIZED HANGUL IEUNG + +03208 +PARENTHESIZED HANGUL CIEUC + +03209 +PARENTHESIZED HANGUL CHIEUCH + +0320A +PARENTHESIZED HANGUL KHIEUKH + +0320B +PARENTHESIZED HANGUL THIEUTH + +0320C +PARENTHESIZED HANGUL PHIEUPH + +0320D +PARENTHESIZED HANGUL HIEUH + +0320E +PARENTHESIZED HANGUL KIYEOK A + +0320F +PARENTHESIZED HANGUL NIEUN A + +03210 +PARENTHESIZED HANGUL TIKEUT A + +03211 +PARENTHESIZED HANGUL RIEUL A + +03212 +PARENTHESIZED HANGUL MIEUM A + +03213 +PARENTHESIZED HANGUL PIEUP A + +03214 +PARENTHESIZED HANGUL SIOS A + +03215 +PARENTHESIZED HANGUL IEUNG A + +03216 +PARENTHESIZED HANGUL CIEUC A + +03217 +PARENTHESIZED HANGUL CHIEUCH A + +03218 +PARENTHESIZED HANGUL KHIEUKH A + +03219 +PARENTHESIZED HANGUL THIEUTH A + +0321A +PARENTHESIZED HANGUL PHIEUPH A + +0321B +PARENTHESIZED HANGUL HIEUH A + +0321C +PARENTHESIZED HANGUL CIEUC U + +0321D +PARENTHESIZED KOREAN CHARACTER OJEON + +0321E +PARENTHESIZED KOREAN CHARACTER O HU + +03220 +PARENTHESIZED IDEOGRAPH ONE + +03221 +PARENTHESIZED IDEOGRAPH TWO + +03222 +PARENTHESIZED IDEOGRAPH THREE + +03223 +PARENTHESIZED IDEOGRAPH FOUR + +03224 +PARENTHESIZED IDEOGRAPH FIVE + +03225 +PARENTHESIZED IDEOGRAPH SIX + +03226 +PARENTHESIZED IDEOGRAPH SEVEN + +03227 +PARENTHESIZED IDEOGRAPH EIGHT + +03228 +PARENTHESIZED IDEOGRAPH NINE + +03229 +PARENTHESIZED IDEOGRAPH TEN + +0322A +PARENTHESIZED IDEOGRAPH MOON + +0322B +PARENTHESIZED IDEOGRAPH FIRE + +0322C +PARENTHESIZED IDEOGRAPH WATER + +0322D +PARENTHESIZED IDEOGRAPH WOOD + +0322E +PARENTHESIZED IDEOGRAPH METAL + +0322F +PARENTHESIZED IDEOGRAPH EARTH + +03230 +PARENTHESIZED IDEOGRAPH SUN + +03231 +PARENTHESIZED IDEOGRAPH STOCK + +03232 +PARENTHESIZED IDEOGRAPH HAVE + +03233 +PARENTHESIZED IDEOGRAPH SOCIETY + +03234 +PARENTHESIZED IDEOGRAPH NAME + +03235 +PARENTHESIZED IDEOGRAPH SPECIAL + +03236 +PARENTHESIZED IDEOGRAPH FINANCIAL + +03237 +PARENTHESIZED IDEOGRAPH CONGRATULATION + +03238 +PARENTHESIZED IDEOGRAPH LABOR + +03239 +PARENTHESIZED IDEOGRAPH REPRESENT + +0323A +PARENTHESIZED IDEOGRAPH CALL + +0323B +PARENTHESIZED IDEOGRAPH STUDY + +0323C +PARENTHESIZED IDEOGRAPH SUPERVISE + +0323D +PARENTHESIZED IDEOGRAPH ENTERPRISE + +0323E +PARENTHESIZED IDEOGRAPH RESOURCE + +0323F +PARENTHESIZED IDEOGRAPH ALLIANCE + +03240 +PARENTHESIZED IDEOGRAPH FESTIVAL + +03241 +PARENTHESIZED IDEOGRAPH REST + +03242 +PARENTHESIZED IDEOGRAPH SELF + +03243 +PARENTHESIZED IDEOGRAPH REACH + +03244 +CIRCLED IDEOGRAPH QUESTION + +03245 +CIRCLED IDEOGRAPH KINDERGARTEN + +03246 +CIRCLED IDEOGRAPH SCHOOL + +03247 +CIRCLED IDEOGRAPH KOTO + +03248 +CIRCLED NUMBER TEN ON BLACK SQUARE + +03249 +CIRCLED NUMBER TWENTY ON BLACK SQUARE + +0324A +CIRCLED NUMBER THIRTY ON BLACK SQUARE + +0324B +CIRCLED NUMBER FORTY ON BLACK SQUARE + +0324C +CIRCLED NUMBER FIFTY ON BLACK SQUARE + +0324D +CIRCLED NUMBER SIXTY ON BLACK SQUARE + +0324E +CIRCLED NUMBER SEVENTY ON BLACK SQUARE + +0324F +CIRCLED NUMBER EIGHTY ON BLACK SQUARE + +03250 +PARTNERSHIP SIGN + +03251 +CIRCLED NUMBER TWENTY ONE + +03252 +CIRCLED NUMBER TWENTY TWO + +03253 +CIRCLED NUMBER TWENTY THREE + +03254 +CIRCLED NUMBER TWENTY FOUR + +03255 +CIRCLED NUMBER TWENTY FIVE + +03256 +CIRCLED NUMBER TWENTY SIX + +03257 +CIRCLED NUMBER TWENTY SEVEN + +03258 +CIRCLED NUMBER TWENTY EIGHT + +03259 +CIRCLED NUMBER TWENTY NINE + +0325A +CIRCLED NUMBER THIRTY + +0325B +CIRCLED NUMBER THIRTY ONE + +0325C +CIRCLED NUMBER THIRTY TWO + +0325D +CIRCLED NUMBER THIRTY THREE + +0325E +CIRCLED NUMBER THIRTY FOUR + +0325F +CIRCLED NUMBER THIRTY FIVE + +03260 +CIRCLED HANGUL KIYEOK + +03261 +CIRCLED HANGUL NIEUN + +03262 +CIRCLED HANGUL TIKEUT + +03263 +CIRCLED HANGUL RIEUL + +03264 +CIRCLED HANGUL MIEUM + +03265 +CIRCLED HANGUL PIEUP + +03266 +CIRCLED HANGUL SIOS + +03267 +CIRCLED HANGUL IEUNG + +03268 +CIRCLED HANGUL CIEUC + +03269 +CIRCLED HANGUL CHIEUCH + +0326A +CIRCLED HANGUL KHIEUKH + +0326B +CIRCLED HANGUL THIEUTH + +0326C +CIRCLED HANGUL PHIEUPH + +0326D +CIRCLED HANGUL HIEUH + +0326E +CIRCLED HANGUL KIYEOK A + +0326F +CIRCLED HANGUL NIEUN A + +03270 +CIRCLED HANGUL TIKEUT A + +03271 +CIRCLED HANGUL RIEUL A + +03272 +CIRCLED HANGUL MIEUM A + +03273 +CIRCLED HANGUL PIEUP A + +03274 +CIRCLED HANGUL SIOS A + +03275 +CIRCLED HANGUL IEUNG A + +03276 +CIRCLED HANGUL CIEUC A + +03277 +CIRCLED HANGUL CHIEUCH A + +03278 +CIRCLED HANGUL KHIEUKH A + +03279 +CIRCLED HANGUL THIEUTH A + +0327A +CIRCLED HANGUL PHIEUPH A + +0327B +CIRCLED HANGUL HIEUH A + +0327C +CIRCLED KOREAN CHARACTER CHAMKO + +0327D +CIRCLED KOREAN CHARACTER JUEUI + +0327E +CIRCLED HANGUL IEUNG U + +0327F +KOREAN STANDARD SYMBOL + +03280 +CIRCLED IDEOGRAPH ONE + +03281 +CIRCLED IDEOGRAPH TWO + +03282 +CIRCLED IDEOGRAPH THREE + +03283 +CIRCLED IDEOGRAPH FOUR + +03284 +CIRCLED IDEOGRAPH FIVE + +03285 +CIRCLED IDEOGRAPH SIX + +03286 +CIRCLED IDEOGRAPH SEVEN + +03287 +CIRCLED IDEOGRAPH EIGHT + +03288 +CIRCLED IDEOGRAPH NINE + +03289 +CIRCLED IDEOGRAPH TEN + +0328A +CIRCLED IDEOGRAPH MOON + +0328B +CIRCLED IDEOGRAPH FIRE + +0328C +CIRCLED IDEOGRAPH WATER + +0328D +CIRCLED IDEOGRAPH WOOD + +0328E +CIRCLED IDEOGRAPH METAL + +0328F +CIRCLED IDEOGRAPH EARTH + +03290 +CIRCLED IDEOGRAPH SUN + +03291 +CIRCLED IDEOGRAPH STOCK + +03292 +CIRCLED IDEOGRAPH HAVE + +03293 +CIRCLED IDEOGRAPH SOCIETY + +03294 +CIRCLED IDEOGRAPH NAME + +03295 +CIRCLED IDEOGRAPH SPECIAL + +03296 +CIRCLED IDEOGRAPH FINANCIAL + +03297 +CIRCLED IDEOGRAPH CONGRATULATION + +03298 +CIRCLED IDEOGRAPH LABOR + +03299 +CIRCLED IDEOGRAPH SECRET + +0329A +CIRCLED IDEOGRAPH MALE + +0329B +CIRCLED IDEOGRAPH FEMALE + +0329C +CIRCLED IDEOGRAPH SUITABLE + +0329D +CIRCLED IDEOGRAPH EXCELLENT + +0329E +CIRCLED IDEOGRAPH PRINT + +0329F +CIRCLED IDEOGRAPH ATTENTION + +032A0 +CIRCLED IDEOGRAPH ITEM + +032A1 +CIRCLED IDEOGRAPH REST + +032A2 +CIRCLED IDEOGRAPH COPY + +032A3 +CIRCLED IDEOGRAPH CORRECT + +032A4 +CIRCLED IDEOGRAPH HIGH + +032A5 +CIRCLED IDEOGRAPH CENTRE + +032A6 +CIRCLED IDEOGRAPH LOW + +032A7 +CIRCLED IDEOGRAPH LEFT + +032A8 +CIRCLED IDEOGRAPH RIGHT + +032A9 +CIRCLED IDEOGRAPH MEDICINE + +032AA +CIRCLED IDEOGRAPH RELIGION + +032AB +CIRCLED IDEOGRAPH STUDY + +032AC +CIRCLED IDEOGRAPH SUPERVISE + +032AD +CIRCLED IDEOGRAPH ENTERPRISE + +032AE +CIRCLED IDEOGRAPH RESOURCE + +032AF +CIRCLED IDEOGRAPH ALLIANCE + +032B0 +CIRCLED IDEOGRAPH NIGHT + +032B1 +CIRCLED NUMBER THIRTY SIX + +032B2 +CIRCLED NUMBER THIRTY SEVEN + +032B3 +CIRCLED NUMBER THIRTY EIGHT + +032B4 +CIRCLED NUMBER THIRTY NINE + +032B5 +CIRCLED NUMBER FORTY + +032B6 +CIRCLED NUMBER FORTY ONE + +032B7 +CIRCLED NUMBER FORTY TWO + +032B8 +CIRCLED NUMBER FORTY THREE + +032B9 +CIRCLED NUMBER FORTY FOUR + +032BA +CIRCLED NUMBER FORTY FIVE + +032BB +CIRCLED NUMBER FORTY SIX + +032BC +CIRCLED NUMBER FORTY SEVEN + +032BD +CIRCLED NUMBER FORTY EIGHT + +032BE +CIRCLED NUMBER FORTY NINE + +032BF +CIRCLED NUMBER FIFTY + +032C0 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR JANUARY + +032C1 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR FEBRUARY + +032C2 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR MARCH + +032C3 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR APRIL + +032C4 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR MAY + +032C5 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR JUNE + +032C6 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR JULY + +032C7 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR AUGUST + +032C8 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR SEPTEMBER + +032C9 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR OCTOBER + +032CA +IDEOGRAPHIC TELEGRAPH SYMBOL FOR NOVEMBER + +032CB +IDEOGRAPHIC TELEGRAPH SYMBOL FOR DECEMBER + +032CC +SQUARE HG + +032CD +SQUARE ERG + +032CE +SQUARE EV + +032CF +LIMITED LIABILITY SIGN + +032D0 +CIRCLED KATAKANA A + +032D1 +CIRCLED KATAKANA I + +032D2 +CIRCLED KATAKANA U + +032D3 +CIRCLED KATAKANA E + +032D4 +CIRCLED KATAKANA O + +032D5 +CIRCLED KATAKANA KA + +032D6 +CIRCLED KATAKANA KI + +032D7 +CIRCLED KATAKANA KU + +032D8 +CIRCLED KATAKANA KE + +032D9 +CIRCLED KATAKANA KO + +032DA +CIRCLED KATAKANA SA + +032DB +CIRCLED KATAKANA SI + +032DC +CIRCLED KATAKANA SU + +032DD +CIRCLED KATAKANA SE + +032DE +CIRCLED KATAKANA SO + +032DF +CIRCLED KATAKANA TA + +032E0 +CIRCLED KATAKANA TI + +032E1 +CIRCLED KATAKANA TU + +032E2 +CIRCLED KATAKANA TE + +032E3 +CIRCLED KATAKANA TO + +032E4 +CIRCLED KATAKANA NA + +032E5 +CIRCLED KATAKANA NI + +032E6 +CIRCLED KATAKANA NU + +032E7 +CIRCLED KATAKANA NE + +032E8 +CIRCLED KATAKANA NO + +032E9 +CIRCLED KATAKANA HA + +032EA +CIRCLED KATAKANA HI + +032EB +CIRCLED KATAKANA HU + +032EC +CIRCLED KATAKANA HE + +032ED +CIRCLED KATAKANA HO + +032EE +CIRCLED KATAKANA MA + +032EF +CIRCLED KATAKANA MI + +032F0 +CIRCLED KATAKANA MU + +032F1 +CIRCLED KATAKANA ME + +032F2 +CIRCLED KATAKANA MO + +032F3 +CIRCLED KATAKANA YA + +032F4 +CIRCLED KATAKANA YU + +032F5 +CIRCLED KATAKANA YO + +032F6 +CIRCLED KATAKANA RA + +032F7 +CIRCLED KATAKANA RI + +032F8 +CIRCLED KATAKANA RU + +032F9 +CIRCLED KATAKANA RE + +032FA +CIRCLED KATAKANA RO + +032FB +CIRCLED KATAKANA WA + +032FC +CIRCLED KATAKANA WI + +032FD +CIRCLED KATAKANA WE + +032FE +CIRCLED KATAKANA WO + +032FF +SQUARE ERA NAME REIWA + +03300 +SQUARE APAATO + +03301 +SQUARE ARUHUA + +03302 +SQUARE ANPEA + +03303 +SQUARE AARU + +03304 +SQUARE ININGU + +03305 +SQUARE INTI + +03306 +SQUARE UON + +03307 +SQUARE ESUKUUDO + +03308 +SQUARE EEKAA + +03309 +SQUARE ONSU + +0330A +SQUARE OOMU + +0330B +SQUARE KAIRI + +0330C +SQUARE KARATTO + +0330D +SQUARE KARORII + +0330E +SQUARE GARON + +0330F +SQUARE GANMA + +03310 +SQUARE GIGA + +03311 +SQUARE GINII + +03312 +SQUARE KYURII + +03313 +SQUARE GIRUDAA + +03314 +SQUARE KIRO + +03315 +SQUARE KIROGURAMU + +03316 +SQUARE KIROMEETORU + +03317 +SQUARE KIROWATTO + +03318 +SQUARE GURAMU + +03319 +SQUARE GURAMUTON + +0331A +SQUARE KURUZEIRO + +0331B +SQUARE KUROONE + +0331C +SQUARE KEESU + +0331D +SQUARE KORUNA + +0331E +SQUARE KOOPO + +0331F +SQUARE SAIKURU + +03320 +SQUARE SANTIIMU + +03321 +SQUARE SIRINGU + +03322 +SQUARE SENTI + +03323 +SQUARE SENTO + +03324 +SQUARE DAASU + +03325 +SQUARE DESI + +03326 +SQUARE DORU + +03327 +SQUARE TON + +03328 +SQUARE NANO + +03329 +SQUARE NOTTO + +0332A +SQUARE HAITU + +0332B +SQUARE PAASENTO + +0332C +SQUARE PAATU + +0332D +SQUARE BAARERU + +0332E +SQUARE PIASUTORU + +0332F +SQUARE PIKURU + +03330 +SQUARE PIKO + +03331 +SQUARE BIRU + +03332 +SQUARE HUARADDO + +03333 +SQUARE HUIITO + +03334 +SQUARE BUSSYERU + +03335 +SQUARE HURAN + +03336 +SQUARE HEKUTAARU + +03337 +SQUARE PESO + +03338 +SQUARE PENIHI + +03339 +SQUARE HERUTU + +0333A +SQUARE PENSU + +0333B +SQUARE PEEZI + +0333C +SQUARE BEETA + +0333D +SQUARE POINTO + +0333E +SQUARE BORUTO + +0333F +SQUARE HON + +03340 +SQUARE PONDO + +03341 +SQUARE HOORU + +03342 +SQUARE HOON + +03343 +SQUARE MAIKURO + +03344 +SQUARE MAIRU + +03345 +SQUARE MAHHA + +03346 +SQUARE MARUKU + +03347 +SQUARE MANSYON + +03348 +SQUARE MIKURON + +03349 +SQUARE MIRI + +0334A +SQUARE MIRIBAARU + +0334B +SQUARE MEGA + +0334C +SQUARE MEGATON + +0334D +SQUARE MEETORU + +0334E +SQUARE YAADO + +0334F +SQUARE YAARU + +03350 +SQUARE YUAN + +03351 +SQUARE RITTORU + +03352 +SQUARE RIRA + +03353 +SQUARE RUPII + +03354 +SQUARE RUUBURU + +03355 +SQUARE REMU + +03356 +SQUARE RENTOGEN + +03357 +SQUARE WATTO + +03358 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ZERO + +03359 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ONE + +0335A +IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWO + +0335B +IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR THREE + +0335C +IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FOUR + +0335D +IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FIVE + +0335E +IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SIX + +0335F +IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SEVEN + +03360 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR EIGHT + +03361 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR NINE + +03362 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TEN + +03363 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ELEVEN + +03364 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWELVE + +03365 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR THIRTEEN + +03366 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FOURTEEN + +03367 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FIFTEEN + +03368 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SIXTEEN + +03369 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SEVENTEEN + +0336A +IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR EIGHTEEN + +0336B +IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR NINETEEN + +0336C +IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY + +0336D +IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-ONE + +0336E +IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-TWO + +0336F +IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-THREE + +03370 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-FOUR + +03371 +SQUARE HPA + +03372 +SQUARE DA + +03373 +SQUARE AU + +03374 +SQUARE BAR + +03375 +SQUARE OV + +03376 +SQUARE PC + +03377 +SQUARE DM + +03378 +SQUARE DM SQUARED + +03379 +SQUARE DM CUBED + +0337A +SQUARE IU + +0337B +SQUARE ERA NAME HEISEI + +0337C +SQUARE ERA NAME SYOUWA + +0337D +SQUARE ERA NAME TAISYOU + +0337E +SQUARE ERA NAME MEIZI + +0337F +SQUARE CORPORATION + +03380 +SQUARE PA AMPS + +03381 +SQUARE NA + +03382 +SQUARE MU A + +03383 +SQUARE MA + +03384 +SQUARE KA + +03385 +SQUARE KB + +03386 +SQUARE MB + +03387 +SQUARE GB + +03388 +SQUARE CAL + +03389 +SQUARE KCAL + +0338A +SQUARE PF + +0338B +SQUARE NF + +0338C +SQUARE MU F + +0338D +SQUARE MU G + +0338E +SQUARE MG + +0338F +SQUARE KG + +03390 +SQUARE HZ + +03391 +SQUARE KHZ + +03392 +SQUARE MHZ + +03393 +SQUARE GHZ + +03394 +SQUARE THZ + +03395 +SQUARE MU L + +03396 +SQUARE ML + +03397 +SQUARE DL + +03398 +SQUARE KL + +03399 +SQUARE FM + +0339A +SQUARE NM + +0339B +SQUARE MU M + +0339C +SQUARE MM + +0339D +SQUARE CM + +0339E +SQUARE KM + +0339F +SQUARE MM SQUARED + +033A0 +SQUARE CM SQUARED + +033A1 +SQUARE M SQUARED + +033A2 +SQUARE KM SQUARED + +033A3 +SQUARE MM CUBED + +033A4 +SQUARE CM CUBED + +033A5 +SQUARE M CUBED + +033A6 +SQUARE KM CUBED + +033A7 +SQUARE M OVER S + +033A8 +SQUARE M OVER S SQUARED + +033A9 +SQUARE PA + +033AA +SQUARE KPA + +033AB +SQUARE MPA + +033AC +SQUARE GPA + +033AD +SQUARE RAD + +033AE +SQUARE RAD OVER S + +033AF +SQUARE RAD OVER S SQUARED + +033B0 +SQUARE PS + +033B1 +SQUARE NS + +033B2 +SQUARE MU S + +033B3 +SQUARE MS + +033B4 +SQUARE PV + +033B5 +SQUARE NV + +033B6 +SQUARE MU V + +033B7 +SQUARE MV + +033B8 +SQUARE KV + +033B9 +SQUARE MV MEGA + +033BA +SQUARE PW + +033BB +SQUARE NW + +033BC +SQUARE MU W + +033BD +SQUARE MW + +033BE +SQUARE KW + +033BF +SQUARE MW MEGA + +033C0 +SQUARE K OHM + +033C1 +SQUARE M OHM + +033C2 +SQUARE AM + +033C3 +SQUARE BQ + +033C4 +SQUARE CC + +033C5 +SQUARE CD + +033C6 +SQUARE C OVER KG + +033C7 +SQUARE CO + +033C8 +SQUARE DB + +033C9 +SQUARE GY + +033CA +SQUARE HA + +033CB +SQUARE HP + +033CC +SQUARE IN + +033CD +SQUARE KK + +033CE +SQUARE KM CAPITAL + +033CF +SQUARE KT + +033D0 +SQUARE LM + +033D1 +SQUARE LN + +033D2 +SQUARE LOG + +033D3 +SQUARE LX + +033D4 +SQUARE MB SMALL + +033D5 +SQUARE MIL + +033D6 +SQUARE MOL + +033D7 +SQUARE PH + +033D8 +SQUARE PM + +033D9 +SQUARE PPM + +033DA +SQUARE PR + +033DB +SQUARE SR + +033DC +SQUARE SV + +033DD +SQUARE WB + +033DE +SQUARE V OVER M + +033DF +SQUARE A OVER M + +033E0 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ONE + +033E1 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWO + +033E2 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THREE + +033E3 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FOUR + +033E4 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FIVE + +033E5 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SIX + +033E6 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SEVEN + +033E7 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY EIGHT + +033E8 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY NINE + +033E9 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TEN + +033EA +IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ELEVEN + +033EB +IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWELVE + +033EC +IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTEEN + +033ED +IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FOURTEEN + +033EE +IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FIFTEEN + +033EF +IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SIXTEEN + +033F0 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SEVENTEEN + +033F1 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY EIGHTEEN + +033F2 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY NINETEEN + +033F3 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY + +033F4 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-ONE + +033F5 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-TWO + +033F6 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-THREE + +033F7 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-FOUR + +033F8 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-FIVE + +033F9 +IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-SIX + +033FA +IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-SEVEN + +033FB +IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-EIGHT + +033FC +IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-NINE + +033FD +IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTY + +033FE +IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTY-ONE + +033FF +SQUARE GAL + +04DC0 +HEXAGRAM FOR THE CREATIVE HEAVEN + +04DC1 +HEXAGRAM FOR THE RECEPTIVE EARTH + +04DC2 +HEXAGRAM FOR DIFFICULTY AT THE BEGINNING + +04DC3 +HEXAGRAM FOR YOUTHFUL FOLLY + +04DC4 +HEXAGRAM FOR WAITING + +04DC5 +HEXAGRAM FOR CONFLICT + +04DC6 +HEXAGRAM FOR THE ARMY + +04DC7 +HEXAGRAM FOR HOLDING TOGETHER + +04DC8 +HEXAGRAM FOR SMALL TAMING + +04DC9 +HEXAGRAM FOR TREADING + +04DCA +HEXAGRAM FOR PEACE + +04DCB +HEXAGRAM FOR STANDSTILL + +04DCC +HEXAGRAM FOR FELLOWSHIP + +04DCD +HEXAGRAM FOR GREAT POSSESSION + +04DCE +HEXAGRAM FOR MODESTY + +04DCF +HEXAGRAM FOR ENTHUSIASM + +04DD0 +HEXAGRAM FOR FOLLOWING + +04DD1 +HEXAGRAM FOR WORK ON THE DECAYED + +04DD2 +HEXAGRAM FOR APPROACH + +04DD3 +HEXAGRAM FOR CONTEMPLATION + +04DD4 +HEXAGRAM FOR BITING THROUGH + +04DD5 +HEXAGRAM FOR GRACE + +04DD6 +HEXAGRAM FOR SPLITTING APART + +04DD7 +HEXAGRAM FOR RETURN + +04DD8 +HEXAGRAM FOR INNOCENCE + +04DD9 +HEXAGRAM FOR GREAT TAMING + +04DDA +HEXAGRAM FOR MOUTH CORNERS + +04DDB +HEXAGRAM FOR GREAT PREPONDERANCE + +04DDC +HEXAGRAM FOR THE ABYSMAL WATER + +04DDD +HEXAGRAM FOR THE CLINGING FIRE + +04DDE +HEXAGRAM FOR INFLUENCE + +04DDF +HEXAGRAM FOR DURATION + +04DE0 +HEXAGRAM FOR RETREAT + +04DE1 +HEXAGRAM FOR GREAT POWER + +04DE2 +HEXAGRAM FOR PROGRESS + +04DE3 +HEXAGRAM FOR DARKENING OF THE LIGHT + +04DE4 +HEXAGRAM FOR THE FAMILY + +04DE5 +HEXAGRAM FOR OPPOSITION + +04DE6 +HEXAGRAM FOR OBSTRUCTION + +04DE7 +HEXAGRAM FOR DELIVERANCE + +04DE8 +HEXAGRAM FOR DECREASE + +04DE9 +HEXAGRAM FOR INCREASE + +04DEA +HEXAGRAM FOR BREAKTHROUGH + +04DEB +HEXAGRAM FOR COMING TO MEET + +04DEC +HEXAGRAM FOR GATHERING TOGETHER + +04DED +HEXAGRAM FOR PUSHING UPWARD + +04DEE +HEXAGRAM FOR OPPRESSION + +04DEF +HEXAGRAM FOR THE WELL + +04DF0 +HEXAGRAM FOR REVOLUTION + +04DF1 +HEXAGRAM FOR THE CAULDRON + +04DF2 +HEXAGRAM FOR THE AROUSING THUNDER + +04DF3 +HEXAGRAM FOR THE KEEPING STILL MOUNTAIN + +04DF4 +HEXAGRAM FOR DEVELOPMENT + +04DF5 +HEXAGRAM FOR THE MARRYING MAIDEN + +04DF6 +HEXAGRAM FOR ABUNDANCE + +04DF7 +HEXAGRAM FOR THE WANDERER + +04DF8 +HEXAGRAM FOR THE GENTLE WIND + +04DF9 +HEXAGRAM FOR THE JOYOUS LAKE + +04DFA +HEXAGRAM FOR DISPERSION + +04DFB +HEXAGRAM FOR LIMITATION + +04DFC +HEXAGRAM FOR INNER TRUTH + +04DFD +HEXAGRAM FOR SMALL PREPONDERANCE + +04DFE +HEXAGRAM FOR AFTER COMPLETION + +04DFF +HEXAGRAM FOR BEFORE COMPLETION + +0A000 +YI SYLLABLE IT + +0A001 +YI SYLLABLE IX + +0A002 +YI SYLLABLE I + +0A003 +YI SYLLABLE IP + +0A004 +YI SYLLABLE IET + +0A005 +YI SYLLABLE IEX + +0A006 +YI SYLLABLE IE + +0A007 +YI SYLLABLE IEP + +0A008 +YI SYLLABLE AT + +0A009 +YI SYLLABLE AX + +0A00A +YI SYLLABLE A + +0A00B +YI SYLLABLE AP + +0A00C +YI SYLLABLE UOX + +0A00D +YI SYLLABLE UO + +0A00E +YI SYLLABLE UOP + +0A00F +YI SYLLABLE OT + +0A010 +YI SYLLABLE OX + +0A011 +YI SYLLABLE O + +0A012 +YI SYLLABLE OP + +0A013 +YI SYLLABLE EX + +0A014 +YI SYLLABLE E + +0A015 +YI SYLLABLE ITERATION MARK + +0A015 +YI SYLLABLE WU + +0A016 +YI SYLLABLE BIT + +0A017 +YI SYLLABLE BIX + +0A018 +YI SYLLABLE BI + +0A019 +YI SYLLABLE BIP + +0A01A +YI SYLLABLE BIET + +0A01B +YI SYLLABLE BIEX + +0A01C +YI SYLLABLE BIE + +0A01D +YI SYLLABLE BIEP + +0A01E +YI SYLLABLE BAT + +0A01F +YI SYLLABLE BAX + +0A020 +YI SYLLABLE BA + +0A021 +YI SYLLABLE BAP + +0A022 +YI SYLLABLE BUOX + +0A023 +YI SYLLABLE BUO + +0A024 +YI SYLLABLE BUOP + +0A025 +YI SYLLABLE BOT + +0A026 +YI SYLLABLE BOX + +0A027 +YI SYLLABLE BO + +0A028 +YI SYLLABLE BOP + +0A029 +YI SYLLABLE BEX + +0A02A +YI SYLLABLE BE + +0A02B +YI SYLLABLE BEP + +0A02C +YI SYLLABLE BUT + +0A02D +YI SYLLABLE BUX + +0A02E +YI SYLLABLE BU + +0A02F +YI SYLLABLE BUP + +0A030 +YI SYLLABLE BURX + +0A031 +YI SYLLABLE BUR + +0A032 +YI SYLLABLE BYT + +0A033 +YI SYLLABLE BYX + +0A034 +YI SYLLABLE BY + +0A035 +YI SYLLABLE BYP + +0A036 +YI SYLLABLE BYRX + +0A037 +YI SYLLABLE BYR + +0A038 +YI SYLLABLE PIT + +0A039 +YI SYLLABLE PIX + +0A03A +YI SYLLABLE PI + +0A03B +YI SYLLABLE PIP + +0A03C +YI SYLLABLE PIEX + +0A03D +YI SYLLABLE PIE + +0A03E +YI SYLLABLE PIEP + +0A03F +YI SYLLABLE PAT + +0A040 +YI SYLLABLE PAX + +0A041 +YI SYLLABLE PA + +0A042 +YI SYLLABLE PAP + +0A043 +YI SYLLABLE PUOX + +0A044 +YI SYLLABLE PUO + +0A045 +YI SYLLABLE PUOP + +0A046 +YI SYLLABLE POT + +0A047 +YI SYLLABLE POX + +0A048 +YI SYLLABLE PO + +0A049 +YI SYLLABLE POP + +0A04A +YI SYLLABLE PUT + +0A04B +YI SYLLABLE PUX + +0A04C +YI SYLLABLE PU + +0A04D +YI SYLLABLE PUP + +0A04E +YI SYLLABLE PURX + +0A04F +YI SYLLABLE PUR + +0A050 +YI SYLLABLE PYT + +0A051 +YI SYLLABLE PYX + +0A052 +YI SYLLABLE PY + +0A053 +YI SYLLABLE PYP + +0A054 +YI SYLLABLE PYRX + +0A055 +YI SYLLABLE PYR + +0A056 +YI SYLLABLE BBIT + +0A057 +YI SYLLABLE BBIX + +0A058 +YI SYLLABLE BBI + +0A059 +YI SYLLABLE BBIP + +0A05A +YI SYLLABLE BBIET + +0A05B +YI SYLLABLE BBIEX + +0A05C +YI SYLLABLE BBIE + +0A05D +YI SYLLABLE BBIEP + +0A05E +YI SYLLABLE BBAT + +0A05F +YI SYLLABLE BBAX + +0A060 +YI SYLLABLE BBA + +0A061 +YI SYLLABLE BBAP + +0A062 +YI SYLLABLE BBUOX + +0A063 +YI SYLLABLE BBUO + +0A064 +YI SYLLABLE BBUOP + +0A065 +YI SYLLABLE BBOT + +0A066 +YI SYLLABLE BBOX + +0A067 +YI SYLLABLE BBO + +0A068 +YI SYLLABLE BBOP + +0A069 +YI SYLLABLE BBEX + +0A06A +YI SYLLABLE BBE + +0A06B +YI SYLLABLE BBEP + +0A06C +YI SYLLABLE BBUT + +0A06D +YI SYLLABLE BBUX + +0A06E +YI SYLLABLE BBU + +0A06F +YI SYLLABLE BBUP + +0A070 +YI SYLLABLE BBURX + +0A071 +YI SYLLABLE BBUR + +0A072 +YI SYLLABLE BBYT + +0A073 +YI SYLLABLE BBYX + +0A074 +YI SYLLABLE BBY + +0A075 +YI SYLLABLE BBYP + +0A076 +YI SYLLABLE NBIT + +0A077 +YI SYLLABLE NBIX + +0A078 +YI SYLLABLE NBI + +0A079 +YI SYLLABLE NBIP + +0A07A +YI SYLLABLE NBIEX + +0A07B +YI SYLLABLE NBIE + +0A07C +YI SYLLABLE NBIEP + +0A07D +YI SYLLABLE NBAT + +0A07E +YI SYLLABLE NBAX + +0A07F +YI SYLLABLE NBA + +0A080 +YI SYLLABLE NBAP + +0A081 +YI SYLLABLE NBOT + +0A082 +YI SYLLABLE NBOX + +0A083 +YI SYLLABLE NBO + +0A084 +YI SYLLABLE NBOP + +0A085 +YI SYLLABLE NBUT + +0A086 +YI SYLLABLE NBUX + +0A087 +YI SYLLABLE NBU + +0A088 +YI SYLLABLE NBUP + +0A089 +YI SYLLABLE NBURX + +0A08A +YI SYLLABLE NBUR + +0A08B +YI SYLLABLE NBYT + +0A08C +YI SYLLABLE NBYX + +0A08D +YI SYLLABLE NBY + +0A08E +YI SYLLABLE NBYP + +0A08F +YI SYLLABLE NBYRX + +0A090 +YI SYLLABLE NBYR + +0A091 +YI SYLLABLE HMIT + +0A092 +YI SYLLABLE HMIX + +0A093 +YI SYLLABLE HMI + +0A094 +YI SYLLABLE HMIP + +0A095 +YI SYLLABLE HMIEX + +0A096 +YI SYLLABLE HMIE + +0A097 +YI SYLLABLE HMIEP + +0A098 +YI SYLLABLE HMAT + +0A099 +YI SYLLABLE HMAX + +0A09A +YI SYLLABLE HMA + +0A09B +YI SYLLABLE HMAP + +0A09C +YI SYLLABLE HMUOX + +0A09D +YI SYLLABLE HMUO + +0A09E +YI SYLLABLE HMUOP + +0A09F +YI SYLLABLE HMOT + +0A0A0 +YI SYLLABLE HMOX + +0A0A1 +YI SYLLABLE HMO + +0A0A2 +YI SYLLABLE HMOP + +0A0A3 +YI SYLLABLE HMUT + +0A0A4 +YI SYLLABLE HMUX + +0A0A5 +YI SYLLABLE HMU + +0A0A6 +YI SYLLABLE HMUP + +0A0A7 +YI SYLLABLE HMURX + +0A0A8 +YI SYLLABLE HMUR + +0A0A9 +YI SYLLABLE HMYX + +0A0AA +YI SYLLABLE HMY + +0A0AB +YI SYLLABLE HMYP + +0A0AC +YI SYLLABLE HMYRX + +0A0AD +YI SYLLABLE HMYR + +0A0AE +YI SYLLABLE MIT + +0A0AF +YI SYLLABLE MIX + +0A0B0 +YI SYLLABLE MI + +0A0B1 +YI SYLLABLE MIP + +0A0B2 +YI SYLLABLE MIEX + +0A0B3 +YI SYLLABLE MIE + +0A0B4 +YI SYLLABLE MIEP + +0A0B5 +YI SYLLABLE MAT + +0A0B6 +YI SYLLABLE MAX + +0A0B7 +YI SYLLABLE MA + +0A0B8 +YI SYLLABLE MAP + +0A0B9 +YI SYLLABLE MUOT + +0A0BA +YI SYLLABLE MUOX + +0A0BB +YI SYLLABLE MUO + +0A0BC +YI SYLLABLE MUOP + +0A0BD +YI SYLLABLE MOT + +0A0BE +YI SYLLABLE MOX + +0A0BF +YI SYLLABLE MO + +0A0C0 +YI SYLLABLE MOP + +0A0C1 +YI SYLLABLE MEX + +0A0C2 +YI SYLLABLE ME + +0A0C3 +YI SYLLABLE MUT + +0A0C4 +YI SYLLABLE MUX + +0A0C5 +YI SYLLABLE MU + +0A0C6 +YI SYLLABLE MUP + +0A0C7 +YI SYLLABLE MURX + +0A0C8 +YI SYLLABLE MUR + +0A0C9 +YI SYLLABLE MYT + +0A0CA +YI SYLLABLE MYX + +0A0CB +YI SYLLABLE MY + +0A0CC +YI SYLLABLE MYP + +0A0CD +YI SYLLABLE FIT + +0A0CE +YI SYLLABLE FIX + +0A0CF +YI SYLLABLE FI + +0A0D0 +YI SYLLABLE FIP + +0A0D1 +YI SYLLABLE FAT + +0A0D2 +YI SYLLABLE FAX + +0A0D3 +YI SYLLABLE FA + +0A0D4 +YI SYLLABLE FAP + +0A0D5 +YI SYLLABLE FOX + +0A0D6 +YI SYLLABLE FO + +0A0D7 +YI SYLLABLE FOP + +0A0D8 +YI SYLLABLE FUT + +0A0D9 +YI SYLLABLE FUX + +0A0DA +YI SYLLABLE FU + +0A0DB +YI SYLLABLE FUP + +0A0DC +YI SYLLABLE FURX + +0A0DD +YI SYLLABLE FUR + +0A0DE +YI SYLLABLE FYT + +0A0DF +YI SYLLABLE FYX + +0A0E0 +YI SYLLABLE FY + +0A0E1 +YI SYLLABLE FYP + +0A0E2 +YI SYLLABLE VIT + +0A0E3 +YI SYLLABLE VIX + +0A0E4 +YI SYLLABLE VI + +0A0E5 +YI SYLLABLE VIP + +0A0E6 +YI SYLLABLE VIET + +0A0E7 +YI SYLLABLE VIEX + +0A0E8 +YI SYLLABLE VIE + +0A0E9 +YI SYLLABLE VIEP + +0A0EA +YI SYLLABLE VAT + +0A0EB +YI SYLLABLE VAX + +0A0EC +YI SYLLABLE VA + +0A0ED +YI SYLLABLE VAP + +0A0EE +YI SYLLABLE VOT + +0A0EF +YI SYLLABLE VOX + +0A0F0 +YI SYLLABLE VO + +0A0F1 +YI SYLLABLE VOP + +0A0F2 +YI SYLLABLE VEX + +0A0F3 +YI SYLLABLE VEP + +0A0F4 +YI SYLLABLE VUT + +0A0F5 +YI SYLLABLE VUX + +0A0F6 +YI SYLLABLE VU + +0A0F7 +YI SYLLABLE VUP + +0A0F8 +YI SYLLABLE VURX + +0A0F9 +YI SYLLABLE VUR + +0A0FA +YI SYLLABLE VYT + +0A0FB +YI SYLLABLE VYX + +0A0FC +YI SYLLABLE VY + +0A0FD +YI SYLLABLE VYP + +0A0FE +YI SYLLABLE VYRX + +0A0FF +YI SYLLABLE VYR + +0A100 +YI SYLLABLE DIT + +0A101 +YI SYLLABLE DIX + +0A102 +YI SYLLABLE DI + +0A103 +YI SYLLABLE DIP + +0A104 +YI SYLLABLE DIEX + +0A105 +YI SYLLABLE DIE + +0A106 +YI SYLLABLE DIEP + +0A107 +YI SYLLABLE DAT + +0A108 +YI SYLLABLE DAX + +0A109 +YI SYLLABLE DA + +0A10A +YI SYLLABLE DAP + +0A10B +YI SYLLABLE DUOX + +0A10C +YI SYLLABLE DUO + +0A10D +YI SYLLABLE DOT + +0A10E +YI SYLLABLE DOX + +0A10F +YI SYLLABLE DO + +0A110 +YI SYLLABLE DOP + +0A111 +YI SYLLABLE DEX + +0A112 +YI SYLLABLE DE + +0A113 +YI SYLLABLE DEP + +0A114 +YI SYLLABLE DUT + +0A115 +YI SYLLABLE DUX + +0A116 +YI SYLLABLE DU + +0A117 +YI SYLLABLE DUP + +0A118 +YI SYLLABLE DURX + +0A119 +YI SYLLABLE DUR + +0A11A +YI SYLLABLE TIT + +0A11B +YI SYLLABLE TIX + +0A11C +YI SYLLABLE TI + +0A11D +YI SYLLABLE TIP + +0A11E +YI SYLLABLE TIEX + +0A11F +YI SYLLABLE TIE + +0A120 +YI SYLLABLE TIEP + +0A121 +YI SYLLABLE TAT + +0A122 +YI SYLLABLE TAX + +0A123 +YI SYLLABLE TA + +0A124 +YI SYLLABLE TAP + +0A125 +YI SYLLABLE TUOT + +0A126 +YI SYLLABLE TUOX + +0A127 +YI SYLLABLE TUO + +0A128 +YI SYLLABLE TUOP + +0A129 +YI SYLLABLE TOT + +0A12A +YI SYLLABLE TOX + +0A12B +YI SYLLABLE TO + +0A12C +YI SYLLABLE TOP + +0A12D +YI SYLLABLE TEX + +0A12E +YI SYLLABLE TE + +0A12F +YI SYLLABLE TEP + +0A130 +YI SYLLABLE TUT + +0A131 +YI SYLLABLE TUX + +0A132 +YI SYLLABLE TU + +0A133 +YI SYLLABLE TUP + +0A134 +YI SYLLABLE TURX + +0A135 +YI SYLLABLE TUR + +0A136 +YI SYLLABLE DDIT + +0A137 +YI SYLLABLE DDIX + +0A138 +YI SYLLABLE DDI + +0A139 +YI SYLLABLE DDIP + +0A13A +YI SYLLABLE DDIEX + +0A13B +YI SYLLABLE DDIE + +0A13C +YI SYLLABLE DDIEP + +0A13D +YI SYLLABLE DDAT + +0A13E +YI SYLLABLE DDAX + +0A13F +YI SYLLABLE DDA + +0A140 +YI SYLLABLE DDAP + +0A141 +YI SYLLABLE DDUOX + +0A142 +YI SYLLABLE DDUO + +0A143 +YI SYLLABLE DDUOP + +0A144 +YI SYLLABLE DDOT + +0A145 +YI SYLLABLE DDOX + +0A146 +YI SYLLABLE DDO + +0A147 +YI SYLLABLE DDOP + +0A148 +YI SYLLABLE DDEX + +0A149 +YI SYLLABLE DDE + +0A14A +YI SYLLABLE DDEP + +0A14B +YI SYLLABLE DDUT + +0A14C +YI SYLLABLE DDUX + +0A14D +YI SYLLABLE DDU + +0A14E +YI SYLLABLE DDUP + +0A14F +YI SYLLABLE DDURX + +0A150 +YI SYLLABLE DDUR + +0A151 +YI SYLLABLE NDIT + +0A152 +YI SYLLABLE NDIX + +0A153 +YI SYLLABLE NDI + +0A154 +YI SYLLABLE NDIP + +0A155 +YI SYLLABLE NDIEX + +0A156 +YI SYLLABLE NDIE + +0A157 +YI SYLLABLE NDAT + +0A158 +YI SYLLABLE NDAX + +0A159 +YI SYLLABLE NDA + +0A15A +YI SYLLABLE NDAP + +0A15B +YI SYLLABLE NDOT + +0A15C +YI SYLLABLE NDOX + +0A15D +YI SYLLABLE NDO + +0A15E +YI SYLLABLE NDOP + +0A15F +YI SYLLABLE NDEX + +0A160 +YI SYLLABLE NDE + +0A161 +YI SYLLABLE NDEP + +0A162 +YI SYLLABLE NDUT + +0A163 +YI SYLLABLE NDUX + +0A164 +YI SYLLABLE NDU + +0A165 +YI SYLLABLE NDUP + +0A166 +YI SYLLABLE NDURX + +0A167 +YI SYLLABLE NDUR + +0A168 +YI SYLLABLE HNIT + +0A169 +YI SYLLABLE HNIX + +0A16A +YI SYLLABLE HNI + +0A16B +YI SYLLABLE HNIP + +0A16C +YI SYLLABLE HNIET + +0A16D +YI SYLLABLE HNIEX + +0A16E +YI SYLLABLE HNIE + +0A16F +YI SYLLABLE HNIEP + +0A170 +YI SYLLABLE HNAT + +0A171 +YI SYLLABLE HNAX + +0A172 +YI SYLLABLE HNA + +0A173 +YI SYLLABLE HNAP + +0A174 +YI SYLLABLE HNUOX + +0A175 +YI SYLLABLE HNUO + +0A176 +YI SYLLABLE HNOT + +0A177 +YI SYLLABLE HNOX + +0A178 +YI SYLLABLE HNOP + +0A179 +YI SYLLABLE HNEX + +0A17A +YI SYLLABLE HNE + +0A17B +YI SYLLABLE HNEP + +0A17C +YI SYLLABLE HNUT + +0A17D +YI SYLLABLE NIT + +0A17E +YI SYLLABLE NIX + +0A17F +YI SYLLABLE NI + +0A180 +YI SYLLABLE NIP + +0A181 +YI SYLLABLE NIEX + +0A182 +YI SYLLABLE NIE + +0A183 +YI SYLLABLE NIEP + +0A184 +YI SYLLABLE NAX + +0A185 +YI SYLLABLE NA + +0A186 +YI SYLLABLE NAP + +0A187 +YI SYLLABLE NUOX + +0A188 +YI SYLLABLE NUO + +0A189 +YI SYLLABLE NUOP + +0A18A +YI SYLLABLE NOT + +0A18B +YI SYLLABLE NOX + +0A18C +YI SYLLABLE NO + +0A18D +YI SYLLABLE NOP + +0A18E +YI SYLLABLE NEX + +0A18F +YI SYLLABLE NE + +0A190 +YI SYLLABLE NEP + +0A191 +YI SYLLABLE NUT + +0A192 +YI SYLLABLE NUX + +0A193 +YI SYLLABLE NU + +0A194 +YI SYLLABLE NUP + +0A195 +YI SYLLABLE NURX + +0A196 +YI SYLLABLE NUR + +0A197 +YI SYLLABLE HLIT + +0A198 +YI SYLLABLE HLIX + +0A199 +YI SYLLABLE HLI + +0A19A +YI SYLLABLE HLIP + +0A19B +YI SYLLABLE HLIEX + +0A19C +YI SYLLABLE HLIE + +0A19D +YI SYLLABLE HLIEP + +0A19E +YI SYLLABLE HLAT + +0A19F +YI SYLLABLE HLAX + +0A1A0 +YI SYLLABLE HLA + +0A1A1 +YI SYLLABLE HLAP + +0A1A2 +YI SYLLABLE HLUOX + +0A1A3 +YI SYLLABLE HLUO + +0A1A4 +YI SYLLABLE HLUOP + +0A1A5 +YI SYLLABLE HLOX + +0A1A6 +YI SYLLABLE HLO + +0A1A7 +YI SYLLABLE HLOP + +0A1A8 +YI SYLLABLE HLEX + +0A1A9 +YI SYLLABLE HLE + +0A1AA +YI SYLLABLE HLEP + +0A1AB +YI SYLLABLE HLUT + +0A1AC +YI SYLLABLE HLUX + +0A1AD +YI SYLLABLE HLU + +0A1AE +YI SYLLABLE HLUP + +0A1AF +YI SYLLABLE HLURX + +0A1B0 +YI SYLLABLE HLUR + +0A1B1 +YI SYLLABLE HLYT + +0A1B2 +YI SYLLABLE HLYX + +0A1B3 +YI SYLLABLE HLY + +0A1B4 +YI SYLLABLE HLYP + +0A1B5 +YI SYLLABLE HLYRX + +0A1B6 +YI SYLLABLE HLYR + +0A1B7 +YI SYLLABLE LIT + +0A1B8 +YI SYLLABLE LIX + +0A1B9 +YI SYLLABLE LI + +0A1BA +YI SYLLABLE LIP + +0A1BB +YI SYLLABLE LIET + +0A1BC +YI SYLLABLE LIEX + +0A1BD +YI SYLLABLE LIE + +0A1BE +YI SYLLABLE LIEP + +0A1BF +YI SYLLABLE LAT + +0A1C0 +YI SYLLABLE LAX + +0A1C1 +YI SYLLABLE LA + +0A1C2 +YI SYLLABLE LAP + +0A1C3 +YI SYLLABLE LUOT + +0A1C4 +YI SYLLABLE LUOX + +0A1C5 +YI SYLLABLE LUO + +0A1C6 +YI SYLLABLE LUOP + +0A1C7 +YI SYLLABLE LOT + +0A1C8 +YI SYLLABLE LOX + +0A1C9 +YI SYLLABLE LO + +0A1CA +YI SYLLABLE LOP + +0A1CB +YI SYLLABLE LEX + +0A1CC +YI SYLLABLE LE + +0A1CD +YI SYLLABLE LEP + +0A1CE +YI SYLLABLE LUT + +0A1CF +YI SYLLABLE LUX + +0A1D0 +YI SYLLABLE LU + +0A1D1 +YI SYLLABLE LUP + +0A1D2 +YI SYLLABLE LURX + +0A1D3 +YI SYLLABLE LUR + +0A1D4 +YI SYLLABLE LYT + +0A1D5 +YI SYLLABLE LYX + +0A1D6 +YI SYLLABLE LY + +0A1D7 +YI SYLLABLE LYP + +0A1D8 +YI SYLLABLE LYRX + +0A1D9 +YI SYLLABLE LYR + +0A1DA +YI SYLLABLE GIT + +0A1DB +YI SYLLABLE GIX + +0A1DC +YI SYLLABLE GI + +0A1DD +YI SYLLABLE GIP + +0A1DE +YI SYLLABLE GIET + +0A1DF +YI SYLLABLE GIEX + +0A1E0 +YI SYLLABLE GIE + +0A1E1 +YI SYLLABLE GIEP + +0A1E2 +YI SYLLABLE GAT + +0A1E3 +YI SYLLABLE GAX + +0A1E4 +YI SYLLABLE GA + +0A1E5 +YI SYLLABLE GAP + +0A1E6 +YI SYLLABLE GUOT + +0A1E7 +YI SYLLABLE GUOX + +0A1E8 +YI SYLLABLE GUO + +0A1E9 +YI SYLLABLE GUOP + +0A1EA +YI SYLLABLE GOT + +0A1EB +YI SYLLABLE GOX + +0A1EC +YI SYLLABLE GO + +0A1ED +YI SYLLABLE GOP + +0A1EE +YI SYLLABLE GET + +0A1EF +YI SYLLABLE GEX + +0A1F0 +YI SYLLABLE GE + +0A1F1 +YI SYLLABLE GEP + +0A1F2 +YI SYLLABLE GUT + +0A1F3 +YI SYLLABLE GUX + +0A1F4 +YI SYLLABLE GU + +0A1F5 +YI SYLLABLE GUP + +0A1F6 +YI SYLLABLE GURX + +0A1F7 +YI SYLLABLE GUR + +0A1F8 +YI SYLLABLE KIT + +0A1F9 +YI SYLLABLE KIX + +0A1FA +YI SYLLABLE KI + +0A1FB +YI SYLLABLE KIP + +0A1FC +YI SYLLABLE KIEX + +0A1FD +YI SYLLABLE KIE + +0A1FE +YI SYLLABLE KIEP + +0A1FF +YI SYLLABLE KAT + +0A200 +YI SYLLABLE KAX + +0A201 +YI SYLLABLE KA + +0A202 +YI SYLLABLE KAP + +0A203 +YI SYLLABLE KUOX + +0A204 +YI SYLLABLE KUO + +0A205 +YI SYLLABLE KUOP + +0A206 +YI SYLLABLE KOT + +0A207 +YI SYLLABLE KOX + +0A208 +YI SYLLABLE KO + +0A209 +YI SYLLABLE KOP + +0A20A +YI SYLLABLE KET + +0A20B +YI SYLLABLE KEX + +0A20C +YI SYLLABLE KE + +0A20D +YI SYLLABLE KEP + +0A20E +YI SYLLABLE KUT + +0A20F +YI SYLLABLE KUX + +0A210 +YI SYLLABLE KU + +0A211 +YI SYLLABLE KUP + +0A212 +YI SYLLABLE KURX + +0A213 +YI SYLLABLE KUR + +0A214 +YI SYLLABLE GGIT + +0A215 +YI SYLLABLE GGIX + +0A216 +YI SYLLABLE GGI + +0A217 +YI SYLLABLE GGIEX + +0A218 +YI SYLLABLE GGIE + +0A219 +YI SYLLABLE GGIEP + +0A21A +YI SYLLABLE GGAT + +0A21B +YI SYLLABLE GGAX + +0A21C +YI SYLLABLE GGA + +0A21D +YI SYLLABLE GGAP + +0A21E +YI SYLLABLE GGUOT + +0A21F +YI SYLLABLE GGUOX + +0A220 +YI SYLLABLE GGUO + +0A221 +YI SYLLABLE GGUOP + +0A222 +YI SYLLABLE GGOT + +0A223 +YI SYLLABLE GGOX + +0A224 +YI SYLLABLE GGO + +0A225 +YI SYLLABLE GGOP + +0A226 +YI SYLLABLE GGET + +0A227 +YI SYLLABLE GGEX + +0A228 +YI SYLLABLE GGE + +0A229 +YI SYLLABLE GGEP + +0A22A +YI SYLLABLE GGUT + +0A22B +YI SYLLABLE GGUX + +0A22C +YI SYLLABLE GGU + +0A22D +YI SYLLABLE GGUP + +0A22E +YI SYLLABLE GGURX + +0A22F +YI SYLLABLE GGUR + +0A230 +YI SYLLABLE MGIEX + +0A231 +YI SYLLABLE MGIE + +0A232 +YI SYLLABLE MGAT + +0A233 +YI SYLLABLE MGAX + +0A234 +YI SYLLABLE MGA + +0A235 +YI SYLLABLE MGAP + +0A236 +YI SYLLABLE MGUOX + +0A237 +YI SYLLABLE MGUO + +0A238 +YI SYLLABLE MGUOP + +0A239 +YI SYLLABLE MGOT + +0A23A +YI SYLLABLE MGOX + +0A23B +YI SYLLABLE MGO + +0A23C +YI SYLLABLE MGOP + +0A23D +YI SYLLABLE MGEX + +0A23E +YI SYLLABLE MGE + +0A23F +YI SYLLABLE MGEP + +0A240 +YI SYLLABLE MGUT + +0A241 +YI SYLLABLE MGUX + +0A242 +YI SYLLABLE MGU + +0A243 +YI SYLLABLE MGUP + +0A244 +YI SYLLABLE MGURX + +0A245 +YI SYLLABLE MGUR + +0A246 +YI SYLLABLE HXIT + +0A247 +YI SYLLABLE HXIX + +0A248 +YI SYLLABLE HXI + +0A249 +YI SYLLABLE HXIP + +0A24A +YI SYLLABLE HXIET + +0A24B +YI SYLLABLE HXIEX + +0A24C +YI SYLLABLE HXIE + +0A24D +YI SYLLABLE HXIEP + +0A24E +YI SYLLABLE HXAT + +0A24F +YI SYLLABLE HXAX + +0A250 +YI SYLLABLE HXA + +0A251 +YI SYLLABLE HXAP + +0A252 +YI SYLLABLE HXUOT + +0A253 +YI SYLLABLE HXUOX + +0A254 +YI SYLLABLE HXUO + +0A255 +YI SYLLABLE HXUOP + +0A256 +YI SYLLABLE HXOT + +0A257 +YI SYLLABLE HXOX + +0A258 +YI SYLLABLE HXO + +0A259 +YI SYLLABLE HXOP + +0A25A +YI SYLLABLE HXEX + +0A25B +YI SYLLABLE HXE + +0A25C +YI SYLLABLE HXEP + +0A25D +YI SYLLABLE NGIEX + +0A25E +YI SYLLABLE NGIE + +0A25F +YI SYLLABLE NGIEP + +0A260 +YI SYLLABLE NGAT + +0A261 +YI SYLLABLE NGAX + +0A262 +YI SYLLABLE NGA + +0A263 +YI SYLLABLE NGAP + +0A264 +YI SYLLABLE NGUOT + +0A265 +YI SYLLABLE NGUOX + +0A266 +YI SYLLABLE NGUO + +0A267 +YI SYLLABLE NGOT + +0A268 +YI SYLLABLE NGOX + +0A269 +YI SYLLABLE NGO + +0A26A +YI SYLLABLE NGOP + +0A26B +YI SYLLABLE NGEX + +0A26C +YI SYLLABLE NGE + +0A26D +YI SYLLABLE NGEP + +0A26E +YI SYLLABLE HIT + +0A26F +YI SYLLABLE HIEX + +0A270 +YI SYLLABLE HIE + +0A271 +YI SYLLABLE HAT + +0A272 +YI SYLLABLE HAX + +0A273 +YI SYLLABLE HA + +0A274 +YI SYLLABLE HAP + +0A275 +YI SYLLABLE HUOT + +0A276 +YI SYLLABLE HUOX + +0A277 +YI SYLLABLE HUO + +0A278 +YI SYLLABLE HUOP + +0A279 +YI SYLLABLE HOT + +0A27A +YI SYLLABLE HOX + +0A27B +YI SYLLABLE HO + +0A27C +YI SYLLABLE HOP + +0A27D +YI SYLLABLE HEX + +0A27E +YI SYLLABLE HE + +0A27F +YI SYLLABLE HEP + +0A280 +YI SYLLABLE WAT + +0A281 +YI SYLLABLE WAX + +0A282 +YI SYLLABLE WA + +0A283 +YI SYLLABLE WAP + +0A284 +YI SYLLABLE WUOX + +0A285 +YI SYLLABLE WUO + +0A286 +YI SYLLABLE WUOP + +0A287 +YI SYLLABLE WOX + +0A288 +YI SYLLABLE WO + +0A289 +YI SYLLABLE WOP + +0A28A +YI SYLLABLE WEX + +0A28B +YI SYLLABLE WE + +0A28C +YI SYLLABLE WEP + +0A28D +YI SYLLABLE ZIT + +0A28E +YI SYLLABLE ZIX + +0A28F +YI SYLLABLE ZI + +0A290 +YI SYLLABLE ZIP + +0A291 +YI SYLLABLE ZIEX + +0A292 +YI SYLLABLE ZIE + +0A293 +YI SYLLABLE ZIEP + +0A294 +YI SYLLABLE ZAT + +0A295 +YI SYLLABLE ZAX + +0A296 +YI SYLLABLE ZA + +0A297 +YI SYLLABLE ZAP + +0A298 +YI SYLLABLE ZUOX + +0A299 +YI SYLLABLE ZUO + +0A29A +YI SYLLABLE ZUOP + +0A29B +YI SYLLABLE ZOT + +0A29C +YI SYLLABLE ZOX + +0A29D +YI SYLLABLE ZO + +0A29E +YI SYLLABLE ZOP + +0A29F +YI SYLLABLE ZEX + +0A2A0 +YI SYLLABLE ZE + +0A2A1 +YI SYLLABLE ZEP + +0A2A2 +YI SYLLABLE ZUT + +0A2A3 +YI SYLLABLE ZUX + +0A2A4 +YI SYLLABLE ZU + +0A2A5 +YI SYLLABLE ZUP + +0A2A6 +YI SYLLABLE ZURX + +0A2A7 +YI SYLLABLE ZUR + +0A2A8 +YI SYLLABLE ZYT + +0A2A9 +YI SYLLABLE ZYX + +0A2AA +YI SYLLABLE ZY + +0A2AB +YI SYLLABLE ZYP + +0A2AC +YI SYLLABLE ZYRX + +0A2AD +YI SYLLABLE ZYR + +0A2AE +YI SYLLABLE CIT + +0A2AF +YI SYLLABLE CIX + +0A2B0 +YI SYLLABLE CI + +0A2B1 +YI SYLLABLE CIP + +0A2B2 +YI SYLLABLE CIET + +0A2B3 +YI SYLLABLE CIEX + +0A2B4 +YI SYLLABLE CIE + +0A2B5 +YI SYLLABLE CIEP + +0A2B6 +YI SYLLABLE CAT + +0A2B7 +YI SYLLABLE CAX + +0A2B8 +YI SYLLABLE CA + +0A2B9 +YI SYLLABLE CAP + +0A2BA +YI SYLLABLE CUOX + +0A2BB +YI SYLLABLE CUO + +0A2BC +YI SYLLABLE CUOP + +0A2BD +YI SYLLABLE COT + +0A2BE +YI SYLLABLE COX + +0A2BF +YI SYLLABLE CO + +0A2C0 +YI SYLLABLE COP + +0A2C1 +YI SYLLABLE CEX + +0A2C2 +YI SYLLABLE CE + +0A2C3 +YI SYLLABLE CEP + +0A2C4 +YI SYLLABLE CUT + +0A2C5 +YI SYLLABLE CUX + +0A2C6 +YI SYLLABLE CU + +0A2C7 +YI SYLLABLE CUP + +0A2C8 +YI SYLLABLE CURX + +0A2C9 +YI SYLLABLE CUR + +0A2CA +YI SYLLABLE CYT + +0A2CB +YI SYLLABLE CYX + +0A2CC +YI SYLLABLE CY + +0A2CD +YI SYLLABLE CYP + +0A2CE +YI SYLLABLE CYRX + +0A2CF +YI SYLLABLE CYR + +0A2D0 +YI SYLLABLE ZZIT + +0A2D1 +YI SYLLABLE ZZIX + +0A2D2 +YI SYLLABLE ZZI + +0A2D3 +YI SYLLABLE ZZIP + +0A2D4 +YI SYLLABLE ZZIET + +0A2D5 +YI SYLLABLE ZZIEX + +0A2D6 +YI SYLLABLE ZZIE + +0A2D7 +YI SYLLABLE ZZIEP + +0A2D8 +YI SYLLABLE ZZAT + +0A2D9 +YI SYLLABLE ZZAX + +0A2DA +YI SYLLABLE ZZA + +0A2DB +YI SYLLABLE ZZAP + +0A2DC +YI SYLLABLE ZZOX + +0A2DD +YI SYLLABLE ZZO + +0A2DE +YI SYLLABLE ZZOP + +0A2DF +YI SYLLABLE ZZEX + +0A2E0 +YI SYLLABLE ZZE + +0A2E1 +YI SYLLABLE ZZEP + +0A2E2 +YI SYLLABLE ZZUX + +0A2E3 +YI SYLLABLE ZZU + +0A2E4 +YI SYLLABLE ZZUP + +0A2E5 +YI SYLLABLE ZZURX + +0A2E6 +YI SYLLABLE ZZUR + +0A2E7 +YI SYLLABLE ZZYT + +0A2E8 +YI SYLLABLE ZZYX + +0A2E9 +YI SYLLABLE ZZY + +0A2EA +YI SYLLABLE ZZYP + +0A2EB +YI SYLLABLE ZZYRX + +0A2EC +YI SYLLABLE ZZYR + +0A2ED +YI SYLLABLE NZIT + +0A2EE +YI SYLLABLE NZIX + +0A2EF +YI SYLLABLE NZI + +0A2F0 +YI SYLLABLE NZIP + +0A2F1 +YI SYLLABLE NZIEX + +0A2F2 +YI SYLLABLE NZIE + +0A2F3 +YI SYLLABLE NZIEP + +0A2F4 +YI SYLLABLE NZAT + +0A2F5 +YI SYLLABLE NZAX + +0A2F6 +YI SYLLABLE NZA + +0A2F7 +YI SYLLABLE NZAP + +0A2F8 +YI SYLLABLE NZUOX + +0A2F9 +YI SYLLABLE NZUO + +0A2FA +YI SYLLABLE NZOX + +0A2FB +YI SYLLABLE NZOP + +0A2FC +YI SYLLABLE NZEX + +0A2FD +YI SYLLABLE NZE + +0A2FE +YI SYLLABLE NZUX + +0A2FF +YI SYLLABLE NZU + +0A300 +YI SYLLABLE NZUP + +0A301 +YI SYLLABLE NZURX + +0A302 +YI SYLLABLE NZUR + +0A303 +YI SYLLABLE NZYT + +0A304 +YI SYLLABLE NZYX + +0A305 +YI SYLLABLE NZY + +0A306 +YI SYLLABLE NZYP + +0A307 +YI SYLLABLE NZYRX + +0A308 +YI SYLLABLE NZYR + +0A309 +YI SYLLABLE SIT + +0A30A +YI SYLLABLE SIX + +0A30B +YI SYLLABLE SI + +0A30C +YI SYLLABLE SIP + +0A30D +YI SYLLABLE SIEX + +0A30E +YI SYLLABLE SIE + +0A30F +YI SYLLABLE SIEP + +0A310 +YI SYLLABLE SAT + +0A311 +YI SYLLABLE SAX + +0A312 +YI SYLLABLE SA + +0A313 +YI SYLLABLE SAP + +0A314 +YI SYLLABLE SUOX + +0A315 +YI SYLLABLE SUO + +0A316 +YI SYLLABLE SUOP + +0A317 +YI SYLLABLE SOT + +0A318 +YI SYLLABLE SOX + +0A319 +YI SYLLABLE SO + +0A31A +YI SYLLABLE SOP + +0A31B +YI SYLLABLE SEX + +0A31C +YI SYLLABLE SE + +0A31D +YI SYLLABLE SEP + +0A31E +YI SYLLABLE SUT + +0A31F +YI SYLLABLE SUX + +0A320 +YI SYLLABLE SU + +0A321 +YI SYLLABLE SUP + +0A322 +YI SYLLABLE SURX + +0A323 +YI SYLLABLE SUR + +0A324 +YI SYLLABLE SYT + +0A325 +YI SYLLABLE SYX + +0A326 +YI SYLLABLE SY + +0A327 +YI SYLLABLE SYP + +0A328 +YI SYLLABLE SYRX + +0A329 +YI SYLLABLE SYR + +0A32A +YI SYLLABLE SSIT + +0A32B +YI SYLLABLE SSIX + +0A32C +YI SYLLABLE SSI + +0A32D +YI SYLLABLE SSIP + +0A32E +YI SYLLABLE SSIEX + +0A32F +YI SYLLABLE SSIE + +0A330 +YI SYLLABLE SSIEP + +0A331 +YI SYLLABLE SSAT + +0A332 +YI SYLLABLE SSAX + +0A333 +YI SYLLABLE SSA + +0A334 +YI SYLLABLE SSAP + +0A335 +YI SYLLABLE SSOT + +0A336 +YI SYLLABLE SSOX + +0A337 +YI SYLLABLE SSO + +0A338 +YI SYLLABLE SSOP + +0A339 +YI SYLLABLE SSEX + +0A33A +YI SYLLABLE SSE + +0A33B +YI SYLLABLE SSEP + +0A33C +YI SYLLABLE SSUT + +0A33D +YI SYLLABLE SSUX + +0A33E +YI SYLLABLE SSU + +0A33F +YI SYLLABLE SSUP + +0A340 +YI SYLLABLE SSYT + +0A341 +YI SYLLABLE SSYX + +0A342 +YI SYLLABLE SSY + +0A343 +YI SYLLABLE SSYP + +0A344 +YI SYLLABLE SSYRX + +0A345 +YI SYLLABLE SSYR + +0A346 +YI SYLLABLE ZHAT + +0A347 +YI SYLLABLE ZHAX + +0A348 +YI SYLLABLE ZHA + +0A349 +YI SYLLABLE ZHAP + +0A34A +YI SYLLABLE ZHUOX + +0A34B +YI SYLLABLE ZHUO + +0A34C +YI SYLLABLE ZHUOP + +0A34D +YI SYLLABLE ZHOT + +0A34E +YI SYLLABLE ZHOX + +0A34F +YI SYLLABLE ZHO + +0A350 +YI SYLLABLE ZHOP + +0A351 +YI SYLLABLE ZHET + +0A352 +YI SYLLABLE ZHEX + +0A353 +YI SYLLABLE ZHE + +0A354 +YI SYLLABLE ZHEP + +0A355 +YI SYLLABLE ZHUT + +0A356 +YI SYLLABLE ZHUX + +0A357 +YI SYLLABLE ZHU + +0A358 +YI SYLLABLE ZHUP + +0A359 +YI SYLLABLE ZHURX + +0A35A +YI SYLLABLE ZHUR + +0A35B +YI SYLLABLE ZHYT + +0A35C +YI SYLLABLE ZHYX + +0A35D +YI SYLLABLE ZHY + +0A35E +YI SYLLABLE ZHYP + +0A35F +YI SYLLABLE ZHYRX + +0A360 +YI SYLLABLE ZHYR + +0A361 +YI SYLLABLE CHAT + +0A362 +YI SYLLABLE CHAX + +0A363 +YI SYLLABLE CHA + +0A364 +YI SYLLABLE CHAP + +0A365 +YI SYLLABLE CHUOT + +0A366 +YI SYLLABLE CHUOX + +0A367 +YI SYLLABLE CHUO + +0A368 +YI SYLLABLE CHUOP + +0A369 +YI SYLLABLE CHOT + +0A36A +YI SYLLABLE CHOX + +0A36B +YI SYLLABLE CHO + +0A36C +YI SYLLABLE CHOP + +0A36D +YI SYLLABLE CHET + +0A36E +YI SYLLABLE CHEX + +0A36F +YI SYLLABLE CHE + +0A370 +YI SYLLABLE CHEP + +0A371 +YI SYLLABLE CHUX + +0A372 +YI SYLLABLE CHU + +0A373 +YI SYLLABLE CHUP + +0A374 +YI SYLLABLE CHURX + +0A375 +YI SYLLABLE CHUR + +0A376 +YI SYLLABLE CHYT + +0A377 +YI SYLLABLE CHYX + +0A378 +YI SYLLABLE CHY + +0A379 +YI SYLLABLE CHYP + +0A37A +YI SYLLABLE CHYRX + +0A37B +YI SYLLABLE CHYR + +0A37C +YI SYLLABLE RRAX + +0A37D +YI SYLLABLE RRA + +0A37E +YI SYLLABLE RRUOX + +0A37F +YI SYLLABLE RRUO + +0A380 +YI SYLLABLE RROT + +0A381 +YI SYLLABLE RROX + +0A382 +YI SYLLABLE RRO + +0A383 +YI SYLLABLE RROP + +0A384 +YI SYLLABLE RRET + +0A385 +YI SYLLABLE RREX + +0A386 +YI SYLLABLE RRE + +0A387 +YI SYLLABLE RREP + +0A388 +YI SYLLABLE RRUT + +0A389 +YI SYLLABLE RRUX + +0A38A +YI SYLLABLE RRU + +0A38B +YI SYLLABLE RRUP + +0A38C +YI SYLLABLE RRURX + +0A38D +YI SYLLABLE RRUR + +0A38E +YI SYLLABLE RRYT + +0A38F +YI SYLLABLE RRYX + +0A390 +YI SYLLABLE RRY + +0A391 +YI SYLLABLE RRYP + +0A392 +YI SYLLABLE RRYRX + +0A393 +YI SYLLABLE RRYR + +0A394 +YI SYLLABLE NRAT + +0A395 +YI SYLLABLE NRAX + +0A396 +YI SYLLABLE NRA + +0A397 +YI SYLLABLE NRAP + +0A398 +YI SYLLABLE NROX + +0A399 +YI SYLLABLE NRO + +0A39A +YI SYLLABLE NROP + +0A39B +YI SYLLABLE NRET + +0A39C +YI SYLLABLE NREX + +0A39D +YI SYLLABLE NRE + +0A39E +YI SYLLABLE NREP + +0A39F +YI SYLLABLE NRUT + +0A3A0 +YI SYLLABLE NRUX + +0A3A1 +YI SYLLABLE NRU + +0A3A2 +YI SYLLABLE NRUP + +0A3A3 +YI SYLLABLE NRURX + +0A3A4 +YI SYLLABLE NRUR + +0A3A5 +YI SYLLABLE NRYT + +0A3A6 +YI SYLLABLE NRYX + +0A3A7 +YI SYLLABLE NRY + +0A3A8 +YI SYLLABLE NRYP + +0A3A9 +YI SYLLABLE NRYRX + +0A3AA +YI SYLLABLE NRYR + +0A3AB +YI SYLLABLE SHAT + +0A3AC +YI SYLLABLE SHAX + +0A3AD +YI SYLLABLE SHA + +0A3AE +YI SYLLABLE SHAP + +0A3AF +YI SYLLABLE SHUOX + +0A3B0 +YI SYLLABLE SHUO + +0A3B1 +YI SYLLABLE SHUOP + +0A3B2 +YI SYLLABLE SHOT + +0A3B3 +YI SYLLABLE SHOX + +0A3B4 +YI SYLLABLE SHO + +0A3B5 +YI SYLLABLE SHOP + +0A3B6 +YI SYLLABLE SHET + +0A3B7 +YI SYLLABLE SHEX + +0A3B8 +YI SYLLABLE SHE + +0A3B9 +YI SYLLABLE SHEP + +0A3BA +YI SYLLABLE SHUT + +0A3BB +YI SYLLABLE SHUX + +0A3BC +YI SYLLABLE SHU + +0A3BD +YI SYLLABLE SHUP + +0A3BE +YI SYLLABLE SHURX + +0A3BF +YI SYLLABLE SHUR + +0A3C0 +YI SYLLABLE SHYT + +0A3C1 +YI SYLLABLE SHYX + +0A3C2 +YI SYLLABLE SHY + +0A3C3 +YI SYLLABLE SHYP + +0A3C4 +YI SYLLABLE SHYRX + +0A3C5 +YI SYLLABLE SHYR + +0A3C6 +YI SYLLABLE RAT + +0A3C7 +YI SYLLABLE RAX + +0A3C8 +YI SYLLABLE RA + +0A3C9 +YI SYLLABLE RAP + +0A3CA +YI SYLLABLE RUOX + +0A3CB +YI SYLLABLE RUO + +0A3CC +YI SYLLABLE RUOP + +0A3CD +YI SYLLABLE ROT + +0A3CE +YI SYLLABLE ROX + +0A3CF +YI SYLLABLE RO + +0A3D0 +YI SYLLABLE ROP + +0A3D1 +YI SYLLABLE REX + +0A3D2 +YI SYLLABLE RE + +0A3D3 +YI SYLLABLE REP + +0A3D4 +YI SYLLABLE RUT + +0A3D5 +YI SYLLABLE RUX + +0A3D6 +YI SYLLABLE RU + +0A3D7 +YI SYLLABLE RUP + +0A3D8 +YI SYLLABLE RURX + +0A3D9 +YI SYLLABLE RUR + +0A3DA +YI SYLLABLE RYT + +0A3DB +YI SYLLABLE RYX + +0A3DC +YI SYLLABLE RY + +0A3DD +YI SYLLABLE RYP + +0A3DE +YI SYLLABLE RYRX + +0A3DF +YI SYLLABLE RYR + +0A3E0 +YI SYLLABLE JIT + +0A3E1 +YI SYLLABLE JIX + +0A3E2 +YI SYLLABLE JI + +0A3E3 +YI SYLLABLE JIP + +0A3E4 +YI SYLLABLE JIET + +0A3E5 +YI SYLLABLE JIEX + +0A3E6 +YI SYLLABLE JIE + +0A3E7 +YI SYLLABLE JIEP + +0A3E8 +YI SYLLABLE JUOT + +0A3E9 +YI SYLLABLE JUOX + +0A3EA +YI SYLLABLE JUO + +0A3EB +YI SYLLABLE JUOP + +0A3EC +YI SYLLABLE JOT + +0A3ED +YI SYLLABLE JOX + +0A3EE +YI SYLLABLE JO + +0A3EF +YI SYLLABLE JOP + +0A3F0 +YI SYLLABLE JUT + +0A3F1 +YI SYLLABLE JUX + +0A3F2 +YI SYLLABLE JU + +0A3F3 +YI SYLLABLE JUP + +0A3F4 +YI SYLLABLE JURX + +0A3F5 +YI SYLLABLE JUR + +0A3F6 +YI SYLLABLE JYT + +0A3F7 +YI SYLLABLE JYX + +0A3F8 +YI SYLLABLE JY + +0A3F9 +YI SYLLABLE JYP + +0A3FA +YI SYLLABLE JYRX + +0A3FB +YI SYLLABLE JYR + +0A3FC +YI SYLLABLE QIT + +0A3FD +YI SYLLABLE QIX + +0A3FE +YI SYLLABLE QI + +0A3FF +YI SYLLABLE QIP + +0A400 +YI SYLLABLE QIET + +0A401 +YI SYLLABLE QIEX + +0A402 +YI SYLLABLE QIE + +0A403 +YI SYLLABLE QIEP + +0A404 +YI SYLLABLE QUOT + +0A405 +YI SYLLABLE QUOX + +0A406 +YI SYLLABLE QUO + +0A407 +YI SYLLABLE QUOP + +0A408 +YI SYLLABLE QOT + +0A409 +YI SYLLABLE QOX + +0A40A +YI SYLLABLE QO + +0A40B +YI SYLLABLE QOP + +0A40C +YI SYLLABLE QUT + +0A40D +YI SYLLABLE QUX + +0A40E +YI SYLLABLE QU + +0A40F +YI SYLLABLE QUP + +0A410 +YI SYLLABLE QURX + +0A411 +YI SYLLABLE QUR + +0A412 +YI SYLLABLE QYT + +0A413 +YI SYLLABLE QYX + +0A414 +YI SYLLABLE QY + +0A415 +YI SYLLABLE QYP + +0A416 +YI SYLLABLE QYRX + +0A417 +YI SYLLABLE QYR + +0A418 +YI SYLLABLE JJIT + +0A419 +YI SYLLABLE JJIX + +0A41A +YI SYLLABLE JJI + +0A41B +YI SYLLABLE JJIP + +0A41C +YI SYLLABLE JJIET + +0A41D +YI SYLLABLE JJIEX + +0A41E +YI SYLLABLE JJIE + +0A41F +YI SYLLABLE JJIEP + +0A420 +YI SYLLABLE JJUOX + +0A421 +YI SYLLABLE JJUO + +0A422 +YI SYLLABLE JJUOP + +0A423 +YI SYLLABLE JJOT + +0A424 +YI SYLLABLE JJOX + +0A425 +YI SYLLABLE JJO + +0A426 +YI SYLLABLE JJOP + +0A427 +YI SYLLABLE JJUT + +0A428 +YI SYLLABLE JJUX + +0A429 +YI SYLLABLE JJU + +0A42A +YI SYLLABLE JJUP + +0A42B +YI SYLLABLE JJURX + +0A42C +YI SYLLABLE JJUR + +0A42D +YI SYLLABLE JJYT + +0A42E +YI SYLLABLE JJYX + +0A42F +YI SYLLABLE JJY + +0A430 +YI SYLLABLE JJYP + +0A431 +YI SYLLABLE NJIT + +0A432 +YI SYLLABLE NJIX + +0A433 +YI SYLLABLE NJI + +0A434 +YI SYLLABLE NJIP + +0A435 +YI SYLLABLE NJIET + +0A436 +YI SYLLABLE NJIEX + +0A437 +YI SYLLABLE NJIE + +0A438 +YI SYLLABLE NJIEP + +0A439 +YI SYLLABLE NJUOX + +0A43A +YI SYLLABLE NJUO + +0A43B +YI SYLLABLE NJOT + +0A43C +YI SYLLABLE NJOX + +0A43D +YI SYLLABLE NJO + +0A43E +YI SYLLABLE NJOP + +0A43F +YI SYLLABLE NJUX + +0A440 +YI SYLLABLE NJU + +0A441 +YI SYLLABLE NJUP + +0A442 +YI SYLLABLE NJURX + +0A443 +YI SYLLABLE NJUR + +0A444 +YI SYLLABLE NJYT + +0A445 +YI SYLLABLE NJYX + +0A446 +YI SYLLABLE NJY + +0A447 +YI SYLLABLE NJYP + +0A448 +YI SYLLABLE NJYRX + +0A449 +YI SYLLABLE NJYR + +0A44A +YI SYLLABLE NYIT + +0A44B +YI SYLLABLE NYIX + +0A44C +YI SYLLABLE NYI + +0A44D +YI SYLLABLE NYIP + +0A44E +YI SYLLABLE NYIET + +0A44F +YI SYLLABLE NYIEX + +0A450 +YI SYLLABLE NYIE + +0A451 +YI SYLLABLE NYIEP + +0A452 +YI SYLLABLE NYUOX + +0A453 +YI SYLLABLE NYUO + +0A454 +YI SYLLABLE NYUOP + +0A455 +YI SYLLABLE NYOT + +0A456 +YI SYLLABLE NYOX + +0A457 +YI SYLLABLE NYO + +0A458 +YI SYLLABLE NYOP + +0A459 +YI SYLLABLE NYUT + +0A45A +YI SYLLABLE NYUX + +0A45B +YI SYLLABLE NYU + +0A45C +YI SYLLABLE NYUP + +0A45D +YI SYLLABLE XIT + +0A45E +YI SYLLABLE XIX + +0A45F +YI SYLLABLE XI + +0A460 +YI SYLLABLE XIP + +0A461 +YI SYLLABLE XIET + +0A462 +YI SYLLABLE XIEX + +0A463 +YI SYLLABLE XIE + +0A464 +YI SYLLABLE XIEP + +0A465 +YI SYLLABLE XUOX + +0A466 +YI SYLLABLE XUO + +0A467 +YI SYLLABLE XOT + +0A468 +YI SYLLABLE XOX + +0A469 +YI SYLLABLE XO + +0A46A +YI SYLLABLE XOP + +0A46B +YI SYLLABLE XYT + +0A46C +YI SYLLABLE XYX + +0A46D +YI SYLLABLE XY + +0A46E +YI SYLLABLE XYP + +0A46F +YI SYLLABLE XYRX + +0A470 +YI SYLLABLE XYR + +0A471 +YI SYLLABLE YIT + +0A472 +YI SYLLABLE YIX + +0A473 +YI SYLLABLE YI + +0A474 +YI SYLLABLE YIP + +0A475 +YI SYLLABLE YIET + +0A476 +YI SYLLABLE YIEX + +0A477 +YI SYLLABLE YIE + +0A478 +YI SYLLABLE YIEP + +0A479 +YI SYLLABLE YUOT + +0A47A +YI SYLLABLE YUOX + +0A47B +YI SYLLABLE YUO + +0A47C +YI SYLLABLE YUOP + +0A47D +YI SYLLABLE YOT + +0A47E +YI SYLLABLE YOX + +0A47F +YI SYLLABLE YO + +0A480 +YI SYLLABLE YOP + +0A481 +YI SYLLABLE YUT + +0A482 +YI SYLLABLE YUX + +0A483 +YI SYLLABLE YU + +0A484 +YI SYLLABLE YUP + +0A485 +YI SYLLABLE YURX + +0A486 +YI SYLLABLE YUR + +0A487 +YI SYLLABLE YYT + +0A488 +YI SYLLABLE YYX + +0A489 +YI SYLLABLE YY + +0A48A +YI SYLLABLE YYP + +0A48B +YI SYLLABLE YYRX + +0A48C +YI SYLLABLE YYR + +0A490 +YI RADICAL QOT + +0A491 +YI RADICAL LI + +0A492 +YI RADICAL KIT + +0A493 +YI RADICAL NYIP + +0A494 +YI RADICAL CYP + +0A495 +YI RADICAL SSI + +0A496 +YI RADICAL GGOP + +0A497 +YI RADICAL GEP + +0A498 +YI RADICAL MI + +0A499 +YI RADICAL HXIT + +0A49A +YI RADICAL LYR + +0A49B +YI RADICAL BBUT + +0A49C +YI RADICAL MOP + +0A49D +YI RADICAL YO + +0A49E +YI RADICAL PUT + +0A49F +YI RADICAL HXUO + +0A4A0 +YI RADICAL TAT + +0A4A1 +YI RADICAL GA + +0A4A2 +YI RADICAL ZUP + +0A4A3 +YI RADICAL CYT + +0A4A4 +YI RADICAL DDUR + +0A4A5 +YI RADICAL BUR + +0A4A6 +YI RADICAL GGUO + +0A4A7 +YI RADICAL NYOP + +0A4A8 +YI RADICAL TU + +0A4A9 +YI RADICAL OP + +0A4AA +YI RADICAL JJUT + +0A4AB +YI RADICAL ZOT + +0A4AC +YI RADICAL PYT + +0A4AD +YI RADICAL HMO + +0A4AE +YI RADICAL YIT + +0A4AF +YI RADICAL VUR + +0A4B0 +YI RADICAL SHY + +0A4B1 +YI RADICAL VEP + +0A4B2 +YI RADICAL ZA + +0A4B3 +YI RADICAL JO + +0A4B4 +YI RADICAL NZUP + +0A4B5 +YI RADICAL JJY + +0A4B6 +YI RADICAL GOT + +0A4B7 +YI RADICAL JJIE + +0A4B8 +YI RADICAL WO + +0A4B9 +YI RADICAL DU + +0A4BA +YI RADICAL SHUR + +0A4BB +YI RADICAL LIE + +0A4BC +YI RADICAL CY + +0A4BD +YI RADICAL CUOP + +0A4BE +YI RADICAL CIP + +0A4BF +YI RADICAL HXOP + +0A4C0 +YI RADICAL SHAT + +0A4C1 +YI RADICAL ZUR + +0A4C2 +YI RADICAL SHOP + +0A4C3 +YI RADICAL CHE + +0A4C4 +YI RADICAL ZZIET + +0A4C5 +YI RADICAL NBIE + +0A4C6 +YI RADICAL KE + +0A4D0 +LISU LETTER BA + +0A4D1 +LISU LETTER PA + +0A4D2 +LISU LETTER PHA + +0A4D3 +LISU LETTER DA + +0A4D4 +LISU LETTER TA + +0A4D5 +LISU LETTER THA + +0A4D6 +LISU LETTER GA + +0A4D7 +LISU LETTER KA + +0A4D8 +LISU LETTER KHA + +0A4D9 +LISU LETTER JA + +0A4DA +LISU LETTER CA + +0A4DB +LISU LETTER CHA + +0A4DC +LISU LETTER DZA + +0A4DD +LISU LETTER TSA + +0A4DE +LISU LETTER TSHA + +0A4DF +LISU LETTER MA + +0A4E0 +LISU LETTER NA + +0A4E1 +LISU LETTER LA + +0A4E2 +LISU LETTER SA + +0A4E3 +LISU LETTER ZHA + +0A4E4 +LISU LETTER ZA + +0A4E5 +LISU LETTER NGA + +0A4E6 +LISU LETTER HA + +0A4E7 +LISU LETTER XA + +0A4E8 +LISU LETTER HHA + +0A4E9 +LISU LETTER FA + +0A4EA +LISU LETTER WA + +0A4EB +LISU LETTER SHA + +0A4EC +LISU LETTER YA + +0A4ED +LISU LETTER GHA + +0A4EE +LISU LETTER A + +0A4EF +LISU LETTER AE + +0A4F0 +LISU LETTER E + +0A4F1 +LISU LETTER EU + +0A4F2 +LISU LETTER I + +0A4F3 +LISU LETTER O + +0A4F4 +LISU LETTER U + +0A4F5 +LISU LETTER UE + +0A4F6 +LISU LETTER UH + +0A4F7 +LISU LETTER OE + +0A4F8 +LISU LETTER TONE MYA TI + +0A4F9 +LISU LETTER TONE NA PO + +0A4FA +LISU LETTER TONE MYA CYA + +0A4FB +LISU LETTER TONE MYA BO + +0A4FC +LISU LETTER TONE MYA NA + +0A4FD +LISU LETTER TONE MYA JEU + +0A4FE +LISU PUNCTUATION COMMA + +0A4FF +LISU PUNCTUATION FULL STOP + +0A500 +VAI SYLLABLE EE + +0A501 +VAI SYLLABLE EEN + +0A502 +VAI SYLLABLE HEE + +0A503 +VAI SYLLABLE WEE + +0A504 +VAI SYLLABLE WEEN + +0A505 +VAI SYLLABLE PEE + +0A506 +VAI SYLLABLE BHEE + +0A507 +VAI SYLLABLE BEE + +0A508 +VAI SYLLABLE MBEE + +0A509 +VAI SYLLABLE KPEE + +0A50A +VAI SYLLABLE MGBEE + +0A50B +VAI SYLLABLE GBEE + +0A50C +VAI SYLLABLE FEE + +0A50D +VAI SYLLABLE VEE + +0A50E +VAI SYLLABLE TEE + +0A50F +VAI SYLLABLE THEE + +0A510 +VAI SYLLABLE DHEE + +0A511 +VAI SYLLABLE DHHEE + +0A512 +VAI SYLLABLE LEE + +0A513 +VAI SYLLABLE REE + +0A514 +VAI SYLLABLE DEE + +0A515 +VAI SYLLABLE NDEE + +0A516 +VAI SYLLABLE SEE + +0A517 +VAI SYLLABLE SHEE + +0A518 +VAI SYLLABLE ZEE + +0A519 +VAI SYLLABLE ZHEE + +0A51A +VAI SYLLABLE CEE + +0A51B +VAI SYLLABLE JEE + +0A51C +VAI SYLLABLE NJEE + +0A51D +VAI SYLLABLE YEE + +0A51E +VAI SYLLABLE KEE + +0A51F +VAI SYLLABLE NGGEE + +0A520 +VAI SYLLABLE GEE + +0A521 +VAI SYLLABLE MEE + +0A522 +VAI SYLLABLE NEE + +0A523 +VAI SYLLABLE NYEE + +0A524 +VAI SYLLABLE I + +0A525 +VAI SYLLABLE IN + +0A526 +VAI SYLLABLE HI + +0A527 +VAI SYLLABLE HIN + +0A528 +VAI SYLLABLE WI + +0A529 +VAI SYLLABLE WIN + +0A52A +VAI SYLLABLE PI + +0A52B +VAI SYLLABLE BHI + +0A52C +VAI SYLLABLE BI + +0A52D +VAI SYLLABLE MBI + +0A52E +VAI SYLLABLE KPI + +0A52F +VAI SYLLABLE MGBI + +0A530 +VAI SYLLABLE GBI + +0A531 +VAI SYLLABLE FI + +0A532 +VAI SYLLABLE VI + +0A533 +VAI SYLLABLE TI + +0A534 +VAI SYLLABLE THI + +0A535 +VAI SYLLABLE DHI + +0A536 +VAI SYLLABLE DHHI + +0A537 +VAI SYLLABLE LI + +0A538 +VAI SYLLABLE RI + +0A539 +VAI SYLLABLE DI + +0A53A +VAI SYLLABLE NDI + +0A53B +VAI SYLLABLE SI + +0A53C +VAI SYLLABLE SHI + +0A53D +VAI SYLLABLE ZI + +0A53E +VAI SYLLABLE ZHI + +0A53F +VAI SYLLABLE CI + +0A540 +VAI SYLLABLE JI + +0A541 +VAI SYLLABLE NJI + +0A542 +VAI SYLLABLE YI + +0A543 +VAI SYLLABLE KI + +0A544 +VAI SYLLABLE NGGI + +0A545 +VAI SYLLABLE GI + +0A546 +VAI SYLLABLE MI + +0A547 +VAI SYLLABLE NI + +0A548 +VAI SYLLABLE NYI + +0A549 +VAI SYLLABLE A + +0A54A +VAI SYLLABLE AN + +0A54B +VAI SYLLABLE NGAN + +0A54C +VAI SYLLABLE HA + +0A54D +VAI SYLLABLE HAN + +0A54E +VAI SYLLABLE WA + +0A54F +VAI SYLLABLE WAN + +0A550 +VAI SYLLABLE PA + +0A551 +VAI SYLLABLE BHA + +0A552 +VAI SYLLABLE BA + +0A553 +VAI SYLLABLE MBA + +0A554 +VAI SYLLABLE KPA + +0A555 +VAI SYLLABLE KPAN + +0A556 +VAI SYLLABLE MGBA + +0A557 +VAI SYLLABLE GBA + +0A558 +VAI SYLLABLE FA + +0A559 +VAI SYLLABLE VA + +0A55A +VAI SYLLABLE TA + +0A55B +VAI SYLLABLE THA + +0A55C +VAI SYLLABLE DHA + +0A55D +VAI SYLLABLE DHHA + +0A55E +VAI SYLLABLE LA + +0A55F +VAI SYLLABLE RA + +0A560 +VAI SYLLABLE DA + +0A561 +VAI SYLLABLE NDA + +0A562 +VAI SYLLABLE SA + +0A563 +VAI SYLLABLE SHA + +0A564 +VAI SYLLABLE ZA + +0A565 +VAI SYLLABLE ZHA + +0A566 +VAI SYLLABLE CA + +0A567 +VAI SYLLABLE JA + +0A568 +VAI SYLLABLE NJA + +0A569 +VAI SYLLABLE YA + +0A56A +VAI SYLLABLE KA + +0A56B +VAI SYLLABLE KAN + +0A56C +VAI SYLLABLE NGGA + +0A56D +VAI SYLLABLE GA + +0A56E +VAI SYLLABLE MA + +0A56F +VAI SYLLABLE NA + +0A570 +VAI SYLLABLE NYA + +0A571 +VAI SYLLABLE OO + +0A572 +VAI SYLLABLE OON + +0A573 +VAI SYLLABLE HOO + +0A574 +VAI SYLLABLE WOO + +0A575 +VAI SYLLABLE WOON + +0A576 +VAI SYLLABLE POO + +0A577 +VAI SYLLABLE BHOO + +0A578 +VAI SYLLABLE BOO + +0A579 +VAI SYLLABLE MBOO + +0A57A +VAI SYLLABLE KPOO + +0A57B +VAI SYLLABLE MGBOO + +0A57C +VAI SYLLABLE GBOO + +0A57D +VAI SYLLABLE FOO + +0A57E +VAI SYLLABLE VOO + +0A57F +VAI SYLLABLE TOO + +0A580 +VAI SYLLABLE THOO + +0A581 +VAI SYLLABLE DHOO + +0A582 +VAI SYLLABLE DHHOO + +0A583 +VAI SYLLABLE LOO + +0A584 +VAI SYLLABLE ROO + +0A585 +VAI SYLLABLE DOO + +0A586 +VAI SYLLABLE NDOO + +0A587 +VAI SYLLABLE SOO + +0A588 +VAI SYLLABLE SHOO + +0A589 +VAI SYLLABLE ZOO + +0A58A +VAI SYLLABLE ZHOO + +0A58B +VAI SYLLABLE COO + +0A58C +VAI SYLLABLE JOO + +0A58D +VAI SYLLABLE NJOO + +0A58E +VAI SYLLABLE YOO + +0A58F +VAI SYLLABLE KOO + +0A590 +VAI SYLLABLE NGGOO + +0A591 +VAI SYLLABLE GOO + +0A592 +VAI SYLLABLE MOO + +0A593 +VAI SYLLABLE NOO + +0A594 +VAI SYLLABLE NYOO + +0A595 +VAI SYLLABLE U + +0A596 +VAI SYLLABLE UN + +0A597 +VAI SYLLABLE HU + +0A598 +VAI SYLLABLE HUN + +0A599 +VAI SYLLABLE WU + +0A59A +VAI SYLLABLE WUN + +0A59B +VAI SYLLABLE PU + +0A59C +VAI SYLLABLE BHU + +0A59D +VAI SYLLABLE BU + +0A59E +VAI SYLLABLE MBU + +0A59F +VAI SYLLABLE KPU + +0A5A0 +VAI SYLLABLE MGBU + +0A5A1 +VAI SYLLABLE GBU + +0A5A2 +VAI SYLLABLE FU + +0A5A3 +VAI SYLLABLE VU + +0A5A4 +VAI SYLLABLE TU + +0A5A5 +VAI SYLLABLE THU + +0A5A6 +VAI SYLLABLE DHU + +0A5A7 +VAI SYLLABLE DHHU + +0A5A8 +VAI SYLLABLE LU + +0A5A9 +VAI SYLLABLE RU + +0A5AA +VAI SYLLABLE DU + +0A5AB +VAI SYLLABLE NDU + +0A5AC +VAI SYLLABLE SU + +0A5AD +VAI SYLLABLE SHU + +0A5AE +VAI SYLLABLE ZU + +0A5AF +VAI SYLLABLE ZHU + +0A5B0 +VAI SYLLABLE CU + +0A5B1 +VAI SYLLABLE JU + +0A5B2 +VAI SYLLABLE NJU + +0A5B3 +VAI SYLLABLE YU + +0A5B4 +VAI SYLLABLE KU + +0A5B5 +VAI SYLLABLE NGGU + +0A5B6 +VAI SYLLABLE GU + +0A5B7 +VAI SYLLABLE MU + +0A5B8 +VAI SYLLABLE NU + +0A5B9 +VAI SYLLABLE NYU + +0A5BA +VAI SYLLABLE O + +0A5BB +VAI SYLLABLE ON + +0A5BC +VAI SYLLABLE NGON + +0A5BD +VAI SYLLABLE HO + +0A5BE +VAI SYLLABLE HON + +0A5BF +VAI SYLLABLE WO + +0A5C0 +VAI SYLLABLE WON + +0A5C1 +VAI SYLLABLE PO + +0A5C2 +VAI SYLLABLE BHO + +0A5C3 +VAI SYLLABLE BO + +0A5C4 +VAI SYLLABLE MBO + +0A5C5 +VAI SYLLABLE KPO + +0A5C6 +VAI SYLLABLE MGBO + +0A5C7 +VAI SYLLABLE GBO + +0A5C8 +VAI SYLLABLE GBON + +0A5C9 +VAI SYLLABLE FO + +0A5CA +VAI SYLLABLE VO + +0A5CB +VAI SYLLABLE TO + +0A5CC +VAI SYLLABLE THO + +0A5CD +VAI SYLLABLE DHO + +0A5CE +VAI SYLLABLE DHHO + +0A5CF +VAI SYLLABLE LO + +0A5D0 +VAI SYLLABLE RO + +0A5D1 +VAI SYLLABLE DO + +0A5D2 +VAI SYLLABLE NDO + +0A5D3 +VAI SYLLABLE SO + +0A5D4 +VAI SYLLABLE SHO + +0A5D5 +VAI SYLLABLE ZO + +0A5D6 +VAI SYLLABLE ZHO + +0A5D7 +VAI SYLLABLE CO + +0A5D8 +VAI SYLLABLE JO + +0A5D9 +VAI SYLLABLE NJO + +0A5DA +VAI SYLLABLE YO + +0A5DB +VAI SYLLABLE KO + +0A5DC +VAI SYLLABLE NGGO + +0A5DD +VAI SYLLABLE GO + +0A5DE +VAI SYLLABLE MO + +0A5DF +VAI SYLLABLE NO + +0A5E0 +VAI SYLLABLE NYO + +0A5E1 +VAI SYLLABLE E + +0A5E2 +VAI SYLLABLE EN + +0A5E3 +VAI SYLLABLE NGEN + +0A5E4 +VAI SYLLABLE HE + +0A5E5 +VAI SYLLABLE HEN + +0A5E6 +VAI SYLLABLE WE + +0A5E7 +VAI SYLLABLE WEN + +0A5E8 +VAI SYLLABLE PE + +0A5E9 +VAI SYLLABLE BHE + +0A5EA +VAI SYLLABLE BE + +0A5EB +VAI SYLLABLE MBE + +0A5EC +VAI SYLLABLE KPE + +0A5ED +VAI SYLLABLE KPEN + +0A5EE +VAI SYLLABLE MGBE + +0A5EF +VAI SYLLABLE GBE + +0A5F0 +VAI SYLLABLE GBEN + +0A5F1 +VAI SYLLABLE FE + +0A5F2 +VAI SYLLABLE VE + +0A5F3 +VAI SYLLABLE TE + +0A5F4 +VAI SYLLABLE THE + +0A5F5 +VAI SYLLABLE DHE + +0A5F6 +VAI SYLLABLE DHHE + +0A5F7 +VAI SYLLABLE LE + +0A5F8 +VAI SYLLABLE RE + +0A5F9 +VAI SYLLABLE DE + +0A5FA +VAI SYLLABLE NDE + +0A5FB +VAI SYLLABLE SE + +0A5FC +VAI SYLLABLE SHE + +0A5FD +VAI SYLLABLE ZE + +0A5FE +VAI SYLLABLE ZHE + +0A5FF +VAI SYLLABLE CE + +0A600 +VAI SYLLABLE JE + +0A601 +VAI SYLLABLE NJE + +0A602 +VAI SYLLABLE YE + +0A603 +VAI SYLLABLE KE + +0A604 +VAI SYLLABLE NGGE + +0A605 +VAI SYLLABLE NGGEN + +0A606 +VAI SYLLABLE GE + +0A607 +VAI SYLLABLE GEN + +0A608 +VAI SYLLABLE ME + +0A609 +VAI SYLLABLE NE + +0A60A +VAI SYLLABLE NYE + +0A60B +VAI SYLLABLE NG + +0A60C +VAI SYLLABLE LENGTHENER + +0A60D +VAI COMMA + +0A60E +VAI FULL STOP + +0A60F +VAI QUESTION MARK + +0A610 +VAI SYLLABLE NDOLE FA + +0A611 +VAI SYLLABLE NDOLE KA + +0A612 +VAI SYLLABLE NDOLE SOO + +0A613 +VAI SYMBOL FEENG + +0A614 +VAI SYMBOL KEENG + +0A615 +VAI SYMBOL TING + +0A616 +VAI SYMBOL NII + +0A617 +VAI SYMBOL BANG + +0A618 +VAI SYMBOL FAA + +0A619 +VAI SYMBOL TAA + +0A61A +VAI SYMBOL DANG + +0A61B +VAI SYMBOL DOONG + +0A61C +VAI SYMBOL KUNG + +0A61D +VAI SYMBOL TONG + +0A61E +VAI SYMBOL DO-O + +0A61F +VAI SYMBOL JONG + +0A620 +VAI DIGIT ZERO + +0A621 +VAI DIGIT ONE + +0A622 +VAI DIGIT TWO + +0A623 +VAI DIGIT THREE + +0A624 +VAI DIGIT FOUR + +0A625 +VAI DIGIT FIVE + +0A626 +VAI DIGIT SIX + +0A627 +VAI DIGIT SEVEN + +0A628 +VAI DIGIT EIGHT + +0A629 +VAI DIGIT NINE + +0A62A +VAI SYLLABLE NDOLE MA + +0A62B +VAI SYLLABLE NDOLE DO + +0A640 +CYRILLIC CAPITAL LETTER ZEMLYA + +0A641 +CYRILLIC SMALL LETTER ZEMLYA + +0A642 +CYRILLIC CAPITAL LETTER DZELO + +0A643 +CYRILLIC SMALL LETTER DZELO + +0A644 +CYRILLIC CAPITAL LETTER REVERSED DZE + +0A645 +CYRILLIC SMALL LETTER REVERSED DZE + +0A646 +CYRILLIC CAPITAL LETTER IOTA + +0A647 +CYRILLIC SMALL LETTER IOTA + +0A648 +CYRILLIC CAPITAL LETTER DJERV + +0A649 +CYRILLIC SMALL LETTER DJERV + +0A64A +CYRILLIC CAPITAL LETTER MONOGRAPH UK + +0A64B +CYRILLIC SMALL LETTER MONOGRAPH UK + +0A64C +CYRILLIC CAPITAL LETTER BROAD OMEGA + +0A64D +CYRILLIC SMALL LETTER BROAD OMEGA + +0A64E +CYRILLIC CAPITAL LETTER NEUTRAL YER + +0A64F +CYRILLIC SMALL LETTER NEUTRAL YER + +0A650 +CYRILLIC CAPITAL LETTER YERU WITH BACK YER + +0A651 +CYRILLIC SMALL LETTER YERU WITH BACK YER + +0A652 +CYRILLIC CAPITAL LETTER IOTIFIED YAT + +0A653 +CYRILLIC SMALL LETTER IOTIFIED YAT + +0A654 +CYRILLIC CAPITAL LETTER REVERSED YU + +0A655 +CYRILLIC SMALL LETTER REVERSED YU + +0A656 +CYRILLIC CAPITAL LETTER IOTIFIED A + +0A657 +CYRILLIC SMALL LETTER IOTIFIED A + +0A658 +CYRILLIC CAPITAL LETTER CLOSED LITTLE YUS + +0A659 +CYRILLIC SMALL LETTER CLOSED LITTLE YUS + +0A65A +CYRILLIC CAPITAL LETTER BLENDED YUS + +0A65B +CYRILLIC SMALL LETTER BLENDED YUS + +0A65C +CYRILLIC CAPITAL LETTER IOTIFIED CLOSED LITTLE YUS + +0A65D +CYRILLIC SMALL LETTER IOTIFIED CLOSED LITTLE YUS + +0A65E +CYRILLIC CAPITAL LETTER YN + +0A65F +CYRILLIC SMALL LETTER YN + +0A660 +CYRILLIC CAPITAL LETTER REVERSED TSE + +0A661 +CYRILLIC SMALL LETTER REVERSED TSE + +0A662 +CYRILLIC CAPITAL LETTER SOFT DE + +0A663 +CYRILLIC SMALL LETTER SOFT DE + +0A664 +CYRILLIC CAPITAL LETTER SOFT EL + +0A665 +CYRILLIC SMALL LETTER SOFT EL + +0A666 +CYRILLIC CAPITAL LETTER SOFT EM + +0A667 +CYRILLIC SMALL LETTER SOFT EM + +0A668 +CYRILLIC CAPITAL LETTER MONOCULAR O + +0A669 +CYRILLIC SMALL LETTER MONOCULAR O + +0A66A +CYRILLIC CAPITAL LETTER BINOCULAR O + +0A66B +CYRILLIC SMALL LETTER BINOCULAR O + +0A66C +CYRILLIC CAPITAL LETTER DOUBLE MONOCULAR O + +0A66D +CYRILLIC SMALL LETTER DOUBLE MONOCULAR O + +0A66E +CYRILLIC LETTER MULTIOCULAR O + +0A66F +COMBINING CYRILLIC VZMET + +0A670 +COMBINING CYRILLIC TEN MILLIONS SIGN + +0A671 +COMBINING CYRILLIC HUNDRED MILLIONS SIGN + +0A672 +COMBINING CYRILLIC THOUSAND MILLIONS SIGN + +0A673 +SLAVONIC ASTERISK + +0A674 +COMBINING CYRILLIC LETTER UKRAINIAN IE + +0A675 +COMBINING CYRILLIC LETTER I + +0A676 +COMBINING CYRILLIC LETTER YI + +0A677 +COMBINING CYRILLIC LETTER U + +0A678 +COMBINING CYRILLIC LETTER HARD SIGN + +0A679 +COMBINING CYRILLIC LETTER YERU + +0A67A +COMBINING CYRILLIC LETTER SOFT SIGN + +0A67B +COMBINING CYRILLIC LETTER OMEGA + +0A67C +COMBINING CYRILLIC KAVYKA + +0A67D +COMBINING CYRILLIC PAYEROK + +0A67E +CYRILLIC KAVYKA + +0A67F +CYRILLIC PAYEROK + +0A680 +CYRILLIC CAPITAL LETTER DWE + +0A681 +CYRILLIC SMALL LETTER DWE + +0A682 +CYRILLIC CAPITAL LETTER DZWE + +0A683 +CYRILLIC SMALL LETTER DZWE + +0A684 +CYRILLIC CAPITAL LETTER ZHWE + +0A685 +CYRILLIC SMALL LETTER ZHWE + +0A686 +CYRILLIC CAPITAL LETTER CCHE + +0A687 +CYRILLIC SMALL LETTER CCHE + +0A688 +CYRILLIC CAPITAL LETTER DZZE + +0A689 +CYRILLIC SMALL LETTER DZZE + +0A68A +CYRILLIC CAPITAL LETTER TE WITH MIDDLE HOOK + +0A68B +CYRILLIC SMALL LETTER TE WITH MIDDLE HOOK + +0A68C +CYRILLIC CAPITAL LETTER TWE + +0A68D +CYRILLIC SMALL LETTER TWE + +0A68E +CYRILLIC CAPITAL LETTER TSWE + +0A68F +CYRILLIC SMALL LETTER TSWE + +0A690 +CYRILLIC CAPITAL LETTER TSSE + +0A691 +CYRILLIC SMALL LETTER TSSE + +0A692 +CYRILLIC CAPITAL LETTER TCHE + +0A693 +CYRILLIC SMALL LETTER TCHE + +0A694 +CYRILLIC CAPITAL LETTER HWE + +0A695 +CYRILLIC SMALL LETTER HWE + +0A696 +CYRILLIC CAPITAL LETTER SHWE + +0A697 +CYRILLIC SMALL LETTER SHWE + +0A698 +CYRILLIC CAPITAL LETTER DOUBLE O + +0A699 +CYRILLIC SMALL LETTER DOUBLE O + +0A69A +CYRILLIC CAPITAL LETTER CROSSED O + +0A69B +CYRILLIC SMALL LETTER CROSSED O + +0A69C +MODIFIER LETTER CYRILLIC HARD SIGN + +0A69D +MODIFIER LETTER CYRILLIC SOFT SIGN + +0A69E +COMBINING CYRILLIC LETTER EF + +0A69F +COMBINING CYRILLIC LETTER IOTIFIED E + +0A6A0 +BAMUM LETTER A + +0A6A1 +BAMUM LETTER KA + +0A6A2 +BAMUM LETTER U + +0A6A3 +BAMUM LETTER KU + +0A6A4 +BAMUM LETTER EE + +0A6A5 +BAMUM LETTER REE + +0A6A6 +BAMUM LETTER TAE + +0A6A7 +BAMUM LETTER O + +0A6A8 +BAMUM LETTER NYI + +0A6A9 +BAMUM LETTER I + +0A6AA +BAMUM LETTER LA + +0A6AB +BAMUM LETTER PA + +0A6AC +BAMUM LETTER RII + +0A6AD +BAMUM LETTER RIEE + +0A6AE +BAMUM LETTER LEEEE + +0A6AF +BAMUM LETTER MEEEE + +0A6B0 +BAMUM LETTER TAA + +0A6B1 +BAMUM LETTER NDAA + +0A6B2 +BAMUM LETTER NJAEM + +0A6B3 +BAMUM LETTER M + +0A6B4 +BAMUM LETTER SUU + +0A6B5 +BAMUM LETTER MU + +0A6B6 +BAMUM LETTER SHII + +0A6B7 +BAMUM LETTER SI + +0A6B8 +BAMUM LETTER SHEUX + +0A6B9 +BAMUM LETTER SEUX + +0A6BA +BAMUM LETTER KYEE + +0A6BB +BAMUM LETTER KET + +0A6BC +BAMUM LETTER NUAE + +0A6BD +BAMUM LETTER NU + +0A6BE +BAMUM LETTER NJUAE + +0A6BF +BAMUM LETTER YOQ + +0A6C0 +BAMUM LETTER SHU + +0A6C1 +BAMUM LETTER YUQ + +0A6C2 +BAMUM LETTER YA + +0A6C3 +BAMUM LETTER NSHA + +0A6C4 +BAMUM LETTER KEUX + +0A6C5 +BAMUM LETTER PEUX + +0A6C6 +BAMUM LETTER NJEE + +0A6C7 +BAMUM LETTER NTEE + +0A6C8 +BAMUM LETTER PUE + +0A6C9 +BAMUM LETTER WUE + +0A6CA +BAMUM LETTER PEE + +0A6CB +BAMUM LETTER FEE + +0A6CC +BAMUM LETTER RU + +0A6CD +BAMUM LETTER LU + +0A6CE +BAMUM LETTER MI + +0A6CF +BAMUM LETTER NI + +0A6D0 +BAMUM LETTER REUX + +0A6D1 +BAMUM LETTER RAE + +0A6D2 +BAMUM LETTER KEN + +0A6D3 +BAMUM LETTER NGKWAEN + +0A6D4 +BAMUM LETTER NGGA + +0A6D5 +BAMUM LETTER NGA + +0A6D6 +BAMUM LETTER SHO + +0A6D7 +BAMUM LETTER PUAE + +0A6D8 +BAMUM LETTER FU + +0A6D9 +BAMUM LETTER FOM + +0A6DA +BAMUM LETTER WA + +0A6DB +BAMUM LETTER NA + +0A6DC +BAMUM LETTER LI + +0A6DD +BAMUM LETTER PI + +0A6DE +BAMUM LETTER LOQ + +0A6DF +BAMUM LETTER KO + +0A6E0 +BAMUM LETTER MBEN + +0A6E1 +BAMUM LETTER REN + +0A6E2 +BAMUM LETTER MEN + +0A6E3 +BAMUM LETTER MA + +0A6E4 +BAMUM LETTER TI + +0A6E5 +BAMUM LETTER KI + +0A6E6 +BAMUM LETTER MO + +0A6E7 +BAMUM LETTER MBAA + +0A6E8 +BAMUM LETTER TET + +0A6E9 +BAMUM LETTER KPA + +0A6EA +BAMUM LETTER TEN + +0A6EB +BAMUM LETTER NTUU + +0A6EC +BAMUM LETTER SAMBA + +0A6ED +BAMUM LETTER FAAMAE + +0A6EE +BAMUM LETTER KOVUU + +0A6EF +BAMUM LETTER KOGHOM + +0A6F0 +BAMUM COMBINING MARK KOQNDON + +0A6F1 +BAMUM COMBINING MARK TUKWENTIS + +0A6F2 +BAMUM NJAEMLI + +0A6F3 +BAMUM FULL STOP + +0A6F4 +BAMUM COLON + +0A6F5 +BAMUM COMMA + +0A6F6 +BAMUM SEMICOLON + +0A6F7 +BAMUM QUESTION MARK + +0A700 +MODIFIER LETTER CHINESE TONE YIN PING + +0A701 +MODIFIER LETTER CHINESE TONE YANG PING + +0A702 +MODIFIER LETTER CHINESE TONE YIN SHANG + +0A703 +MODIFIER LETTER CHINESE TONE YANG SHANG + +0A704 +MODIFIER LETTER CHINESE TONE YIN QU + +0A705 +MODIFIER LETTER CHINESE TONE YANG QU + +0A706 +MODIFIER LETTER CHINESE TONE YIN RU + +0A707 +MODIFIER LETTER CHINESE TONE YANG RU + +0A708 +MODIFIER LETTER EXTRA-HIGH DOTTED TONE BAR + +0A709 +MODIFIER LETTER HIGH DOTTED TONE BAR + +0A70A +MODIFIER LETTER MID DOTTED TONE BAR + +0A70B +MODIFIER LETTER LOW DOTTED TONE BAR + +0A70C +MODIFIER LETTER EXTRA-LOW DOTTED TONE BAR + +0A70D +MODIFIER LETTER EXTRA-HIGH DOTTED LEFT-STEM TONE BAR + +0A70E +MODIFIER LETTER HIGH DOTTED LEFT-STEM TONE BAR + +0A70F +MODIFIER LETTER MID DOTTED LEFT-STEM TONE BAR + +0A710 +MODIFIER LETTER LOW DOTTED LEFT-STEM TONE BAR + +0A711 +MODIFIER LETTER EXTRA-LOW DOTTED LEFT-STEM TONE BAR + +0A712 +MODIFIER LETTER EXTRA-HIGH LEFT-STEM TONE BAR + +0A713 +MODIFIER LETTER HIGH LEFT-STEM TONE BAR + +0A714 +MODIFIER LETTER MID LEFT-STEM TONE BAR + +0A715 +MODIFIER LETTER LOW LEFT-STEM TONE BAR + +0A716 +MODIFIER LETTER EXTRA-LOW LEFT-STEM TONE BAR + +0A717 +MODIFIER LETTER DOT VERTICAL BAR + +0A718 +MODIFIER LETTER DOT SLASH + +0A719 +MODIFIER LETTER DOT HORIZONTAL BAR + +0A71A +MODIFIER LETTER LOWER RIGHT CORNER ANGLE + +0A71B +MODIFIER LETTER RAISED UP ARROW + +0A71C +MODIFIER LETTER RAISED DOWN ARROW + +0A71D +MODIFIER LETTER RAISED EXCLAMATION MARK + +0A71E +MODIFIER LETTER RAISED INVERTED EXCLAMATION MARK + +0A71F +MODIFIER LETTER LOW INVERTED EXCLAMATION MARK + +0A720 +MODIFIER LETTER STRESS AND HIGH TONE + +0A721 +MODIFIER LETTER STRESS AND LOW TONE + +0A722 +LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF + +0A723 +LATIN SMALL LETTER EGYPTOLOGICAL ALEF + +0A724 +LATIN CAPITAL LETTER EGYPTOLOGICAL AIN + +0A725 +LATIN SMALL LETTER EGYPTOLOGICAL AIN + +0A726 +LATIN CAPITAL LETTER HENG + +0A727 +LATIN SMALL LETTER HENG + +0A728 +LATIN CAPITAL LETTER TZ + +0A729 +LATIN SMALL LETTER TZ + +0A72A +LATIN CAPITAL LETTER TRESILLO + +0A72B +LATIN SMALL LETTER TRESILLO + +0A72C +LATIN CAPITAL LETTER CUATRILLO + +0A72D +LATIN SMALL LETTER CUATRILLO + +0A72E +LATIN CAPITAL LETTER CUATRILLO WITH COMMA + +0A72F +LATIN SMALL LETTER CUATRILLO WITH COMMA + +0A730 +LATIN LETTER SMALL CAPITAL F + +0A731 +LATIN LETTER SMALL CAPITAL S + +0A732 +LATIN CAPITAL LETTER AA + +0A733 +LATIN SMALL LETTER AA + +0A734 +LATIN CAPITAL LETTER AO + +0A735 +LATIN SMALL LETTER AO + +0A736 +LATIN CAPITAL LETTER AU + +0A737 +LATIN SMALL LETTER AU + +0A738 +LATIN CAPITAL LETTER AV + +0A739 +LATIN SMALL LETTER AV + +0A73A +LATIN CAPITAL LETTER AV WITH HORIZONTAL BAR + +0A73B +LATIN SMALL LETTER AV WITH HORIZONTAL BAR + +0A73C +LATIN CAPITAL LETTER AY + +0A73D +LATIN SMALL LETTER AY + +0A73E +LATIN CAPITAL LETTER REVERSED C WITH DOT + +0A73F +LATIN SMALL LETTER REVERSED C WITH DOT + +0A740 +LATIN CAPITAL LETTER K WITH STROKE + +0A741 +LATIN SMALL LETTER K WITH STROKE + +0A742 +LATIN CAPITAL LETTER K WITH DIAGONAL STROKE + +0A743 +LATIN SMALL LETTER K WITH DIAGONAL STROKE + +0A744 +LATIN CAPITAL LETTER K WITH STROKE AND DIAGONAL STROKE + +0A745 +LATIN SMALL LETTER K WITH STROKE AND DIAGONAL STROKE + +0A746 +LATIN CAPITAL LETTER BROKEN L + +0A747 +LATIN SMALL LETTER BROKEN L + +0A748 +LATIN CAPITAL LETTER L WITH HIGH STROKE + +0A749 +LATIN SMALL LETTER L WITH HIGH STROKE + +0A74A +LATIN CAPITAL LETTER O WITH LONG STROKE OVERLAY + +0A74B +LATIN SMALL LETTER O WITH LONG STROKE OVERLAY + +0A74C +LATIN CAPITAL LETTER O WITH LOOP + +0A74D +LATIN SMALL LETTER O WITH LOOP + +0A74E +LATIN CAPITAL LETTER OO + +0A74F +LATIN SMALL LETTER OO + +0A750 +LATIN CAPITAL LETTER P WITH STROKE THROUGH DESCENDER + +0A751 +LATIN SMALL LETTER P WITH STROKE THROUGH DESCENDER + +0A752 +LATIN CAPITAL LETTER P WITH FLOURISH + +0A753 +LATIN SMALL LETTER P WITH FLOURISH + +0A754 +LATIN CAPITAL LETTER P WITH SQUIRREL TAIL + +0A755 +LATIN SMALL LETTER P WITH SQUIRREL TAIL + +0A756 +LATIN CAPITAL LETTER Q WITH STROKE THROUGH DESCENDER + +0A757 +LATIN SMALL LETTER Q WITH STROKE THROUGH DESCENDER + +0A758 +LATIN CAPITAL LETTER Q WITH DIAGONAL STROKE + +0A759 +LATIN SMALL LETTER Q WITH DIAGONAL STROKE + +0A75A +LATIN CAPITAL LETTER R ROTUNDA + +0A75B +LATIN SMALL LETTER R ROTUNDA + +0A75C +LATIN CAPITAL LETTER RUM ROTUNDA + +0A75D +LATIN SMALL LETTER RUM ROTUNDA + +0A75E +LATIN CAPITAL LETTER V WITH DIAGONAL STROKE + +0A75F +LATIN SMALL LETTER V WITH DIAGONAL STROKE + +0A760 +LATIN CAPITAL LETTER VY + +0A761 +LATIN SMALL LETTER VY + +0A762 +LATIN CAPITAL LETTER VISIGOTHIC Z + +0A763 +LATIN SMALL LETTER VISIGOTHIC Z + +0A764 +LATIN CAPITAL LETTER THORN WITH STROKE + +0A765 +LATIN SMALL LETTER THORN WITH STROKE + +0A766 +LATIN CAPITAL LETTER THORN WITH STROKE THROUGH DESCENDER + +0A767 +LATIN SMALL LETTER THORN WITH STROKE THROUGH DESCENDER + +0A768 +LATIN CAPITAL LETTER VEND + +0A769 +LATIN SMALL LETTER VEND + +0A76A +LATIN CAPITAL LETTER ET + +0A76B +LATIN SMALL LETTER ET + +0A76C +LATIN CAPITAL LETTER IS + +0A76D +LATIN SMALL LETTER IS + +0A76E +LATIN CAPITAL LETTER CON + +0A76F +LATIN SMALL LETTER CON + +0A770 +MODIFIER LETTER US + +0A771 +LATIN SMALL LETTER DUM + +0A772 +LATIN SMALL LETTER LUM + +0A773 +LATIN SMALL LETTER MUM + +0A774 +LATIN SMALL LETTER NUM + +0A775 +LATIN SMALL LETTER RUM + +0A776 +LATIN LETTER SMALL CAPITAL RUM + +0A777 +LATIN SMALL LETTER TUM + +0A778 +LATIN SMALL LETTER UM + +0A779 +LATIN CAPITAL LETTER INSULAR D + +0A77A +LATIN SMALL LETTER INSULAR D + +0A77B +LATIN CAPITAL LETTER INSULAR F + +0A77C +LATIN SMALL LETTER INSULAR F + +0A77D +LATIN CAPITAL LETTER INSULAR G + +0A77E +LATIN CAPITAL LETTER TURNED INSULAR G + +0A77F +LATIN SMALL LETTER TURNED INSULAR G + +0A780 +LATIN CAPITAL LETTER TURNED L + +0A781 +LATIN SMALL LETTER TURNED L + +0A782 +LATIN CAPITAL LETTER INSULAR R + +0A783 +LATIN SMALL LETTER INSULAR R + +0A784 +LATIN CAPITAL LETTER INSULAR S + +0A785 +LATIN SMALL LETTER INSULAR S + +0A786 +LATIN CAPITAL LETTER INSULAR T + +0A787 +LATIN SMALL LETTER INSULAR T + +0A788 +MODIFIER LETTER LOW CIRCUMFLEX ACCENT + +0A789 +MODIFIER LETTER COLON + +0A78A +MODIFIER LETTER SHORT EQUALS SIGN + +0A78B +LATIN CAPITAL LETTER SALTILLO + +0A78C +LATIN SMALL LETTER SALTILLO + +0A78D +LATIN CAPITAL LETTER TURNED H + +0A78E +LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT + +0A78F +LATIN LETTER SINOLOGICAL DOT + +0A790 +LATIN CAPITAL LETTER N WITH DESCENDER + +0A791 +LATIN SMALL LETTER N WITH DESCENDER + +0A792 +LATIN CAPITAL LETTER C WITH BAR + +0A793 +LATIN SMALL LETTER C WITH BAR + +0A794 +LATIN SMALL LETTER C WITH PALATAL HOOK + +0A795 +LATIN SMALL LETTER H WITH PALATAL HOOK + +0A796 +LATIN CAPITAL LETTER B WITH FLOURISH + +0A797 +LATIN SMALL LETTER B WITH FLOURISH + +0A798 +LATIN CAPITAL LETTER F WITH STROKE + +0A799 +LATIN SMALL LETTER F WITH STROKE + +0A79A +LATIN CAPITAL LETTER VOLAPUK AE + +0A79B +LATIN SMALL LETTER VOLAPUK AE + +0A79C +LATIN CAPITAL LETTER VOLAPUK OE + +0A79D +LATIN SMALL LETTER VOLAPUK OE + +0A79E +LATIN CAPITAL LETTER VOLAPUK UE + +0A79F +LATIN SMALL LETTER VOLAPUK UE + +0A7A0 +LATIN CAPITAL LETTER G WITH OBLIQUE STROKE + +0A7A1 +LATIN SMALL LETTER G WITH OBLIQUE STROKE + +0A7A2 +LATIN CAPITAL LETTER K WITH OBLIQUE STROKE + +0A7A3 +LATIN SMALL LETTER K WITH OBLIQUE STROKE + +0A7A4 +LATIN CAPITAL LETTER N WITH OBLIQUE STROKE + +0A7A5 +LATIN SMALL LETTER N WITH OBLIQUE STROKE + +0A7A6 +LATIN CAPITAL LETTER R WITH OBLIQUE STROKE + +0A7A7 +LATIN SMALL LETTER R WITH OBLIQUE STROKE + +0A7A8 +LATIN CAPITAL LETTER S WITH OBLIQUE STROKE + +0A7A9 +LATIN SMALL LETTER S WITH OBLIQUE STROKE + +0A7AA +LATIN CAPITAL LETTER H WITH HOOK + +0A7AB +LATIN CAPITAL LETTER REVERSED OPEN E + +0A7AC +LATIN CAPITAL LETTER SCRIPT G + +0A7AD +LATIN CAPITAL LETTER L WITH BELT + +0A7AE +LATIN CAPITAL LETTER SMALL CAPITAL I + +0A7AF +LATIN LETTER SMALL CAPITAL Q + +0A7B0 +LATIN CAPITAL LETTER TURNED K + +0A7B1 +LATIN CAPITAL LETTER TURNED T + +0A7B2 +LATIN CAPITAL LETTER J WITH CROSSED-TAIL + +0A7B3 +LATIN CAPITAL LETTER CHI + +0A7B4 +LATIN CAPITAL LETTER BETA + +0A7B5 +LATIN SMALL LETTER BETA + +0A7B6 +LATIN CAPITAL LETTER OMEGA + +0A7B7 +LATIN SMALL LETTER OMEGA + +0A7B8 +LATIN CAPITAL LETTER U WITH STROKE + +0A7B9 +LATIN SMALL LETTER U WITH STROKE + +0A7BA +LATIN CAPITAL LETTER GLOTTAL A + +0A7BB +LATIN SMALL LETTER GLOTTAL A + +0A7BC +LATIN CAPITAL LETTER GLOTTAL I + +0A7BD +LATIN SMALL LETTER GLOTTAL I + +0A7BE +LATIN CAPITAL LETTER GLOTTAL U + +0A7BF +LATIN SMALL LETTER GLOTTAL U + +0A7C0 +LATIN CAPITAL LETTER OLD POLISH O + +0A7C1 +LATIN SMALL LETTER OLD POLISH O + +0A7C2 +LATIN CAPITAL LETTER ANGLICANA W + +0A7C3 +LATIN SMALL LETTER ANGLICANA W + +0A7C4 +LATIN CAPITAL LETTER C WITH PALATAL HOOK + +0A7C5 +LATIN CAPITAL LETTER S WITH HOOK + +0A7C6 +LATIN CAPITAL LETTER Z WITH PALATAL HOOK + +0A7C7 +LATIN CAPITAL LETTER D WITH SHORT STROKE OVERLAY + +0A7C8 +LATIN SMALL LETTER D WITH SHORT STROKE OVERLAY + +0A7C9 +LATIN CAPITAL LETTER S WITH SHORT STROKE OVERLAY + +0A7CA +LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY + +0A7CB +LATIN CAPITAL LETTER RAMS HORN + +0A7CC +LATIN CAPITAL LETTER S WITH DIAGONAL STROKE + +0A7CD +LATIN SMALL LETTER S WITH DIAGONAL STROKE + +0A7CE +LATIN CAPITAL LETTER PHARYNGEAL VOICED FRICATIVE + +0A7CF +LATIN SMALL LETTER PHARYNGEAL VOICED FRICATIVE + +0A7D0 +LATIN CAPITAL LETTER CLOSED INSULAR G + +0A7D1 +LATIN SMALL LETTER CLOSED INSULAR G + +0A7D2 +LATIN CAPITAL LETTER DOUBLE THORN + +0A7D3 +LATIN SMALL LETTER DOUBLE THORN + +0A7D4 +LATIN CAPITAL LETTER DOUBLE WYNN + +0A7D5 +LATIN SMALL LETTER DOUBLE WYNN + +0A7D6 +LATIN CAPITAL LETTER MIDDLE SCOTS S + +0A7D7 +LATIN SMALL LETTER MIDDLE SCOTS S + +0A7D8 +LATIN CAPITAL LETTER SIGMOID S + +0A7D9 +LATIN SMALL LETTER SIGMOID S + +0A7DA +LATIN CAPITAL LETTER LAMBDA + +0A7DB +LATIN SMALL LETTER LAMBDA + +0A7DC +LATIN CAPITAL LETTER LAMBDA WITH STROKE + +0A7F1 +MODIFIER LETTER CAPITAL S + +0A7F2 +MODIFIER LETTER CAPITAL C + +0A7F3 +MODIFIER LETTER CAPITAL F + +0A7F4 +MODIFIER LETTER CAPITAL Q + +0A7F5 +LATIN CAPITAL LETTER REVERSED HALF H + +0A7F6 +LATIN SMALL LETTER REVERSED HALF H + +0A7F7 +LATIN EPIGRAPHIC LETTER SIDEWAYS I + +0A7F8 +MODIFIER LETTER CAPITAL H WITH STROKE + +0A7F9 +MODIFIER LETTER SMALL LIGATURE OE + +0A7FA +LATIN LETTER SMALL CAPITAL TURNED M + +0A7FB +LATIN EPIGRAPHIC LETTER REVERSED F + +0A7FC +LATIN EPIGRAPHIC LETTER REVERSED P + +0A7FD +LATIN EPIGRAPHIC LETTER INVERTED M + +0A7FE +LATIN EPIGRAPHIC LETTER I LONGA + +0A7FF +LATIN EPIGRAPHIC LETTER ARCHAIC M + +0A800 +SYLOTI NAGRI LETTER A + +0A801 +SYLOTI NAGRI LETTER I + +0A802 +SYLOTI NAGRI SIGN DVISVARA + +0A803 +SYLOTI NAGRI LETTER U + +0A804 +SYLOTI NAGRI LETTER E + +0A805 +SYLOTI NAGRI LETTER O + +0A806 +SYLOTI NAGRI SIGN HASANTA + +0A807 +SYLOTI NAGRI LETTER KO + +0A808 +SYLOTI NAGRI LETTER KHO + +0A809 +SYLOTI NAGRI LETTER GO + +0A80A +SYLOTI NAGRI LETTER GHO + +0A80B +SYLOTI NAGRI SIGN ANUSVARA + +0A80C +SYLOTI NAGRI LETTER CO + +0A80D +SYLOTI NAGRI LETTER CHO + +0A80E +SYLOTI NAGRI LETTER JO + +0A80F +SYLOTI NAGRI LETTER JHO + +0A810 +SYLOTI NAGRI LETTER TTO + +0A811 +SYLOTI NAGRI LETTER TTHO + +0A812 +SYLOTI NAGRI LETTER DDO + +0A813 +SYLOTI NAGRI LETTER DDHO + +0A814 +SYLOTI NAGRI LETTER TO + +0A815 +SYLOTI NAGRI LETTER THO + +0A816 +SYLOTI NAGRI LETTER DO + +0A817 +SYLOTI NAGRI LETTER DHO + +0A818 +SYLOTI NAGRI LETTER NO + +0A819 +SYLOTI NAGRI LETTER PO + +0A81A +SYLOTI NAGRI LETTER PHO + +0A81B +SYLOTI NAGRI LETTER BO + +0A81C +SYLOTI NAGRI LETTER BHO + +0A81D +SYLOTI NAGRI LETTER MO + +0A81E +SYLOTI NAGRI LETTER RO + +0A81F +SYLOTI NAGRI LETTER LO + +0A820 +SYLOTI NAGRI LETTER RRO + +0A821 +SYLOTI NAGRI LETTER SO + +0A822 +SYLOTI NAGRI LETTER HO + +0A823 +SYLOTI NAGRI VOWEL SIGN A + +0A824 +SYLOTI NAGRI VOWEL SIGN I + +0A825 +SYLOTI NAGRI VOWEL SIGN U + +0A826 +SYLOTI NAGRI VOWEL SIGN E + +0A827 +SYLOTI NAGRI VOWEL SIGN OO + +0A828 +SYLOTI NAGRI POETRY MARK-1 + +0A829 +SYLOTI NAGRI POETRY MARK-2 + +0A82A +SYLOTI NAGRI POETRY MARK-3 + +0A82B +SYLOTI NAGRI POETRY MARK-4 + +0A82C +SYLOTI NAGRI SIGN ALTERNATE HASANTA + +0A830 +NORTH INDIC FRACTION ONE QUARTER + +0A831 +NORTH INDIC FRACTION ONE HALF + +0A832 +NORTH INDIC FRACTION THREE QUARTERS + +0A833 +NORTH INDIC FRACTION ONE SIXTEENTH + +0A834 +NORTH INDIC FRACTION ONE EIGHTH + +0A835 +NORTH INDIC FRACTION THREE SIXTEENTHS + +0A836 +NORTH INDIC QUARTER MARK + +0A837 +NORTH INDIC PLACEHOLDER MARK + +0A838 +NORTH INDIC RUPEE MARK + +0A839 +NORTH INDIC QUANTITY MARK + +0A840 +PHAGS-PA LETTER KA + +0A841 +PHAGS-PA LETTER KHA + +0A842 +PHAGS-PA LETTER GA + +0A843 +PHAGS-PA LETTER NGA + +0A844 +PHAGS-PA LETTER CA + +0A845 +PHAGS-PA LETTER CHA + +0A846 +PHAGS-PA LETTER JA + +0A847 +PHAGS-PA LETTER NYA + +0A848 +PHAGS-PA LETTER TA + +0A849 +PHAGS-PA LETTER THA + +0A84A +PHAGS-PA LETTER DA + +0A84B +PHAGS-PA LETTER NA + +0A84C +PHAGS-PA LETTER PA + +0A84D +PHAGS-PA LETTER PHA + +0A84E +PHAGS-PA LETTER BA + +0A84F +PHAGS-PA LETTER MA + +0A850 +PHAGS-PA LETTER TSA + +0A851 +PHAGS-PA LETTER TSHA + +0A852 +PHAGS-PA LETTER DZA + +0A853 +PHAGS-PA LETTER WA + +0A854 +PHAGS-PA LETTER ZHA + +0A855 +PHAGS-PA LETTER ZA + +0A856 +PHAGS-PA LETTER SMALL A + +0A857 +PHAGS-PA LETTER YA + +0A858 +PHAGS-PA LETTER RA + +0A859 +PHAGS-PA LETTER LA + +0A85A +PHAGS-PA LETTER SHA + +0A85B +PHAGS-PA LETTER SA + +0A85C +PHAGS-PA LETTER HA + +0A85D +PHAGS-PA LETTER A + +0A85E +PHAGS-PA LETTER I + +0A85F +PHAGS-PA LETTER U + +0A860 +PHAGS-PA LETTER E + +0A861 +PHAGS-PA LETTER O + +0A862 +PHAGS-PA LETTER QA + +0A863 +PHAGS-PA LETTER XA + +0A864 +PHAGS-PA LETTER FA + +0A865 +PHAGS-PA LETTER GGA + +0A866 +PHAGS-PA LETTER EE + +0A867 +PHAGS-PA SUBJOINED LETTER WA + +0A868 +PHAGS-PA SUBJOINED LETTER YA + +0A869 +PHAGS-PA LETTER TTA + +0A86A +PHAGS-PA LETTER TTHA + +0A86B +PHAGS-PA LETTER DDA + +0A86C +PHAGS-PA LETTER NNA + +0A86D +PHAGS-PA LETTER ALTERNATE YA + +0A86E +PHAGS-PA LETTER VOICELESS SHA + +0A86F +PHAGS-PA LETTER VOICED HA + +0A870 +PHAGS-PA LETTER ASPIRATED FA + +0A871 +PHAGS-PA SUBJOINED LETTER RA + +0A872 +PHAGS-PA SUPERFIXED LETTER RA + +0A873 +PHAGS-PA LETTER CANDRABINDU + +0A874 +PHAGS-PA SINGLE HEAD MARK + +0A875 +PHAGS-PA DOUBLE HEAD MARK + +0A876 +PHAGS-PA MARK SHAD + +0A877 +PHAGS-PA MARK DOUBLE SHAD + +0A880 +SAURASHTRA SIGN ANUSVARA + +0A881 +SAURASHTRA SIGN VISARGA + +0A882 +SAURASHTRA LETTER A + +0A883 +SAURASHTRA LETTER AA + +0A884 +SAURASHTRA LETTER I + +0A885 +SAURASHTRA LETTER II + +0A886 +SAURASHTRA LETTER U + +0A887 +SAURASHTRA LETTER UU + +0A888 +SAURASHTRA LETTER VOCALIC R + +0A889 +SAURASHTRA LETTER VOCALIC RR + +0A88A +SAURASHTRA LETTER VOCALIC L + +0A88B +SAURASHTRA LETTER VOCALIC LL + +0A88C +SAURASHTRA LETTER E + +0A88D +SAURASHTRA LETTER EE + +0A88E +SAURASHTRA LETTER AI + +0A88F +SAURASHTRA LETTER O + +0A890 +SAURASHTRA LETTER OO + +0A891 +SAURASHTRA LETTER AU + +0A892 +SAURASHTRA LETTER KA + +0A893 +SAURASHTRA LETTER KHA + +0A894 +SAURASHTRA LETTER GA + +0A895 +SAURASHTRA LETTER GHA + +0A896 +SAURASHTRA LETTER NGA + +0A897 +SAURASHTRA LETTER CA + +0A898 +SAURASHTRA LETTER CHA + +0A899 +SAURASHTRA LETTER JA + +0A89A +SAURASHTRA LETTER JHA + +0A89B +SAURASHTRA LETTER NYA + +0A89C +SAURASHTRA LETTER TTA + +0A89D +SAURASHTRA LETTER TTHA + +0A89E +SAURASHTRA LETTER DDA + +0A89F +SAURASHTRA LETTER DDHA + +0A8A0 +SAURASHTRA LETTER NNA + +0A8A1 +SAURASHTRA LETTER TA + +0A8A2 +SAURASHTRA LETTER THA + +0A8A3 +SAURASHTRA LETTER DA + +0A8A4 +SAURASHTRA LETTER DHA + +0A8A5 +SAURASHTRA LETTER NA + +0A8A6 +SAURASHTRA LETTER PA + +0A8A7 +SAURASHTRA LETTER PHA + +0A8A8 +SAURASHTRA LETTER BA + +0A8A9 +SAURASHTRA LETTER BHA + +0A8AA +SAURASHTRA LETTER MA + +0A8AB +SAURASHTRA LETTER YA + +0A8AC +SAURASHTRA LETTER RA + +0A8AD +SAURASHTRA LETTER LA + +0A8AE +SAURASHTRA LETTER VA + +0A8AF +SAURASHTRA LETTER SHA + +0A8B0 +SAURASHTRA LETTER SSA + +0A8B1 +SAURASHTRA LETTER SA + +0A8B2 +SAURASHTRA LETTER HA + +0A8B3 +SAURASHTRA LETTER LLA + +0A8B4 +SAURASHTRA CONSONANT SIGN HAARU + +0A8B5 +SAURASHTRA VOWEL SIGN AA + +0A8B6 +SAURASHTRA VOWEL SIGN I + +0A8B7 +SAURASHTRA VOWEL SIGN II + +0A8B8 +SAURASHTRA VOWEL SIGN U + +0A8B9 +SAURASHTRA VOWEL SIGN UU + +0A8BA +SAURASHTRA VOWEL SIGN VOCALIC R + +0A8BB +SAURASHTRA VOWEL SIGN VOCALIC RR + +0A8BC +SAURASHTRA VOWEL SIGN VOCALIC L + +0A8BD +SAURASHTRA VOWEL SIGN VOCALIC LL + +0A8BE +SAURASHTRA VOWEL SIGN E + +0A8BF +SAURASHTRA VOWEL SIGN EE + +0A8C0 +SAURASHTRA VOWEL SIGN AI + +0A8C1 +SAURASHTRA VOWEL SIGN O + +0A8C2 +SAURASHTRA VOWEL SIGN OO + +0A8C3 +SAURASHTRA VOWEL SIGN AU + +0A8C4 +SAURASHTRA SIGN VIRAMA + +0A8C5 +SAURASHTRA SIGN CANDRABINDU + +0A8CE +SAURASHTRA DANDA + +0A8CF +SAURASHTRA DOUBLE DANDA + +0A8D0 +SAURASHTRA DIGIT ZERO + +0A8D1 +SAURASHTRA DIGIT ONE + +0A8D2 +SAURASHTRA DIGIT TWO + +0A8D3 +SAURASHTRA DIGIT THREE + +0A8D4 +SAURASHTRA DIGIT FOUR + +0A8D5 +SAURASHTRA DIGIT FIVE + +0A8D6 +SAURASHTRA DIGIT SIX + +0A8D7 +SAURASHTRA DIGIT SEVEN + +0A8D8 +SAURASHTRA DIGIT EIGHT + +0A8D9 +SAURASHTRA DIGIT NINE + +0A8E0 +COMBINING DEVANAGARI DIGIT ZERO + +0A8E1 +COMBINING DEVANAGARI DIGIT ONE + +0A8E2 +COMBINING DEVANAGARI DIGIT TWO + +0A8E3 +COMBINING DEVANAGARI DIGIT THREE + +0A8E4 +COMBINING DEVANAGARI DIGIT FOUR + +0A8E5 +COMBINING DEVANAGARI DIGIT FIVE + +0A8E6 +COMBINING DEVANAGARI DIGIT SIX + +0A8E7 +COMBINING DEVANAGARI DIGIT SEVEN + +0A8E8 +COMBINING DEVANAGARI DIGIT EIGHT + +0A8E9 +COMBINING DEVANAGARI DIGIT NINE + +0A8EA +COMBINING DEVANAGARI LETTER A + +0A8EB +COMBINING DEVANAGARI LETTER U + +0A8EC +COMBINING DEVANAGARI LETTER KA + +0A8ED +COMBINING DEVANAGARI LETTER NA + +0A8EE +COMBINING DEVANAGARI LETTER PA + +0A8EF +COMBINING DEVANAGARI LETTER RA + +0A8F0 +COMBINING DEVANAGARI LETTER VI + +0A8F1 +COMBINING DEVANAGARI SIGN AVAGRAHA + +0A8F2 +DEVANAGARI SIGN SPACING CANDRABINDU + +0A8F3 +DEVANAGARI SIGN CANDRABINDU VIRAMA + +0A8F4 +DEVANAGARI SIGN DOUBLE CANDRABINDU VIRAMA + +0A8F5 +DEVANAGARI SIGN CANDRABINDU TWO + +0A8F6 +DEVANAGARI SIGN CANDRABINDU THREE + +0A8F7 +DEVANAGARI SIGN CANDRABINDU AVAGRAHA + +0A8F8 +DEVANAGARI SIGN PUSHPIKA + +0A8F9 +DEVANAGARI GAP FILLER + +0A8FA +DEVANAGARI CARET + +0A8FB +DEVANAGARI HEADSTROKE + +0A8FC +DEVANAGARI SIGN SIDDHAM + +0A8FD +DEVANAGARI JAIN OM + +0A8FE +DEVANAGARI LETTER AY + +0A8FF +DEVANAGARI VOWEL SIGN AY + +0A900 +KAYAH LI DIGIT ZERO + +0A901 +KAYAH LI DIGIT ONE + +0A902 +KAYAH LI DIGIT TWO + +0A903 +KAYAH LI DIGIT THREE + +0A904 +KAYAH LI DIGIT FOUR + +0A905 +KAYAH LI DIGIT FIVE + +0A906 +KAYAH LI DIGIT SIX + +0A907 +KAYAH LI DIGIT SEVEN + +0A908 +KAYAH LI DIGIT EIGHT + +0A909 +KAYAH LI DIGIT NINE + +0A90A +KAYAH LI LETTER KA + +0A90B +KAYAH LI LETTER KHA + +0A90C +KAYAH LI LETTER GA + +0A90D +KAYAH LI LETTER NGA + +0A90E +KAYAH LI LETTER SA + +0A90F +KAYAH LI LETTER SHA + +0A910 +KAYAH LI LETTER ZA + +0A911 +KAYAH LI LETTER NYA + +0A912 +KAYAH LI LETTER TA + +0A913 +KAYAH LI LETTER HTA + +0A914 +KAYAH LI LETTER NA + +0A915 +KAYAH LI LETTER PA + +0A916 +KAYAH LI LETTER PHA + +0A917 +KAYAH LI LETTER MA + +0A918 +KAYAH LI LETTER DA + +0A919 +KAYAH LI LETTER BA + +0A91A +KAYAH LI LETTER RA + +0A91B +KAYAH LI LETTER YA + +0A91C +KAYAH LI LETTER LA + +0A91D +KAYAH LI LETTER WA + +0A91E +KAYAH LI LETTER THA + +0A91F +KAYAH LI LETTER HA + +0A920 +KAYAH LI LETTER VA + +0A921 +KAYAH LI LETTER CA + +0A922 +KAYAH LI LETTER A + +0A923 +KAYAH LI LETTER OE + +0A924 +KAYAH LI LETTER I + +0A925 +KAYAH LI LETTER OO + +0A926 +KAYAH LI VOWEL UE + +0A927 +KAYAH LI VOWEL E + +0A928 +KAYAH LI VOWEL U + +0A929 +KAYAH LI VOWEL EE + +0A92A +KAYAH LI VOWEL O + +0A92B +KAYAH LI TONE PLOPHU + +0A92C +KAYAH LI TONE CALYA + +0A92D +KAYAH LI TONE CALYA PLOPHU + +0A92E +KAYAH LI SIGN CWI + +0A92F +KAYAH LI SIGN SHYA + +0A930 +REJANG LETTER KA + +0A931 +REJANG LETTER GA + +0A932 +REJANG LETTER NGA + +0A933 +REJANG LETTER TA + +0A934 +REJANG LETTER DA + +0A935 +REJANG LETTER NA + +0A936 +REJANG LETTER PA + +0A937 +REJANG LETTER BA + +0A938 +REJANG LETTER MA + +0A939 +REJANG LETTER CA + +0A93A +REJANG LETTER JA + +0A93B +REJANG LETTER NYA + +0A93C +REJANG LETTER SA + +0A93D +REJANG LETTER RA + +0A93E +REJANG LETTER LA + +0A93F +REJANG LETTER YA + +0A940 +REJANG LETTER WA + +0A941 +REJANG LETTER HA + +0A942 +REJANG LETTER MBA + +0A943 +REJANG LETTER NGGA + +0A944 +REJANG LETTER NDA + +0A945 +REJANG LETTER NYJA + +0A946 +REJANG LETTER A + +0A947 +REJANG VOWEL SIGN I + +0A948 +REJANG VOWEL SIGN U + +0A949 +REJANG VOWEL SIGN E + +0A94A +REJANG VOWEL SIGN AI + +0A94B +REJANG VOWEL SIGN O + +0A94C +REJANG VOWEL SIGN AU + +0A94D +REJANG VOWEL SIGN EU + +0A94E +REJANG VOWEL SIGN EA + +0A94F +REJANG CONSONANT SIGN NG + +0A950 +REJANG CONSONANT SIGN N + +0A951 +REJANG CONSONANT SIGN R + +0A952 +REJANG CONSONANT SIGN H + +0A953 +REJANG VIRAMA + +0A95F +REJANG SECTION MARK + +0A960 +HANGUL CHOSEONG TIKEUT-MIEUM + +0A961 +HANGUL CHOSEONG TIKEUT-PIEUP + +0A962 +HANGUL CHOSEONG TIKEUT-SIOS + +0A963 +HANGUL CHOSEONG TIKEUT-CIEUC + +0A964 +HANGUL CHOSEONG RIEUL-KIYEOK + +0A965 +HANGUL CHOSEONG RIEUL-SSANGKIYEOK + +0A966 +HANGUL CHOSEONG RIEUL-TIKEUT + +0A967 +HANGUL CHOSEONG RIEUL-SSANGTIKEUT + +0A968 +HANGUL CHOSEONG RIEUL-MIEUM + +0A969 +HANGUL CHOSEONG RIEUL-PIEUP + +0A96A +HANGUL CHOSEONG RIEUL-SSANGPIEUP + +0A96B +HANGUL CHOSEONG RIEUL-KAPYEOUNPIEUP + +0A96C +HANGUL CHOSEONG RIEUL-SIOS + +0A96D +HANGUL CHOSEONG RIEUL-CIEUC + +0A96E +HANGUL CHOSEONG RIEUL-KHIEUKH + +0A96F +HANGUL CHOSEONG MIEUM-KIYEOK + +0A970 +HANGUL CHOSEONG MIEUM-TIKEUT + +0A971 +HANGUL CHOSEONG MIEUM-SIOS + +0A972 +HANGUL CHOSEONG PIEUP-SIOS-THIEUTH + +0A973 +HANGUL CHOSEONG PIEUP-KHIEUKH + +0A974 +HANGUL CHOSEONG PIEUP-HIEUH + +0A975 +HANGUL CHOSEONG SSANGSIOS-PIEUP + +0A976 +HANGUL CHOSEONG IEUNG-RIEUL + +0A977 +HANGUL CHOSEONG IEUNG-HIEUH + +0A978 +HANGUL CHOSEONG SSANGCIEUC-HIEUH + +0A979 +HANGUL CHOSEONG SSANGTHIEUTH + +0A97A +HANGUL CHOSEONG PHIEUPH-HIEUH + +0A97B +HANGUL CHOSEONG HIEUH-SIOS + +0A97C +HANGUL CHOSEONG SSANGYEORINHIEUH + +0A980 +JAVANESE SIGN PANYANGGA + +0A981 +JAVANESE SIGN CECAK + +0A982 +JAVANESE SIGN LAYAR + +0A983 +JAVANESE SIGN WIGNYAN + +0A984 +JAVANESE LETTER A + +0A985 +JAVANESE LETTER I KAWI + +0A986 +JAVANESE LETTER I + +0A987 +JAVANESE LETTER II + +0A988 +JAVANESE LETTER U + +0A989 +JAVANESE LETTER PA CEREK + +0A98A +JAVANESE LETTER NGA LELET + +0A98B +JAVANESE LETTER NGA LELET RASWADI + +0A98C +JAVANESE LETTER E + +0A98D +JAVANESE LETTER AI + +0A98E +JAVANESE LETTER O + +0A98F +JAVANESE LETTER KA + +0A990 +JAVANESE LETTER KA SASAK + +0A991 +JAVANESE LETTER KA MURDA + +0A992 +JAVANESE LETTER GA + +0A993 +JAVANESE LETTER GA MURDA + +0A994 +JAVANESE LETTER NGA + +0A995 +JAVANESE LETTER CA + +0A996 +JAVANESE LETTER CA MURDA + +0A997 +JAVANESE LETTER JA + +0A998 +JAVANESE LETTER NYA MURDA + +0A999 +JAVANESE LETTER JA MAHAPRANA + +0A99A +JAVANESE LETTER NYA + +0A99B +JAVANESE LETTER TTA + +0A99C +JAVANESE LETTER TTA MAHAPRANA + +0A99D +JAVANESE LETTER DDA + +0A99E +JAVANESE LETTER DDA MAHAPRANA + +0A99F +JAVANESE LETTER NA MURDA + +0A9A0 +JAVANESE LETTER TA + +0A9A1 +JAVANESE LETTER TA MURDA + +0A9A2 +JAVANESE LETTER DA + +0A9A3 +JAVANESE LETTER DA MAHAPRANA + +0A9A4 +JAVANESE LETTER NA + +0A9A5 +JAVANESE LETTER PA + +0A9A6 +JAVANESE LETTER PA MURDA + +0A9A7 +JAVANESE LETTER BA + +0A9A8 +JAVANESE LETTER BA MURDA + +0A9A9 +JAVANESE LETTER MA + +0A9AA +JAVANESE LETTER YA + +0A9AB +JAVANESE LETTER RA + +0A9AC +JAVANESE LETTER RA AGUNG + +0A9AD +JAVANESE LETTER LA + +0A9AE +JAVANESE LETTER WA + +0A9AF +JAVANESE LETTER SA MURDA + +0A9B0 +JAVANESE LETTER SA MAHAPRANA + +0A9B1 +JAVANESE LETTER SA + +0A9B2 +JAVANESE LETTER HA + +0A9B3 +JAVANESE SIGN CECAK TELU + +0A9B4 +JAVANESE VOWEL SIGN TARUNG + +0A9B5 +JAVANESE VOWEL SIGN TOLONG + +0A9B6 +JAVANESE VOWEL SIGN WULU + +0A9B7 +JAVANESE VOWEL SIGN WULU MELIK + +0A9B8 +JAVANESE VOWEL SIGN SUKU + +0A9B9 +JAVANESE VOWEL SIGN SUKU MENDUT + +0A9BA +JAVANESE VOWEL SIGN TALING + +0A9BB +JAVANESE VOWEL SIGN DIRGA MURE + +0A9BC +JAVANESE VOWEL SIGN PEPET + +0A9BD +JAVANESE CONSONANT SIGN KERET + +0A9BE +JAVANESE CONSONANT SIGN PENGKAL + +0A9BF +JAVANESE CONSONANT SIGN CAKRA + +0A9C0 +JAVANESE PANGKON + +0A9C1 +JAVANESE LEFT RERENGGAN + +0A9C2 +JAVANESE RIGHT RERENGGAN + +0A9C3 +JAVANESE PADA ANDAP + +0A9C4 +JAVANESE PADA MADYA + +0A9C5 +JAVANESE PADA LUHUR + +0A9C6 +JAVANESE PADA WINDU + +0A9C7 +JAVANESE PADA PANGKAT + +0A9C8 +JAVANESE PADA LINGSA + +0A9C9 +JAVANESE PADA LUNGSI + +0A9CA +JAVANESE PADA ADEG + +0A9CB +JAVANESE PADA ADEG ADEG + +0A9CC +JAVANESE PADA PISELEH + +0A9CD +JAVANESE TURNED PADA PISELEH + +0A9CF +JAVANESE PANGRANGKEP + +0A9D0 +JAVANESE DIGIT ZERO + +0A9D1 +JAVANESE DIGIT ONE + +0A9D2 +JAVANESE DIGIT TWO + +0A9D3 +JAVANESE DIGIT THREE + +0A9D4 +JAVANESE DIGIT FOUR + +0A9D5 +JAVANESE DIGIT FIVE + +0A9D6 +JAVANESE DIGIT SIX + +0A9D7 +JAVANESE DIGIT SEVEN + +0A9D8 +JAVANESE DIGIT EIGHT + +0A9D9 +JAVANESE DIGIT NINE + +0A9DE +JAVANESE PADA TIRTA TUMETES + +0A9DF +JAVANESE PADA ISEN-ISEN + +0A9E0 +MYANMAR LETTER SHAN GHA + +0A9E1 +MYANMAR LETTER SHAN CHA + +0A9E2 +MYANMAR LETTER SHAN JHA + +0A9E3 +MYANMAR LETTER SHAN NNA + +0A9E4 +MYANMAR LETTER SHAN BHA + +0A9E5 +MYANMAR SIGN SHAN SAW + +0A9E6 +MYANMAR MODIFIER LETTER SHAN REDUPLICATION + +0A9E7 +MYANMAR LETTER TAI LAING NYA + +0A9E8 +MYANMAR LETTER TAI LAING FA + +0A9E9 +MYANMAR LETTER TAI LAING GA + +0A9EA +MYANMAR LETTER TAI LAING GHA + +0A9EB +MYANMAR LETTER TAI LAING JA + +0A9EC +MYANMAR LETTER TAI LAING JHA + +0A9ED +MYANMAR LETTER TAI LAING DDA + +0A9EE +MYANMAR LETTER TAI LAING DDHA + +0A9EF +MYANMAR LETTER TAI LAING NNA + +0A9F0 +MYANMAR TAI LAING DIGIT ZERO + +0A9F1 +MYANMAR TAI LAING DIGIT ONE + +0A9F2 +MYANMAR TAI LAING DIGIT TWO + +0A9F3 +MYANMAR TAI LAING DIGIT THREE + +0A9F4 +MYANMAR TAI LAING DIGIT FOUR + +0A9F5 +MYANMAR TAI LAING DIGIT FIVE + +0A9F6 +MYANMAR TAI LAING DIGIT SIX + +0A9F7 +MYANMAR TAI LAING DIGIT SEVEN + +0A9F8 +MYANMAR TAI LAING DIGIT EIGHT + +0A9F9 +MYANMAR TAI LAING DIGIT NINE + +0A9FA +MYANMAR LETTER TAI LAING LLA + +0A9FB +MYANMAR LETTER TAI LAING DA + +0A9FC +MYANMAR LETTER TAI LAING DHA + +0A9FD +MYANMAR LETTER TAI LAING BA + +0A9FE +MYANMAR LETTER TAI LAING BHA + +0AA00 +CHAM LETTER A + +0AA01 +CHAM LETTER I + +0AA02 +CHAM LETTER U + +0AA03 +CHAM LETTER E + +0AA04 +CHAM LETTER AI + +0AA05 +CHAM LETTER O + +0AA06 +CHAM LETTER KA + +0AA07 +CHAM LETTER KHA + +0AA08 +CHAM LETTER GA + +0AA09 +CHAM LETTER GHA + +0AA0A +CHAM LETTER NGUE + +0AA0B +CHAM LETTER NGA + +0AA0C +CHAM LETTER CHA + +0AA0D +CHAM LETTER CHHA + +0AA0E +CHAM LETTER JA + +0AA0F +CHAM LETTER JHA + +0AA10 +CHAM LETTER NHUE + +0AA11 +CHAM LETTER NHA + +0AA12 +CHAM LETTER NHJA + +0AA13 +CHAM LETTER TA + +0AA14 +CHAM LETTER THA + +0AA15 +CHAM LETTER DA + +0AA16 +CHAM LETTER DHA + +0AA17 +CHAM LETTER NUE + +0AA18 +CHAM LETTER NA + +0AA19 +CHAM LETTER DDA + +0AA1A +CHAM LETTER PA + +0AA1B +CHAM LETTER PPA + +0AA1C +CHAM LETTER PHA + +0AA1D +CHAM LETTER BA + +0AA1E +CHAM LETTER BHA + +0AA1F +CHAM LETTER MUE + +0AA20 +CHAM LETTER MA + +0AA21 +CHAM LETTER BBA + +0AA22 +CHAM LETTER YA + +0AA23 +CHAM LETTER RA + +0AA24 +CHAM LETTER LA + +0AA25 +CHAM LETTER VA + +0AA26 +CHAM LETTER SSA + +0AA27 +CHAM LETTER SA + +0AA28 +CHAM LETTER HA + +0AA29 +CHAM VOWEL SIGN AA + +0AA2A +CHAM VOWEL SIGN I + +0AA2B +CHAM VOWEL SIGN II + +0AA2C +CHAM VOWEL SIGN EI + +0AA2D +CHAM VOWEL SIGN U + +0AA2E +CHAM VOWEL SIGN OE + +0AA2F +CHAM VOWEL SIGN O + +0AA30 +CHAM VOWEL SIGN AI + +0AA31 +CHAM VOWEL SIGN AU + +0AA32 +CHAM VOWEL SIGN UE + +0AA33 +CHAM CONSONANT SIGN YA + +0AA34 +CHAM CONSONANT SIGN RA + +0AA35 +CHAM CONSONANT SIGN LA + +0AA36 +CHAM CONSONANT SIGN WA + +0AA40 +CHAM LETTER FINAL K + +0AA41 +CHAM LETTER FINAL G + +0AA42 +CHAM LETTER FINAL NG + +0AA43 +CHAM CONSONANT SIGN FINAL NG + +0AA44 +CHAM LETTER FINAL CH + +0AA45 +CHAM LETTER FINAL T + +0AA46 +CHAM LETTER FINAL N + +0AA47 +CHAM LETTER FINAL P + +0AA48 +CHAM LETTER FINAL Y + +0AA49 +CHAM LETTER FINAL R + +0AA4A +CHAM LETTER FINAL L + +0AA4B +CHAM LETTER FINAL SS + +0AA4C +CHAM CONSONANT SIGN FINAL M + +0AA4D +CHAM CONSONANT SIGN FINAL H + +0AA50 +CHAM DIGIT ZERO + +0AA51 +CHAM DIGIT ONE + +0AA52 +CHAM DIGIT TWO + +0AA53 +CHAM DIGIT THREE + +0AA54 +CHAM DIGIT FOUR + +0AA55 +CHAM DIGIT FIVE + +0AA56 +CHAM DIGIT SIX + +0AA57 +CHAM DIGIT SEVEN + +0AA58 +CHAM DIGIT EIGHT + +0AA59 +CHAM DIGIT NINE + +0AA5C +CHAM PUNCTUATION SPIRAL + +0AA5D +CHAM PUNCTUATION DANDA + +0AA5E +CHAM PUNCTUATION DOUBLE DANDA + +0AA5F +CHAM PUNCTUATION TRIPLE DANDA + +0AA60 +MYANMAR LETTER KHAMTI GA + +0AA61 +MYANMAR LETTER KHAMTI CA + +0AA62 +MYANMAR LETTER KHAMTI CHA + +0AA63 +MYANMAR LETTER KHAMTI JA + +0AA64 +MYANMAR LETTER KHAMTI JHA + +0AA65 +MYANMAR LETTER KHAMTI NYA + +0AA66 +MYANMAR LETTER KHAMTI TTA + +0AA67 +MYANMAR LETTER KHAMTI TTHA + +0AA68 +MYANMAR LETTER KHAMTI DDA + +0AA69 +MYANMAR LETTER KHAMTI DDHA + +0AA6A +MYANMAR LETTER KHAMTI DHA + +0AA6B +MYANMAR LETTER KHAMTI NA + +0AA6C +MYANMAR LETTER KHAMTI SA + +0AA6D +MYANMAR LETTER KHAMTI HA + +0AA6E +MYANMAR LETTER KHAMTI LLA + +0AA6E +MYANMAR LETTER KHAMTI HHA + +0AA6F +MYANMAR LETTER KHAMTI FA + +0AA70 +MYANMAR MODIFIER LETTER KHAMTI REDUPLICATION + +0AA71 +MYANMAR LETTER KHAMTI XA + +0AA72 +MYANMAR LETTER KHAMTI ZA + +0AA73 +MYANMAR LETTER KHAMTI RA + +0AA74 +MYANMAR LOGOGRAM KHAMTI OAY + +0AA75 +MYANMAR LOGOGRAM KHAMTI QN + +0AA76 +MYANMAR LOGOGRAM KHAMTI HM + +0AA77 +MYANMAR SYMBOL AITON EXCLAMATION + +0AA78 +MYANMAR SYMBOL AITON ONE + +0AA79 +MYANMAR SYMBOL AITON TWO + +0AA7A +MYANMAR LETTER AITON RA + +0AA7B +MYANMAR SIGN PAO KAREN TONE + +0AA7C +MYANMAR SIGN TAI LAING TONE-2 + +0AA7D +MYANMAR SIGN TAI LAING TONE-5 + +0AA7E +MYANMAR LETTER SHWE PALAUNG CHA + +0AA7F +MYANMAR LETTER SHWE PALAUNG SHA + +0AA80 +TAI VIET LETTER LOW KO + +0AA81 +TAI VIET LETTER HIGH KO + +0AA82 +TAI VIET LETTER LOW KHO + +0AA83 +TAI VIET LETTER HIGH KHO + +0AA84 +TAI VIET LETTER LOW KHHO + +0AA85 +TAI VIET LETTER HIGH KHHO + +0AA86 +TAI VIET LETTER LOW GO + +0AA87 +TAI VIET LETTER HIGH GO + +0AA88 +TAI VIET LETTER LOW NGO + +0AA89 +TAI VIET LETTER HIGH NGO + +0AA8A +TAI VIET LETTER LOW CO + +0AA8B +TAI VIET LETTER HIGH CO + +0AA8C +TAI VIET LETTER LOW CHO + +0AA8D +TAI VIET LETTER HIGH CHO + +0AA8E +TAI VIET LETTER LOW SO + +0AA8F +TAI VIET LETTER HIGH SO + +0AA90 +TAI VIET LETTER LOW NYO + +0AA91 +TAI VIET LETTER HIGH NYO + +0AA92 +TAI VIET LETTER LOW DO + +0AA93 +TAI VIET LETTER HIGH DO + +0AA94 +TAI VIET LETTER LOW TO + +0AA95 +TAI VIET LETTER HIGH TO + +0AA96 +TAI VIET LETTER LOW THO + +0AA97 +TAI VIET LETTER HIGH THO + +0AA98 +TAI VIET LETTER LOW NO + +0AA99 +TAI VIET LETTER HIGH NO + +0AA9A +TAI VIET LETTER LOW BO + +0AA9B +TAI VIET LETTER HIGH BO + +0AA9C +TAI VIET LETTER LOW PO + +0AA9D +TAI VIET LETTER HIGH PO + +0AA9E +TAI VIET LETTER LOW PHO + +0AA9F +TAI VIET LETTER HIGH PHO + +0AAA0 +TAI VIET LETTER LOW FO + +0AAA1 +TAI VIET LETTER HIGH FO + +0AAA2 +TAI VIET LETTER LOW MO + +0AAA3 +TAI VIET LETTER HIGH MO + +0AAA4 +TAI VIET LETTER LOW YO + +0AAA5 +TAI VIET LETTER HIGH YO + +0AAA6 +TAI VIET LETTER LOW RO + +0AAA7 +TAI VIET LETTER HIGH RO + +0AAA8 +TAI VIET LETTER LOW LO + +0AAA9 +TAI VIET LETTER HIGH LO + +0AAAA +TAI VIET LETTER LOW VO + +0AAAB +TAI VIET LETTER HIGH VO + +0AAAC +TAI VIET LETTER LOW HO + +0AAAD +TAI VIET LETTER HIGH HO + +0AAAE +TAI VIET LETTER LOW O + +0AAAF +TAI VIET LETTER HIGH O + +0AAB0 +TAI VIET MAI KANG + +0AAB1 +TAI VIET VOWEL AA + +0AAB2 +TAI VIET VOWEL I + +0AAB3 +TAI VIET VOWEL UE + +0AAB4 +TAI VIET VOWEL U + +0AAB5 +TAI VIET VOWEL E + +0AAB6 +TAI VIET VOWEL O + +0AAB7 +TAI VIET MAI KHIT + +0AAB8 +TAI VIET VOWEL IA + +0AAB9 +TAI VIET VOWEL UEA + +0AABA +TAI VIET VOWEL UA + +0AABB +TAI VIET VOWEL AUE + +0AABC +TAI VIET VOWEL AY + +0AABD +TAI VIET VOWEL AN + +0AABE +TAI VIET VOWEL AM + +0AABF +TAI VIET TONE MAI EK + +0AAC0 +TAI VIET TONE MAI NUENG + +0AAC1 +TAI VIET TONE MAI THO + +0AAC2 +TAI VIET TONE MAI SONG + +0AADB +TAI VIET SYMBOL KON + +0AADC +TAI VIET SYMBOL NUENG + +0AADD +TAI VIET SYMBOL SAM + +0AADE +TAI VIET SYMBOL HO HOI + +0AADF +TAI VIET SYMBOL KOI KOI + +0AAE0 +MEETEI MAYEK LETTER E + +0AAE1 +MEETEI MAYEK LETTER O + +0AAE2 +MEETEI MAYEK LETTER CHA + +0AAE3 +MEETEI MAYEK LETTER NYA + +0AAE4 +MEETEI MAYEK LETTER TTA + +0AAE5 +MEETEI MAYEK LETTER TTHA + +0AAE6 +MEETEI MAYEK LETTER DDA + +0AAE7 +MEETEI MAYEK LETTER DDHA + +0AAE8 +MEETEI MAYEK LETTER NNA + +0AAE9 +MEETEI MAYEK LETTER SHA + +0AAEA +MEETEI MAYEK LETTER SSA + +0AAEB +MEETEI MAYEK VOWEL SIGN II + +0AAEC +MEETEI MAYEK VOWEL SIGN UU + +0AAED +MEETEI MAYEK VOWEL SIGN AAI + +0AAEE +MEETEI MAYEK VOWEL SIGN AU + +0AAEF +MEETEI MAYEK VOWEL SIGN AAU + +0AAF0 +MEETEI MAYEK CHEIKHAN + +0AAF1 +MEETEI MAYEK AHANG KHUDAM + +0AAF2 +MEETEI MAYEK ANJI + +0AAF3 +MEETEI MAYEK SYLLABLE REPETITION MARK + +0AAF4 +MEETEI MAYEK WORD REPETITION MARK + +0AAF5 +MEETEI MAYEK VOWEL SIGN VISARGA + +0AAF6 +MEETEI MAYEK VIRAMA + +0AB01 +ETHIOPIC SYLLABLE TTHU + +0AB02 +ETHIOPIC SYLLABLE TTHI + +0AB03 +ETHIOPIC SYLLABLE TTHAA + +0AB04 +ETHIOPIC SYLLABLE TTHEE + +0AB05 +ETHIOPIC SYLLABLE TTHE + +0AB06 +ETHIOPIC SYLLABLE TTHO + +0AB09 +ETHIOPIC SYLLABLE DDHU + +0AB0A +ETHIOPIC SYLLABLE DDHI + +0AB0B +ETHIOPIC SYLLABLE DDHAA + +0AB0C +ETHIOPIC SYLLABLE DDHEE + +0AB0D +ETHIOPIC SYLLABLE DDHE + +0AB0E +ETHIOPIC SYLLABLE DDHO + +0AB11 +ETHIOPIC SYLLABLE DZU + +0AB12 +ETHIOPIC SYLLABLE DZI + +0AB13 +ETHIOPIC SYLLABLE DZAA + +0AB14 +ETHIOPIC SYLLABLE DZEE + +0AB15 +ETHIOPIC SYLLABLE DZE + +0AB16 +ETHIOPIC SYLLABLE DZO + +0AB20 +ETHIOPIC SYLLABLE CCHHA + +0AB21 +ETHIOPIC SYLLABLE CCHHU + +0AB22 +ETHIOPIC SYLLABLE CCHHI + +0AB23 +ETHIOPIC SYLLABLE CCHHAA + +0AB24 +ETHIOPIC SYLLABLE CCHHEE + +0AB25 +ETHIOPIC SYLLABLE CCHHE + +0AB26 +ETHIOPIC SYLLABLE CCHHO + +0AB28 +ETHIOPIC SYLLABLE BBA + +0AB29 +ETHIOPIC SYLLABLE BBU + +0AB2A +ETHIOPIC SYLLABLE BBI + +0AB2B +ETHIOPIC SYLLABLE BBAA + +0AB2C +ETHIOPIC SYLLABLE BBEE + +0AB2D +ETHIOPIC SYLLABLE BBE + +0AB2E +ETHIOPIC SYLLABLE BBO + +0AB30 +LATIN SMALL LETTER BARRED ALPHA + +0AB31 +LATIN SMALL LETTER A REVERSED-SCHWA + +0AB32 +LATIN SMALL LETTER BLACKLETTER E + +0AB33 +LATIN SMALL LETTER BARRED E + +0AB34 +LATIN SMALL LETTER E WITH FLOURISH + +0AB35 +LATIN SMALL LETTER LENIS F + +0AB36 +LATIN SMALL LETTER SCRIPT G WITH CROSSED-TAIL + +0AB37 +LATIN SMALL LETTER L WITH INVERTED LAZY S + +0AB38 +LATIN SMALL LETTER L WITH DOUBLE MIDDLE TILDE + +0AB39 +LATIN SMALL LETTER L WITH MIDDLE RING + +0AB3A +LATIN SMALL LETTER M WITH CROSSED-TAIL + +0AB3B +LATIN SMALL LETTER N WITH CROSSED-TAIL + +0AB3C +LATIN SMALL LETTER ENG WITH CROSSED-TAIL + +0AB3D +LATIN SMALL LETTER BLACKLETTER O + +0AB3E +LATIN SMALL LETTER BLACKLETTER O WITH STROKE + +0AB3F +LATIN SMALL LETTER OPEN O WITH STROKE + +0AB40 +LATIN SMALL LETTER INVERTED OE + +0AB41 +LATIN SMALL LETTER TURNED OE WITH STROKE + +0AB42 +LATIN SMALL LETTER TURNED OE WITH HORIZONTAL STROKE + +0AB43 +LATIN SMALL LETTER TURNED O OPEN-O + +0AB44 +LATIN SMALL LETTER TURNED O OPEN-O WITH STROKE + +0AB45 +LATIN SMALL LETTER STIRRUP R + +0AB46 +LATIN LETTER SMALL CAPITAL R WITH RIGHT LEG + +0AB47 +LATIN SMALL LETTER R WITHOUT HANDLE + +0AB48 +LATIN SMALL LETTER DOUBLE R + +0AB49 +LATIN SMALL LETTER R WITH CROSSED-TAIL + +0AB4A +LATIN SMALL LETTER DOUBLE R WITH CROSSED-TAIL + +0AB4B +LATIN SMALL LETTER SCRIPT R + +0AB4C +LATIN SMALL LETTER SCRIPT R WITH RING + +0AB4D +LATIN SMALL LETTER BASELINE ESH + +0AB4E +LATIN SMALL LETTER U WITH SHORT RIGHT LEG + +0AB4F +LATIN SMALL LETTER U BAR WITH SHORT RIGHT LEG + +0AB50 +LATIN SMALL LETTER UI + +0AB51 +LATIN SMALL LETTER TURNED UI + +0AB52 +LATIN SMALL LETTER U WITH LEFT HOOK + +0AB53 +LATIN SMALL LETTER CHI + +0AB54 +LATIN SMALL LETTER CHI WITH LOW RIGHT RING + +0AB55 +LATIN SMALL LETTER CHI WITH LOW LEFT SERIF + +0AB56 +LATIN SMALL LETTER X WITH LOW RIGHT RING + +0AB57 +LATIN SMALL LETTER X WITH LONG LEFT LEG + +0AB58 +LATIN SMALL LETTER X WITH LONG LEFT LEG AND LOW RIGHT RING + +0AB59 +LATIN SMALL LETTER X WITH LONG LEFT LEG WITH SERIF + +0AB5A +LATIN SMALL LETTER Y WITH SHORT RIGHT LEG + +0AB5B +MODIFIER BREVE WITH INVERTED BREVE + +0AB5C +MODIFIER LETTER SMALL HENG + +0AB5D +MODIFIER LETTER SMALL L WITH INVERTED LAZY S + +0AB5E +MODIFIER LETTER SMALL L WITH MIDDLE TILDE + +0AB5F +MODIFIER LETTER SMALL U WITH LEFT HOOK + +0AB60 +LATIN SMALL LETTER SAKHA YAT + +0AB61 +LATIN SMALL LETTER IOTIFIED E + +0AB62 +LATIN SMALL LETTER OPEN OE + +0AB63 +LATIN SMALL LETTER UO + +0AB64 +LATIN SMALL LETTER INVERTED ALPHA + +0AB65 +GREEK LETTER SMALL CAPITAL OMEGA + +0AB66 +LATIN SMALL LETTER DZ DIGRAPH WITH RETROFLEX HOOK + +0AB67 +LATIN SMALL LETTER TS DIGRAPH WITH RETROFLEX HOOK + +0AB68 +LATIN SMALL LETTER TURNED R WITH MIDDLE TILDE + +0AB69 +MODIFIER LETTER SMALL TURNED W + +0AB6A +MODIFIER LETTER LEFT TACK + +0AB6B +MODIFIER LETTER RIGHT TACK + +0AB70 +CHEROKEE SMALL LETTER A + +0AB71 +CHEROKEE SMALL LETTER E + +0AB72 +CHEROKEE SMALL LETTER I + +0AB73 +CHEROKEE SMALL LETTER O + +0AB74 +CHEROKEE SMALL LETTER U + +0AB75 +CHEROKEE SMALL LETTER V + +0AB76 +CHEROKEE SMALL LETTER GA + +0AB77 +CHEROKEE SMALL LETTER KA + +0AB78 +CHEROKEE SMALL LETTER GE + +0AB79 +CHEROKEE SMALL LETTER GI + +0AB7A +CHEROKEE SMALL LETTER GO + +0AB7B +CHEROKEE SMALL LETTER GU + +0AB7C +CHEROKEE SMALL LETTER GV + +0AB7D +CHEROKEE SMALL LETTER HA + +0AB7E +CHEROKEE SMALL LETTER HE + +0AB7F +CHEROKEE SMALL LETTER HI + +0AB80 +CHEROKEE SMALL LETTER HO + +0AB81 +CHEROKEE SMALL LETTER HU + +0AB82 +CHEROKEE SMALL LETTER HV + +0AB83 +CHEROKEE SMALL LETTER LA + +0AB84 +CHEROKEE SMALL LETTER LE + +0AB85 +CHEROKEE SMALL LETTER LI + +0AB86 +CHEROKEE SMALL LETTER LO + +0AB87 +CHEROKEE SMALL LETTER LU + +0AB88 +CHEROKEE SMALL LETTER LV + +0AB89 +CHEROKEE SMALL LETTER MA + +0AB8A +CHEROKEE SMALL LETTER ME + +0AB8B +CHEROKEE SMALL LETTER MI + +0AB8C +CHEROKEE SMALL LETTER MO + +0AB8D +CHEROKEE SMALL LETTER MU + +0AB8E +CHEROKEE SMALL LETTER NA + +0AB8F +CHEROKEE SMALL LETTER HNA + +0AB90 +CHEROKEE SMALL LETTER NAH + +0AB91 +CHEROKEE SMALL LETTER NE + +0AB92 +CHEROKEE SMALL LETTER NI + +0AB93 +CHEROKEE SMALL LETTER NO + +0AB94 +CHEROKEE SMALL LETTER NU + +0AB95 +CHEROKEE SMALL LETTER NV + +0AB96 +CHEROKEE SMALL LETTER QUA + +0AB97 +CHEROKEE SMALL LETTER QUE + +0AB98 +CHEROKEE SMALL LETTER QUI + +0AB99 +CHEROKEE SMALL LETTER QUO + +0AB9A +CHEROKEE SMALL LETTER QUU + +0AB9B +CHEROKEE SMALL LETTER QUV + +0AB9C +CHEROKEE SMALL LETTER SA + +0AB9D +CHEROKEE SMALL LETTER S + +0AB9E +CHEROKEE SMALL LETTER SE + +0AB9F +CHEROKEE SMALL LETTER SI + +0ABA0 +CHEROKEE SMALL LETTER SO + +0ABA1 +CHEROKEE SMALL LETTER SU + +0ABA2 +CHEROKEE SMALL LETTER SV + +0ABA3 +CHEROKEE SMALL LETTER DA + +0ABA4 +CHEROKEE SMALL LETTER TA + +0ABA5 +CHEROKEE SMALL LETTER DE + +0ABA6 +CHEROKEE SMALL LETTER TE + +0ABA7 +CHEROKEE SMALL LETTER DI + +0ABA8 +CHEROKEE SMALL LETTER TI + +0ABA9 +CHEROKEE SMALL LETTER DO + +0ABAA +CHEROKEE SMALL LETTER DU + +0ABAB +CHEROKEE SMALL LETTER DV + +0ABAC +CHEROKEE SMALL LETTER DLA + +0ABAD +CHEROKEE SMALL LETTER TLA + +0ABAE +CHEROKEE SMALL LETTER TLE + +0ABAF +CHEROKEE SMALL LETTER TLI + +0ABB0 +CHEROKEE SMALL LETTER TLO + +0ABB1 +CHEROKEE SMALL LETTER TLU + +0ABB2 +CHEROKEE SMALL LETTER TLV + +0ABB3 +CHEROKEE SMALL LETTER TSA + +0ABB4 +CHEROKEE SMALL LETTER TSE + +0ABB5 +CHEROKEE SMALL LETTER TSI + +0ABB6 +CHEROKEE SMALL LETTER TSO + +0ABB7 +CHEROKEE SMALL LETTER TSU + +0ABB8 +CHEROKEE SMALL LETTER TSV + +0ABB9 +CHEROKEE SMALL LETTER WA + +0ABBA +CHEROKEE SMALL LETTER WE + +0ABBB +CHEROKEE SMALL LETTER WI + +0ABBC +CHEROKEE SMALL LETTER WO + +0ABBD +CHEROKEE SMALL LETTER WU + +0ABBE +CHEROKEE SMALL LETTER WV + +0ABBF +CHEROKEE SMALL LETTER YA + +0ABC0 +MEETEI MAYEK LETTER KOK + +0ABC1 +MEETEI MAYEK LETTER SAM + +0ABC2 +MEETEI MAYEK LETTER LAI + +0ABC3 +MEETEI MAYEK LETTER MIT + +0ABC4 +MEETEI MAYEK LETTER PA + +0ABC5 +MEETEI MAYEK LETTER NA + +0ABC6 +MEETEI MAYEK LETTER CHIL + +0ABC7 +MEETEI MAYEK LETTER TIL + +0ABC8 +MEETEI MAYEK LETTER KHOU + +0ABC9 +MEETEI MAYEK LETTER NGOU + +0ABCA +MEETEI MAYEK LETTER THOU + +0ABCB +MEETEI MAYEK LETTER WAI + +0ABCC +MEETEI MAYEK LETTER YANG + +0ABCD +MEETEI MAYEK LETTER HUK + +0ABCE +MEETEI MAYEK LETTER UN + +0ABCF +MEETEI MAYEK LETTER I + +0ABD0 +MEETEI MAYEK LETTER PHAM + +0ABD1 +MEETEI MAYEK LETTER ATIYA + +0ABD2 +MEETEI MAYEK LETTER GOK + +0ABD3 +MEETEI MAYEK LETTER JHAM + +0ABD4 +MEETEI MAYEK LETTER RAI + +0ABD5 +MEETEI MAYEK LETTER BA + +0ABD6 +MEETEI MAYEK LETTER JIL + +0ABD7 +MEETEI MAYEK LETTER DIL + +0ABD8 +MEETEI MAYEK LETTER GHOU + +0ABD9 +MEETEI MAYEK LETTER DHOU + +0ABDA +MEETEI MAYEK LETTER BHAM + +0ABDB +MEETEI MAYEK LETTER KOK LONSUM + +0ABDC +MEETEI MAYEK LETTER LAI LONSUM + +0ABDD +MEETEI MAYEK LETTER MIT LONSUM + +0ABDE +MEETEI MAYEK LETTER PA LONSUM + +0ABDF +MEETEI MAYEK LETTER NA LONSUM + +0ABE0 +MEETEI MAYEK LETTER TIL LONSUM + +0ABE1 +MEETEI MAYEK LETTER NGOU LONSUM + +0ABE2 +MEETEI MAYEK LETTER I LONSUM + +0ABE3 +MEETEI MAYEK VOWEL SIGN ONAP + +0ABE4 +MEETEI MAYEK VOWEL SIGN INAP + +0ABE5 +MEETEI MAYEK VOWEL SIGN ANAP + +0ABE6 +MEETEI MAYEK VOWEL SIGN YENAP + +0ABE7 +MEETEI MAYEK VOWEL SIGN SOUNAP + +0ABE8 +MEETEI MAYEK VOWEL SIGN UNAP + +0ABE9 +MEETEI MAYEK VOWEL SIGN CHEINAP + +0ABEA +MEETEI MAYEK VOWEL SIGN NUNG + +0ABEB +MEETEI MAYEK CHEIKHEI + +0ABEC +MEETEI MAYEK LUM IYEK + +0ABED +MEETEI MAYEK APUN IYEK + +0ABF0 +MEETEI MAYEK DIGIT ZERO + +0ABF1 +MEETEI MAYEK DIGIT ONE + +0ABF2 +MEETEI MAYEK DIGIT TWO + +0ABF3 +MEETEI MAYEK DIGIT THREE + +0ABF4 +MEETEI MAYEK DIGIT FOUR + +0ABF5 +MEETEI MAYEK DIGIT FIVE + +0ABF6 +MEETEI MAYEK DIGIT SIX + +0ABF7 +MEETEI MAYEK DIGIT SEVEN + +0ABF8 +MEETEI MAYEK DIGIT EIGHT + +0ABF9 +MEETEI MAYEK DIGIT NINE + +0D7B0 +HANGUL JUNGSEONG O-YEO + +0D7B1 +HANGUL JUNGSEONG O-O-I + +0D7B2 +HANGUL JUNGSEONG YO-A + +0D7B3 +HANGUL JUNGSEONG YO-AE + +0D7B4 +HANGUL JUNGSEONG YO-EO + +0D7B5 +HANGUL JUNGSEONG U-YEO + +0D7B6 +HANGUL JUNGSEONG U-I-I + +0D7B7 +HANGUL JUNGSEONG YU-AE + +0D7B8 +HANGUL JUNGSEONG YU-O + +0D7B9 +HANGUL JUNGSEONG EU-A + +0D7BA +HANGUL JUNGSEONG EU-EO + +0D7BB +HANGUL JUNGSEONG EU-E + +0D7BC +HANGUL JUNGSEONG EU-O + +0D7BD +HANGUL JUNGSEONG I-YA-O + +0D7BE +HANGUL JUNGSEONG I-YAE + +0D7BF +HANGUL JUNGSEONG I-YEO + +0D7C0 +HANGUL JUNGSEONG I-YE + +0D7C1 +HANGUL JUNGSEONG I-O-I + +0D7C2 +HANGUL JUNGSEONG I-YO + +0D7C3 +HANGUL JUNGSEONG I-YU + +0D7C4 +HANGUL JUNGSEONG I-I + +0D7C5 +HANGUL JUNGSEONG ARAEA-A + +0D7C6 +HANGUL JUNGSEONG ARAEA-E + +0D7CB +HANGUL JONGSEONG NIEUN-RIEUL + +0D7CC +HANGUL JONGSEONG NIEUN-CHIEUCH + +0D7CD +HANGUL JONGSEONG SSANGTIKEUT + +0D7CE +HANGUL JONGSEONG SSANGTIKEUT-PIEUP + +0D7CF +HANGUL JONGSEONG TIKEUT-PIEUP + +0D7D0 +HANGUL JONGSEONG TIKEUT-SIOS + +0D7D1 +HANGUL JONGSEONG TIKEUT-SIOS-KIYEOK + +0D7D2 +HANGUL JONGSEONG TIKEUT-CIEUC + +0D7D3 +HANGUL JONGSEONG TIKEUT-CHIEUCH + +0D7D4 +HANGUL JONGSEONG TIKEUT-THIEUTH + +0D7D5 +HANGUL JONGSEONG RIEUL-SSANGKIYEOK + +0D7D6 +HANGUL JONGSEONG RIEUL-KIYEOK-HIEUH + +0D7D7 +HANGUL JONGSEONG SSANGRIEUL-KHIEUKH + +0D7D8 +HANGUL JONGSEONG RIEUL-MIEUM-HIEUH + +0D7D9 +HANGUL JONGSEONG RIEUL-PIEUP-TIKEUT + +0D7DA +HANGUL JONGSEONG RIEUL-PIEUP-PHIEUPH + +0D7DB +HANGUL JONGSEONG RIEUL-YESIEUNG + +0D7DC +HANGUL JONGSEONG RIEUL-YEORINHIEUH-HIEUH + +0D7DD +HANGUL JONGSEONG KAPYEOUNRIEUL + +0D7DE +HANGUL JONGSEONG MIEUM-NIEUN + +0D7DF +HANGUL JONGSEONG MIEUM-SSANGNIEUN + +0D7E0 +HANGUL JONGSEONG SSANGMIEUM + +0D7E1 +HANGUL JONGSEONG MIEUM-PIEUP-SIOS + +0D7E2 +HANGUL JONGSEONG MIEUM-CIEUC + +0D7E3 +HANGUL JONGSEONG PIEUP-TIKEUT + +0D7E4 +HANGUL JONGSEONG PIEUP-RIEUL-PHIEUPH + +0D7E5 +HANGUL JONGSEONG PIEUP-MIEUM + +0D7E6 +HANGUL JONGSEONG SSANGPIEUP + +0D7E7 +HANGUL JONGSEONG PIEUP-SIOS-TIKEUT + +0D7E8 +HANGUL JONGSEONG PIEUP-CIEUC + +0D7E9 +HANGUL JONGSEONG PIEUP-CHIEUCH + +0D7EA +HANGUL JONGSEONG SIOS-MIEUM + +0D7EB +HANGUL JONGSEONG SIOS-KAPYEOUNPIEUP + +0D7EC +HANGUL JONGSEONG SSANGSIOS-KIYEOK + +0D7ED +HANGUL JONGSEONG SSANGSIOS-TIKEUT + +0D7EE +HANGUL JONGSEONG SIOS-PANSIOS + +0D7EF +HANGUL JONGSEONG SIOS-CIEUC + +0D7F0 +HANGUL JONGSEONG SIOS-CHIEUCH + +0D7F1 +HANGUL JONGSEONG SIOS-THIEUTH + +0D7F2 +HANGUL JONGSEONG SIOS-HIEUH + +0D7F3 +HANGUL JONGSEONG PANSIOS-PIEUP + +0D7F4 +HANGUL JONGSEONG PANSIOS-KAPYEOUNPIEUP + +0D7F5 +HANGUL JONGSEONG YESIEUNG-MIEUM + +0D7F6 +HANGUL JONGSEONG YESIEUNG-HIEUH + +0D7F7 +HANGUL JONGSEONG CIEUC-PIEUP + +0D7F8 +HANGUL JONGSEONG CIEUC-SSANGPIEUP + +0D7F9 +HANGUL JONGSEONG SSANGCIEUC + +0D7FA +HANGUL JONGSEONG PHIEUPH-SIOS + +0D7FB +HANGUL JONGSEONG PHIEUPH-THIEUTH + +0FB00 +LATIN SMALL LIGATURE FF + +0FB01 +LATIN SMALL LIGATURE FI + +0FB02 +LATIN SMALL LIGATURE FL + +0FB03 +LATIN SMALL LIGATURE FFI + +0FB04 +LATIN SMALL LIGATURE FFL + +0FB05 +LATIN SMALL LIGATURE LONG S T + +0FB06 +LATIN SMALL LIGATURE ST + +0FB13 +ARMENIAN SMALL LIGATURE MEN NOW + +0FB14 +ARMENIAN SMALL LIGATURE MEN ECH + +0FB15 +ARMENIAN SMALL LIGATURE MEN INI + +0FB16 +ARMENIAN SMALL LIGATURE VEW NOW + +0FB17 +ARMENIAN SMALL LIGATURE MEN XEH + +0FB1D +HEBREW LETTER YOD WITH HIRIQ + +0FB1E +HEBREW POINT JUDEO-SPANISH VARIKA + +0FB1F +HEBREW LIGATURE YIDDISH YOD YOD PATAH + +0FB20 +HEBREW LETTER ALTERNATIVE AYIN + +0FB21 +HEBREW LETTER WIDE ALEF + +0FB22 +HEBREW LETTER WIDE DALET + +0FB23 +HEBREW LETTER WIDE HE + +0FB24 +HEBREW LETTER WIDE KAF + +0FB25 +HEBREW LETTER WIDE LAMED + +0FB26 +HEBREW LETTER WIDE FINAL MEM + +0FB27 +HEBREW LETTER WIDE RESH + +0FB28 +HEBREW LETTER WIDE TAV + +0FB29 +HEBREW LETTER ALTERNATIVE PLUS SIGN + +0FB2A +HEBREW LETTER SHIN WITH SHIN DOT + +0FB2B +HEBREW LETTER SHIN WITH SIN DOT + +0FB2C +HEBREW LETTER SHIN WITH DAGESH AND SHIN DOT + +0FB2D +HEBREW LETTER SHIN WITH DAGESH AND SIN DOT + +0FB2E +HEBREW LETTER ALEF WITH PATAH + +0FB2F +HEBREW LETTER ALEF WITH QAMATS + +0FB30 +HEBREW LETTER ALEF WITH MAPIQ + +0FB31 +HEBREW LETTER BET WITH DAGESH + +0FB32 +HEBREW LETTER GIMEL WITH DAGESH + +0FB33 +HEBREW LETTER DALET WITH DAGESH + +0FB34 +HEBREW LETTER HE WITH MAPIQ + +0FB35 +HEBREW LETTER VAV WITH DAGESH + +0FB36 +HEBREW LETTER ZAYIN WITH DAGESH + +0FB38 +HEBREW LETTER TET WITH DAGESH + +0FB39 +HEBREW LETTER YOD WITH DAGESH + +0FB3A +HEBREW LETTER FINAL KAF WITH DAGESH + +0FB3B +HEBREW LETTER KAF WITH DAGESH + +0FB3C +HEBREW LETTER LAMED WITH DAGESH + +0FB3E +HEBREW LETTER MEM WITH DAGESH + +0FB40 +HEBREW LETTER NUN WITH DAGESH + +0FB41 +HEBREW LETTER SAMEKH WITH DAGESH + +0FB43 +HEBREW LETTER FINAL PE WITH DAGESH + +0FB44 +HEBREW LETTER PE WITH DAGESH + +0FB46 +HEBREW LETTER TSADI WITH DAGESH + +0FB47 +HEBREW LETTER QOF WITH DAGESH + +0FB48 +HEBREW LETTER RESH WITH DAGESH + +0FB49 +HEBREW LETTER SHIN WITH DAGESH + +0FB4A +HEBREW LETTER TAV WITH DAGESH + +0FB4B +HEBREW LETTER VAV WITH HOLAM + +0FB4C +HEBREW LETTER BET WITH RAFE + +0FB4D +HEBREW LETTER KAF WITH RAFE + +0FB4E +HEBREW LETTER PE WITH RAFE + +0FB4F +HEBREW LIGATURE ALEF LAMED + +0FB50 +ARABIC LETTER ALEF WASLA ISOLATED FORM + +0FB51 +ARABIC LETTER ALEF WASLA FINAL FORM + +0FB52 +ARABIC LETTER BEEH ISOLATED FORM + +0FB53 +ARABIC LETTER BEEH FINAL FORM + +0FB54 +ARABIC LETTER BEEH INITIAL FORM + +0FB55 +ARABIC LETTER BEEH MEDIAL FORM + +0FB56 +ARABIC LETTER PEH ISOLATED FORM + +0FB57 +ARABIC LETTER PEH FINAL FORM + +0FB58 +ARABIC LETTER PEH INITIAL FORM + +0FB59 +ARABIC LETTER PEH MEDIAL FORM + +0FB5A +ARABIC LETTER BEHEH ISOLATED FORM + +0FB5B +ARABIC LETTER BEHEH FINAL FORM + +0FB5C +ARABIC LETTER BEHEH INITIAL FORM + +0FB5D +ARABIC LETTER BEHEH MEDIAL FORM + +0FB5E +ARABIC LETTER TTEHEH ISOLATED FORM + +0FB5F +ARABIC LETTER TTEHEH FINAL FORM + +0FB60 +ARABIC LETTER TTEHEH INITIAL FORM + +0FB61 +ARABIC LETTER TTEHEH MEDIAL FORM + +0FB62 +ARABIC LETTER TEHEH ISOLATED FORM + +0FB63 +ARABIC LETTER TEHEH FINAL FORM + +0FB64 +ARABIC LETTER TEHEH INITIAL FORM + +0FB65 +ARABIC LETTER TEHEH MEDIAL FORM + +0FB66 +ARABIC LETTER TTEH ISOLATED FORM + +0FB67 +ARABIC LETTER TTEH FINAL FORM + +0FB68 +ARABIC LETTER TTEH INITIAL FORM + +0FB69 +ARABIC LETTER TTEH MEDIAL FORM + +0FB6A +ARABIC LETTER VEH ISOLATED FORM + +0FB6B +ARABIC LETTER VEH FINAL FORM + +0FB6C +ARABIC LETTER VEH INITIAL FORM + +0FB6D +ARABIC LETTER VEH MEDIAL FORM + +0FB6E +ARABIC LETTER PEHEH ISOLATED FORM + +0FB6F +ARABIC LETTER PEHEH FINAL FORM + +0FB70 +ARABIC LETTER PEHEH INITIAL FORM + +0FB71 +ARABIC LETTER PEHEH MEDIAL FORM + +0FB72 +ARABIC LETTER DYEH ISOLATED FORM + +0FB73 +ARABIC LETTER DYEH FINAL FORM + +0FB74 +ARABIC LETTER DYEH INITIAL FORM + +0FB75 +ARABIC LETTER DYEH MEDIAL FORM + +0FB76 +ARABIC LETTER NYEH ISOLATED FORM + +0FB77 +ARABIC LETTER NYEH FINAL FORM + +0FB78 +ARABIC LETTER NYEH INITIAL FORM + +0FB79 +ARABIC LETTER NYEH MEDIAL FORM + +0FB7A +ARABIC LETTER TCHEH ISOLATED FORM + +0FB7B +ARABIC LETTER TCHEH FINAL FORM + +0FB7C +ARABIC LETTER TCHEH INITIAL FORM + +0FB7D +ARABIC LETTER TCHEH MEDIAL FORM + +0FB7E +ARABIC LETTER TCHEHEH ISOLATED FORM + +0FB7F +ARABIC LETTER TCHEHEH FINAL FORM + +0FB80 +ARABIC LETTER TCHEHEH INITIAL FORM + +0FB81 +ARABIC LETTER TCHEHEH MEDIAL FORM + +0FB82 +ARABIC LETTER DDAHAL ISOLATED FORM + +0FB83 +ARABIC LETTER DDAHAL FINAL FORM + +0FB84 +ARABIC LETTER DAHAL ISOLATED FORM + +0FB85 +ARABIC LETTER DAHAL FINAL FORM + +0FB86 +ARABIC LETTER DUL ISOLATED FORM + +0FB87 +ARABIC LETTER DUL FINAL FORM + +0FB88 +ARABIC LETTER DDAL ISOLATED FORM + +0FB89 +ARABIC LETTER DDAL FINAL FORM + +0FB8A +ARABIC LETTER JEH ISOLATED FORM + +0FB8B +ARABIC LETTER JEH FINAL FORM + +0FB8C +ARABIC LETTER RREH ISOLATED FORM + +0FB8D +ARABIC LETTER RREH FINAL FORM + +0FB8E +ARABIC LETTER KEHEH ISOLATED FORM + +0FB8F +ARABIC LETTER KEHEH FINAL FORM + +0FB90 +ARABIC LETTER KEHEH INITIAL FORM + +0FB91 +ARABIC LETTER KEHEH MEDIAL FORM + +0FB92 +ARABIC LETTER GAF ISOLATED FORM + +0FB93 +ARABIC LETTER GAF FINAL FORM + +0FB94 +ARABIC LETTER GAF INITIAL FORM + +0FB95 +ARABIC LETTER GAF MEDIAL FORM + +0FB96 +ARABIC LETTER GUEH ISOLATED FORM + +0FB97 +ARABIC LETTER GUEH FINAL FORM + +0FB98 +ARABIC LETTER GUEH INITIAL FORM + +0FB99 +ARABIC LETTER GUEH MEDIAL FORM + +0FB9A +ARABIC LETTER NGOEH ISOLATED FORM + +0FB9B +ARABIC LETTER NGOEH FINAL FORM + +0FB9C +ARABIC LETTER NGOEH INITIAL FORM + +0FB9D +ARABIC LETTER NGOEH MEDIAL FORM + +0FB9E +ARABIC LETTER NOON GHUNNA ISOLATED FORM + +0FB9F +ARABIC LETTER NOON GHUNNA FINAL FORM + +0FBA0 +ARABIC LETTER RNOON ISOLATED FORM + +0FBA1 +ARABIC LETTER RNOON FINAL FORM + +0FBA2 +ARABIC LETTER RNOON INITIAL FORM + +0FBA3 +ARABIC LETTER RNOON MEDIAL FORM + +0FBA4 +ARABIC LETTER HEH WITH YEH ABOVE ISOLATED FORM + +0FBA5 +ARABIC LETTER HEH WITH YEH ABOVE FINAL FORM + +0FBA6 +ARABIC LETTER HEH GOAL ISOLATED FORM + +0FBA7 +ARABIC LETTER HEH GOAL FINAL FORM + +0FBA8 +ARABIC LETTER HEH GOAL INITIAL FORM + +0FBA9 +ARABIC LETTER HEH GOAL MEDIAL FORM + +0FBAA +ARABIC LETTER HEH DOACHASHMEE ISOLATED FORM + +0FBAB +ARABIC LETTER HEH DOACHASHMEE FINAL FORM + +0FBAC +ARABIC LETTER HEH DOACHASHMEE INITIAL FORM + +0FBAD +ARABIC LETTER HEH DOACHASHMEE MEDIAL FORM + +0FBAE +ARABIC LETTER YEH BARREE ISOLATED FORM + +0FBAF +ARABIC LETTER YEH BARREE FINAL FORM + +0FBB0 +ARABIC LETTER YEH BARREE WITH HAMZA ABOVE ISOLATED FORM + +0FBB1 +ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM + +0FBB2 +ARABIC SYMBOL DOT ABOVE + +0FBB3 +ARABIC SYMBOL DOT BELOW + +0FBB4 +ARABIC SYMBOL TWO DOTS ABOVE + +0FBB5 +ARABIC SYMBOL TWO DOTS BELOW + +0FBB6 +ARABIC SYMBOL THREE DOTS ABOVE + +0FBB7 +ARABIC SYMBOL THREE DOTS BELOW + +0FBB8 +ARABIC SYMBOL THREE DOTS POINTING DOWNWARDS ABOVE + +0FBB9 +ARABIC SYMBOL THREE DOTS POINTING DOWNWARDS BELOW + +0FBBA +ARABIC SYMBOL FOUR DOTS ABOVE + +0FBBB +ARABIC SYMBOL FOUR DOTS BELOW + +0FBBC +ARABIC SYMBOL DOUBLE VERTICAL BAR BELOW + +0FBBD +ARABIC SYMBOL TWO DOTS VERTICALLY ABOVE + +0FBBE +ARABIC SYMBOL TWO DOTS VERTICALLY BELOW + +0FBBF +ARABIC SYMBOL RING + +0FBC0 +ARABIC SYMBOL SMALL TAH ABOVE + +0FBC1 +ARABIC SYMBOL SMALL TAH BELOW + +0FBC2 +ARABIC SYMBOL WASLA ABOVE + +0FBC3 +ARABIC LIGATURE JALLA WA-ALAA + +0FBC4 +ARABIC LIGATURE DAAMAT BARAKAATUHUM + +0FBC5 +ARABIC LIGATURE RAHMATU ALLAAHI TAAALAA ALAYH + +0FBC6 +ARABIC LIGATURE RAHMATU ALLAAHI ALAYHIM + +0FBC7 +ARABIC LIGATURE RAHMATU ALLAAHI ALAYHIMAA + +0FBC8 +ARABIC LIGATURE RAHIMAHUM ALLAAHU TAAALAA + +0FBC9 +ARABIC LIGATURE RAHIMAHUMAA ALLAAH + +0FBCA +ARABIC LIGATURE RAHIMAHUMAA ALLAAHU TAAALAA + +0FBCB +ARABIC LIGATURE RADI ALLAAHU TAAALAA ANHUM + +0FBCC +ARABIC LIGATURE HAFIZAHU ALLAAH + +0FBCD +ARABIC LIGATURE HAFIZAHU ALLAAHU TAAALAA + +0FBCE +ARABIC LIGATURE HAFIZAHUM ALLAAHU TAAALAA + +0FBCF +ARABIC LIGATURE HAFIZAHUMAA ALLAAHU TAAALAA + +0FBD0 +ARABIC LIGATURE SALLALLAAHU TAAALAA ALAYHI WA-SALLAM + +0FBD1 +ARABIC LIGATURE AJJAL ALLAAHU FARAJAHU ASH-SHAREEF + +0FBD2 +ARABIC LIGATURE ALAYHI AR-RAHMAH + +0FBD3 +ARABIC LETTER NG ISOLATED FORM + +0FBD4 +ARABIC LETTER NG FINAL FORM + +0FBD5 +ARABIC LETTER NG INITIAL FORM + +0FBD6 +ARABIC LETTER NG MEDIAL FORM + +0FBD7 +ARABIC LETTER U ISOLATED FORM + +0FBD8 +ARABIC LETTER U FINAL FORM + +0FBD9 +ARABIC LETTER OE ISOLATED FORM + +0FBDA +ARABIC LETTER OE FINAL FORM + +0FBDB +ARABIC LETTER YU ISOLATED FORM + +0FBDC +ARABIC LETTER YU FINAL FORM + +0FBDD +ARABIC LETTER U WITH HAMZA ABOVE ISOLATED FORM + +0FBDE +ARABIC LETTER VE ISOLATED FORM + +0FBDF +ARABIC LETTER VE FINAL FORM + +0FBE0 +ARABIC LETTER KIRGHIZ OE ISOLATED FORM + +0FBE1 +ARABIC LETTER KIRGHIZ OE FINAL FORM + +0FBE2 +ARABIC LETTER KIRGHIZ YU ISOLATED FORM + +0FBE3 +ARABIC LETTER KIRGHIZ YU FINAL FORM + +0FBE4 +ARABIC LETTER E ISOLATED FORM + +0FBE5 +ARABIC LETTER E FINAL FORM + +0FBE6 +ARABIC LETTER E INITIAL FORM + +0FBE7 +ARABIC LETTER E MEDIAL FORM + +0FBE8 +ARABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA INITIAL FORM + +0FBE9 +ARABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA MEDIAL FORM + +0FBEA +ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF ISOLATED FORM + +0FBEB +ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF FINAL FORM + +0FBEC +ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE ISOLATED FORM + +0FBED +ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE FINAL FORM + +0FBEE +ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH WAW ISOLATED FORM + +0FBEF +ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH WAW FINAL FORM + +0FBF0 +ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U ISOLATED FORM + +0FBF1 +ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U FINAL FORM + +0FBF2 +ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH OE ISOLATED FORM + +0FBF3 +ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH OE FINAL FORM + +0FBF4 +ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YU ISOLATED FORM + +0FBF5 +ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YU FINAL FORM + +0FBF6 +ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E ISOLATED FORM + +0FBF7 +ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E FINAL FORM + +0FBF8 +ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E INITIAL FORM + +0FBF9 +ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA ISOLATED FORM + +0FBFA +ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA FINAL FORM + +0FBFB +ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA INITIAL FORM + +0FBFC +ARABIC LETTER FARSI YEH ISOLATED FORM + +0FBFD +ARABIC LETTER FARSI YEH FINAL FORM + +0FBFE +ARABIC LETTER FARSI YEH INITIAL FORM + +0FBFF +ARABIC LETTER FARSI YEH MEDIAL FORM + +0FC00 +ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH JEEM ISOLATED FORM + +0FC01 +ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HAH ISOLATED FORM + +0FC02 +ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM ISOLATED FORM + +0FC03 +ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA ISOLATED FORM + +0FC04 +ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YEH ISOLATED FORM + +0FC05 +ARABIC LIGATURE BEH WITH JEEM ISOLATED FORM + +0FC06 +ARABIC LIGATURE BEH WITH HAH ISOLATED FORM + +0FC07 +ARABIC LIGATURE BEH WITH KHAH ISOLATED FORM + +0FC08 +ARABIC LIGATURE BEH WITH MEEM ISOLATED FORM + +0FC09 +ARABIC LIGATURE BEH WITH ALEF MAKSURA ISOLATED FORM + +0FC0A +ARABIC LIGATURE BEH WITH YEH ISOLATED FORM + +0FC0B +ARABIC LIGATURE TEH WITH JEEM ISOLATED FORM + +0FC0C +ARABIC LIGATURE TEH WITH HAH ISOLATED FORM + +0FC0D +ARABIC LIGATURE TEH WITH KHAH ISOLATED FORM + +0FC0E +ARABIC LIGATURE TEH WITH MEEM ISOLATED FORM + +0FC0F +ARABIC LIGATURE TEH WITH ALEF MAKSURA ISOLATED FORM + +0FC10 +ARABIC LIGATURE TEH WITH YEH ISOLATED FORM + +0FC11 +ARABIC LIGATURE THEH WITH JEEM ISOLATED FORM + +0FC12 +ARABIC LIGATURE THEH WITH MEEM ISOLATED FORM + +0FC13 +ARABIC LIGATURE THEH WITH ALEF MAKSURA ISOLATED FORM + +0FC14 +ARABIC LIGATURE THEH WITH YEH ISOLATED FORM + +0FC15 +ARABIC LIGATURE JEEM WITH HAH ISOLATED FORM + +0FC16 +ARABIC LIGATURE JEEM WITH MEEM ISOLATED FORM + +0FC17 +ARABIC LIGATURE HAH WITH JEEM ISOLATED FORM + +0FC18 +ARABIC LIGATURE HAH WITH MEEM ISOLATED FORM + +0FC19 +ARABIC LIGATURE KHAH WITH JEEM ISOLATED FORM + +0FC1A +ARABIC LIGATURE KHAH WITH HAH ISOLATED FORM + +0FC1B +ARABIC LIGATURE KHAH WITH MEEM ISOLATED FORM + +0FC1C +ARABIC LIGATURE SEEN WITH JEEM ISOLATED FORM + +0FC1D +ARABIC LIGATURE SEEN WITH HAH ISOLATED FORM + +0FC1E +ARABIC LIGATURE SEEN WITH KHAH ISOLATED FORM + +0FC1F +ARABIC LIGATURE SEEN WITH MEEM ISOLATED FORM + +0FC20 +ARABIC LIGATURE SAD WITH HAH ISOLATED FORM + +0FC21 +ARABIC LIGATURE SAD WITH MEEM ISOLATED FORM + +0FC22 +ARABIC LIGATURE DAD WITH JEEM ISOLATED FORM + +0FC23 +ARABIC LIGATURE DAD WITH HAH ISOLATED FORM + +0FC24 +ARABIC LIGATURE DAD WITH KHAH ISOLATED FORM + +0FC25 +ARABIC LIGATURE DAD WITH MEEM ISOLATED FORM + +0FC26 +ARABIC LIGATURE TAH WITH HAH ISOLATED FORM + +0FC27 +ARABIC LIGATURE TAH WITH MEEM ISOLATED FORM + +0FC28 +ARABIC LIGATURE ZAH WITH MEEM ISOLATED FORM + +0FC29 +ARABIC LIGATURE AIN WITH JEEM ISOLATED FORM + +0FC2A +ARABIC LIGATURE AIN WITH MEEM ISOLATED FORM + +0FC2B +ARABIC LIGATURE GHAIN WITH JEEM ISOLATED FORM + +0FC2C +ARABIC LIGATURE GHAIN WITH MEEM ISOLATED FORM + +0FC2D +ARABIC LIGATURE FEH WITH JEEM ISOLATED FORM + +0FC2E +ARABIC LIGATURE FEH WITH HAH ISOLATED FORM + +0FC2F +ARABIC LIGATURE FEH WITH KHAH ISOLATED FORM + +0FC30 +ARABIC LIGATURE FEH WITH MEEM ISOLATED FORM + +0FC31 +ARABIC LIGATURE FEH WITH ALEF MAKSURA ISOLATED FORM + +0FC32 +ARABIC LIGATURE FEH WITH YEH ISOLATED FORM + +0FC33 +ARABIC LIGATURE QAF WITH HAH ISOLATED FORM + +0FC34 +ARABIC LIGATURE QAF WITH MEEM ISOLATED FORM + +0FC35 +ARABIC LIGATURE QAF WITH ALEF MAKSURA ISOLATED FORM + +0FC36 +ARABIC LIGATURE QAF WITH YEH ISOLATED FORM + +0FC37 +ARABIC LIGATURE KAF WITH ALEF ISOLATED FORM + +0FC38 +ARABIC LIGATURE KAF WITH JEEM ISOLATED FORM + +0FC39 +ARABIC LIGATURE KAF WITH HAH ISOLATED FORM + +0FC3A +ARABIC LIGATURE KAF WITH KHAH ISOLATED FORM + +0FC3B +ARABIC LIGATURE KAF WITH LAM ISOLATED FORM + +0FC3C +ARABIC LIGATURE KAF WITH MEEM ISOLATED FORM + +0FC3D +ARABIC LIGATURE KAF WITH ALEF MAKSURA ISOLATED FORM + +0FC3E +ARABIC LIGATURE KAF WITH YEH ISOLATED FORM + +0FC3F +ARABIC LIGATURE LAM WITH JEEM ISOLATED FORM + +0FC40 +ARABIC LIGATURE LAM WITH HAH ISOLATED FORM + +0FC41 +ARABIC LIGATURE LAM WITH KHAH ISOLATED FORM + +0FC42 +ARABIC LIGATURE LAM WITH MEEM ISOLATED FORM + +0FC43 +ARABIC LIGATURE LAM WITH ALEF MAKSURA ISOLATED FORM + +0FC44 +ARABIC LIGATURE LAM WITH YEH ISOLATED FORM + +0FC45 +ARABIC LIGATURE MEEM WITH JEEM ISOLATED FORM + +0FC46 +ARABIC LIGATURE MEEM WITH HAH ISOLATED FORM + +0FC47 +ARABIC LIGATURE MEEM WITH KHAH ISOLATED FORM + +0FC48 +ARABIC LIGATURE MEEM WITH MEEM ISOLATED FORM + +0FC49 +ARABIC LIGATURE MEEM WITH ALEF MAKSURA ISOLATED FORM + +0FC4A +ARABIC LIGATURE MEEM WITH YEH ISOLATED FORM + +0FC4B +ARABIC LIGATURE NOON WITH JEEM ISOLATED FORM + +0FC4C +ARABIC LIGATURE NOON WITH HAH ISOLATED FORM + +0FC4D +ARABIC LIGATURE NOON WITH KHAH ISOLATED FORM + +0FC4E +ARABIC LIGATURE NOON WITH MEEM ISOLATED FORM + +0FC4F +ARABIC LIGATURE NOON WITH ALEF MAKSURA ISOLATED FORM + +0FC50 +ARABIC LIGATURE NOON WITH YEH ISOLATED FORM + +0FC51 +ARABIC LIGATURE HEH WITH JEEM ISOLATED FORM + +0FC52 +ARABIC LIGATURE HEH WITH MEEM ISOLATED FORM + +0FC53 +ARABIC LIGATURE HEH WITH ALEF MAKSURA ISOLATED FORM + +0FC54 +ARABIC LIGATURE HEH WITH YEH ISOLATED FORM + +0FC55 +ARABIC LIGATURE YEH WITH JEEM ISOLATED FORM + +0FC56 +ARABIC LIGATURE YEH WITH HAH ISOLATED FORM + +0FC57 +ARABIC LIGATURE YEH WITH KHAH ISOLATED FORM + +0FC58 +ARABIC LIGATURE YEH WITH MEEM ISOLATED FORM + +0FC59 +ARABIC LIGATURE YEH WITH ALEF MAKSURA ISOLATED FORM + +0FC5A +ARABIC LIGATURE YEH WITH YEH ISOLATED FORM + +0FC5B +ARABIC LIGATURE THAL WITH SUPERSCRIPT ALEF ISOLATED FORM + +0FC5C +ARABIC LIGATURE REH WITH SUPERSCRIPT ALEF ISOLATED FORM + +0FC5D +ARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF ISOLATED FORM + +0FC5E +ARABIC LIGATURE SHADDA WITH DAMMATAN ISOLATED FORM + +0FC5F +ARABIC LIGATURE SHADDA WITH KASRATAN ISOLATED FORM + +0FC60 +ARABIC LIGATURE SHADDA WITH FATHA ISOLATED FORM + +0FC61 +ARABIC LIGATURE SHADDA WITH DAMMA ISOLATED FORM + +0FC62 +ARABIC LIGATURE SHADDA WITH KASRA ISOLATED FORM + +0FC63 +ARABIC LIGATURE SHADDA WITH SUPERSCRIPT ALEF ISOLATED FORM + +0FC64 +ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH REH FINAL FORM + +0FC65 +ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ZAIN FINAL FORM + +0FC66 +ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM FINAL FORM + +0FC67 +ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH NOON FINAL FORM + +0FC68 +ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA FINAL FORM + +0FC69 +ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YEH FINAL FORM + +0FC6A +ARABIC LIGATURE BEH WITH REH FINAL FORM + +0FC6B +ARABIC LIGATURE BEH WITH ZAIN FINAL FORM + +0FC6C +ARABIC LIGATURE BEH WITH MEEM FINAL FORM + +0FC6D +ARABIC LIGATURE BEH WITH NOON FINAL FORM + +0FC6E +ARABIC LIGATURE BEH WITH ALEF MAKSURA FINAL FORM + +0FC6F +ARABIC LIGATURE BEH WITH YEH FINAL FORM + +0FC70 +ARABIC LIGATURE TEH WITH REH FINAL FORM + +0FC71 +ARABIC LIGATURE TEH WITH ZAIN FINAL FORM + +0FC72 +ARABIC LIGATURE TEH WITH MEEM FINAL FORM + +0FC73 +ARABIC LIGATURE TEH WITH NOON FINAL FORM + +0FC74 +ARABIC LIGATURE TEH WITH ALEF MAKSURA FINAL FORM + +0FC75 +ARABIC LIGATURE TEH WITH YEH FINAL FORM + +0FC76 +ARABIC LIGATURE THEH WITH REH FINAL FORM + +0FC77 +ARABIC LIGATURE THEH WITH ZAIN FINAL FORM + +0FC78 +ARABIC LIGATURE THEH WITH MEEM FINAL FORM + +0FC79 +ARABIC LIGATURE THEH WITH NOON FINAL FORM + +0FC7A +ARABIC LIGATURE THEH WITH ALEF MAKSURA FINAL FORM + +0FC7B +ARABIC LIGATURE THEH WITH YEH FINAL FORM + +0FC7C +ARABIC LIGATURE FEH WITH ALEF MAKSURA FINAL FORM + +0FC7D +ARABIC LIGATURE FEH WITH YEH FINAL FORM + +0FC7E +ARABIC LIGATURE QAF WITH ALEF MAKSURA FINAL FORM + +0FC7F +ARABIC LIGATURE QAF WITH YEH FINAL FORM + +0FC80 +ARABIC LIGATURE KAF WITH ALEF FINAL FORM + +0FC81 +ARABIC LIGATURE KAF WITH LAM FINAL FORM + +0FC82 +ARABIC LIGATURE KAF WITH MEEM FINAL FORM + +0FC83 +ARABIC LIGATURE KAF WITH ALEF MAKSURA FINAL FORM + +0FC84 +ARABIC LIGATURE KAF WITH YEH FINAL FORM + +0FC85 +ARABIC LIGATURE LAM WITH MEEM FINAL FORM + +0FC86 +ARABIC LIGATURE LAM WITH ALEF MAKSURA FINAL FORM + +0FC87 +ARABIC LIGATURE LAM WITH YEH FINAL FORM + +0FC88 +ARABIC LIGATURE MEEM WITH ALEF FINAL FORM + +0FC89 +ARABIC LIGATURE MEEM WITH MEEM FINAL FORM + +0FC8A +ARABIC LIGATURE NOON WITH REH FINAL FORM + +0FC8B +ARABIC LIGATURE NOON WITH ZAIN FINAL FORM + +0FC8C +ARABIC LIGATURE NOON WITH MEEM FINAL FORM + +0FC8D +ARABIC LIGATURE NOON WITH NOON FINAL FORM + +0FC8E +ARABIC LIGATURE NOON WITH ALEF MAKSURA FINAL FORM + +0FC8F +ARABIC LIGATURE NOON WITH YEH FINAL FORM + +0FC90 +ARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF FINAL FORM + +0FC91 +ARABIC LIGATURE YEH WITH REH FINAL FORM + +0FC92 +ARABIC LIGATURE YEH WITH ZAIN FINAL FORM + +0FC93 +ARABIC LIGATURE YEH WITH MEEM FINAL FORM + +0FC94 +ARABIC LIGATURE YEH WITH NOON FINAL FORM + +0FC95 +ARABIC LIGATURE YEH WITH ALEF MAKSURA FINAL FORM + +0FC96 +ARABIC LIGATURE YEH WITH YEH FINAL FORM + +0FC97 +ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH JEEM INITIAL FORM + +0FC98 +ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HAH INITIAL FORM + +0FC99 +ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH KHAH INITIAL FORM + +0FC9A +ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM INITIAL FORM + +0FC9B +ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HEH INITIAL FORM + +0FC9C +ARABIC LIGATURE BEH WITH JEEM INITIAL FORM + +0FC9D +ARABIC LIGATURE BEH WITH HAH INITIAL FORM + +0FC9E +ARABIC LIGATURE BEH WITH KHAH INITIAL FORM + +0FC9F +ARABIC LIGATURE BEH WITH MEEM INITIAL FORM + +0FCA0 +ARABIC LIGATURE BEH WITH HEH INITIAL FORM + +0FCA1 +ARABIC LIGATURE TEH WITH JEEM INITIAL FORM + +0FCA2 +ARABIC LIGATURE TEH WITH HAH INITIAL FORM + +0FCA3 +ARABIC LIGATURE TEH WITH KHAH INITIAL FORM + +0FCA4 +ARABIC LIGATURE TEH WITH MEEM INITIAL FORM + +0FCA5 +ARABIC LIGATURE TEH WITH HEH INITIAL FORM + +0FCA6 +ARABIC LIGATURE THEH WITH MEEM INITIAL FORM + +0FCA7 +ARABIC LIGATURE JEEM WITH HAH INITIAL FORM + +0FCA8 +ARABIC LIGATURE JEEM WITH MEEM INITIAL FORM + +0FCA9 +ARABIC LIGATURE HAH WITH JEEM INITIAL FORM + +0FCAA +ARABIC LIGATURE HAH WITH MEEM INITIAL FORM + +0FCAB +ARABIC LIGATURE KHAH WITH JEEM INITIAL FORM + +0FCAC +ARABIC LIGATURE KHAH WITH MEEM INITIAL FORM + +0FCAD +ARABIC LIGATURE SEEN WITH JEEM INITIAL FORM + +0FCAE +ARABIC LIGATURE SEEN WITH HAH INITIAL FORM + +0FCAF +ARABIC LIGATURE SEEN WITH KHAH INITIAL FORM + +0FCB0 +ARABIC LIGATURE SEEN WITH MEEM INITIAL FORM + +0FCB1 +ARABIC LIGATURE SAD WITH HAH INITIAL FORM + +0FCB2 +ARABIC LIGATURE SAD WITH KHAH INITIAL FORM + +0FCB3 +ARABIC LIGATURE SAD WITH MEEM INITIAL FORM + +0FCB4 +ARABIC LIGATURE DAD WITH JEEM INITIAL FORM + +0FCB5 +ARABIC LIGATURE DAD WITH HAH INITIAL FORM + +0FCB6 +ARABIC LIGATURE DAD WITH KHAH INITIAL FORM + +0FCB7 +ARABIC LIGATURE DAD WITH MEEM INITIAL FORM + +0FCB8 +ARABIC LIGATURE TAH WITH HAH INITIAL FORM + +0FCB9 +ARABIC LIGATURE ZAH WITH MEEM INITIAL FORM + +0FCBA +ARABIC LIGATURE AIN WITH JEEM INITIAL FORM + +0FCBB +ARABIC LIGATURE AIN WITH MEEM INITIAL FORM + +0FCBC +ARABIC LIGATURE GHAIN WITH JEEM INITIAL FORM + +0FCBD +ARABIC LIGATURE GHAIN WITH MEEM INITIAL FORM + +0FCBE +ARABIC LIGATURE FEH WITH JEEM INITIAL FORM + +0FCBF +ARABIC LIGATURE FEH WITH HAH INITIAL FORM + +0FCC0 +ARABIC LIGATURE FEH WITH KHAH INITIAL FORM + +0FCC1 +ARABIC LIGATURE FEH WITH MEEM INITIAL FORM + +0FCC2 +ARABIC LIGATURE QAF WITH HAH INITIAL FORM + +0FCC3 +ARABIC LIGATURE QAF WITH MEEM INITIAL FORM + +0FCC4 +ARABIC LIGATURE KAF WITH JEEM INITIAL FORM + +0FCC5 +ARABIC LIGATURE KAF WITH HAH INITIAL FORM + +0FCC6 +ARABIC LIGATURE KAF WITH KHAH INITIAL FORM + +0FCC7 +ARABIC LIGATURE KAF WITH LAM INITIAL FORM + +0FCC8 +ARABIC LIGATURE KAF WITH MEEM INITIAL FORM + +0FCC9 +ARABIC LIGATURE LAM WITH JEEM INITIAL FORM + +0FCCA +ARABIC LIGATURE LAM WITH HAH INITIAL FORM + +0FCCB +ARABIC LIGATURE LAM WITH KHAH INITIAL FORM + +0FCCC +ARABIC LIGATURE LAM WITH MEEM INITIAL FORM + +0FCCD +ARABIC LIGATURE LAM WITH HEH INITIAL FORM + +0FCCE +ARABIC LIGATURE MEEM WITH JEEM INITIAL FORM + +0FCCF +ARABIC LIGATURE MEEM WITH HAH INITIAL FORM + +0FCD0 +ARABIC LIGATURE MEEM WITH KHAH INITIAL FORM + +0FCD1 +ARABIC LIGATURE MEEM WITH MEEM INITIAL FORM + +0FCD2 +ARABIC LIGATURE NOON WITH JEEM INITIAL FORM + +0FCD3 +ARABIC LIGATURE NOON WITH HAH INITIAL FORM + +0FCD4 +ARABIC LIGATURE NOON WITH KHAH INITIAL FORM + +0FCD5 +ARABIC LIGATURE NOON WITH MEEM INITIAL FORM + +0FCD6 +ARABIC LIGATURE NOON WITH HEH INITIAL FORM + +0FCD7 +ARABIC LIGATURE HEH WITH JEEM INITIAL FORM + +0FCD8 +ARABIC LIGATURE HEH WITH MEEM INITIAL FORM + +0FCD9 +ARABIC LIGATURE HEH WITH SUPERSCRIPT ALEF INITIAL FORM + +0FCDA +ARABIC LIGATURE YEH WITH JEEM INITIAL FORM + +0FCDB +ARABIC LIGATURE YEH WITH HAH INITIAL FORM + +0FCDC +ARABIC LIGATURE YEH WITH KHAH INITIAL FORM + +0FCDD +ARABIC LIGATURE YEH WITH MEEM INITIAL FORM + +0FCDE +ARABIC LIGATURE YEH WITH HEH INITIAL FORM + +0FCDF +ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM MEDIAL FORM + +0FCE0 +ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HEH MEDIAL FORM + +0FCE1 +ARABIC LIGATURE BEH WITH MEEM MEDIAL FORM + +0FCE2 +ARABIC LIGATURE BEH WITH HEH MEDIAL FORM + +0FCE3 +ARABIC LIGATURE TEH WITH MEEM MEDIAL FORM + +0FCE4 +ARABIC LIGATURE TEH WITH HEH MEDIAL FORM + +0FCE5 +ARABIC LIGATURE THEH WITH MEEM MEDIAL FORM + +0FCE6 +ARABIC LIGATURE THEH WITH HEH MEDIAL FORM + +0FCE7 +ARABIC LIGATURE SEEN WITH MEEM MEDIAL FORM + +0FCE8 +ARABIC LIGATURE SEEN WITH HEH MEDIAL FORM + +0FCE9 +ARABIC LIGATURE SHEEN WITH MEEM MEDIAL FORM + +0FCEA +ARABIC LIGATURE SHEEN WITH HEH MEDIAL FORM + +0FCEB +ARABIC LIGATURE KAF WITH LAM MEDIAL FORM + +0FCEC +ARABIC LIGATURE KAF WITH MEEM MEDIAL FORM + +0FCED +ARABIC LIGATURE LAM WITH MEEM MEDIAL FORM + +0FCEE +ARABIC LIGATURE NOON WITH MEEM MEDIAL FORM + +0FCEF +ARABIC LIGATURE NOON WITH HEH MEDIAL FORM + +0FCF0 +ARABIC LIGATURE YEH WITH MEEM MEDIAL FORM + +0FCF1 +ARABIC LIGATURE YEH WITH HEH MEDIAL FORM + +0FCF2 +ARABIC LIGATURE SHADDA WITH FATHA MEDIAL FORM + +0FCF3 +ARABIC LIGATURE SHADDA WITH DAMMA MEDIAL FORM + +0FCF4 +ARABIC LIGATURE SHADDA WITH KASRA MEDIAL FORM + +0FCF5 +ARABIC LIGATURE TAH WITH ALEF MAKSURA ISOLATED FORM + +0FCF6 +ARABIC LIGATURE TAH WITH YEH ISOLATED FORM + +0FCF7 +ARABIC LIGATURE AIN WITH ALEF MAKSURA ISOLATED FORM + +0FCF8 +ARABIC LIGATURE AIN WITH YEH ISOLATED FORM + +0FCF9 +ARABIC LIGATURE GHAIN WITH ALEF MAKSURA ISOLATED FORM + +0FCFA +ARABIC LIGATURE GHAIN WITH YEH ISOLATED FORM + +0FCFB +ARABIC LIGATURE SEEN WITH ALEF MAKSURA ISOLATED FORM + +0FCFC +ARABIC LIGATURE SEEN WITH YEH ISOLATED FORM + +0FCFD +ARABIC LIGATURE SHEEN WITH ALEF MAKSURA ISOLATED FORM + +0FCFE +ARABIC LIGATURE SHEEN WITH YEH ISOLATED FORM + +0FCFF +ARABIC LIGATURE HAH WITH ALEF MAKSURA ISOLATED FORM + +0FD00 +ARABIC LIGATURE HAH WITH YEH ISOLATED FORM + +0FD01 +ARABIC LIGATURE JEEM WITH ALEF MAKSURA ISOLATED FORM + +0FD02 +ARABIC LIGATURE JEEM WITH YEH ISOLATED FORM + +0FD03 +ARABIC LIGATURE KHAH WITH ALEF MAKSURA ISOLATED FORM + +0FD04 +ARABIC LIGATURE KHAH WITH YEH ISOLATED FORM + +0FD05 +ARABIC LIGATURE SAD WITH ALEF MAKSURA ISOLATED FORM + +0FD06 +ARABIC LIGATURE SAD WITH YEH ISOLATED FORM + +0FD07 +ARABIC LIGATURE DAD WITH ALEF MAKSURA ISOLATED FORM + +0FD08 +ARABIC LIGATURE DAD WITH YEH ISOLATED FORM + +0FD09 +ARABIC LIGATURE SHEEN WITH JEEM ISOLATED FORM + +0FD0A +ARABIC LIGATURE SHEEN WITH HAH ISOLATED FORM + +0FD0B +ARABIC LIGATURE SHEEN WITH KHAH ISOLATED FORM + +0FD0C +ARABIC LIGATURE SHEEN WITH MEEM ISOLATED FORM + +0FD0D +ARABIC LIGATURE SHEEN WITH REH ISOLATED FORM + +0FD0E +ARABIC LIGATURE SEEN WITH REH ISOLATED FORM + +0FD0F +ARABIC LIGATURE SAD WITH REH ISOLATED FORM + +0FD10 +ARABIC LIGATURE DAD WITH REH ISOLATED FORM + +0FD11 +ARABIC LIGATURE TAH WITH ALEF MAKSURA FINAL FORM + +0FD12 +ARABIC LIGATURE TAH WITH YEH FINAL FORM + +0FD13 +ARABIC LIGATURE AIN WITH ALEF MAKSURA FINAL FORM + +0FD14 +ARABIC LIGATURE AIN WITH YEH FINAL FORM + +0FD15 +ARABIC LIGATURE GHAIN WITH ALEF MAKSURA FINAL FORM + +0FD16 +ARABIC LIGATURE GHAIN WITH YEH FINAL FORM + +0FD17 +ARABIC LIGATURE SEEN WITH ALEF MAKSURA FINAL FORM + +0FD18 +ARABIC LIGATURE SEEN WITH YEH FINAL FORM + +0FD19 +ARABIC LIGATURE SHEEN WITH ALEF MAKSURA FINAL FORM + +0FD1A +ARABIC LIGATURE SHEEN WITH YEH FINAL FORM + +0FD1B +ARABIC LIGATURE HAH WITH ALEF MAKSURA FINAL FORM + +0FD1C +ARABIC LIGATURE HAH WITH YEH FINAL FORM + +0FD1D +ARABIC LIGATURE JEEM WITH ALEF MAKSURA FINAL FORM + +0FD1E +ARABIC LIGATURE JEEM WITH YEH FINAL FORM + +0FD1F +ARABIC LIGATURE KHAH WITH ALEF MAKSURA FINAL FORM + +0FD20 +ARABIC LIGATURE KHAH WITH YEH FINAL FORM + +0FD21 +ARABIC LIGATURE SAD WITH ALEF MAKSURA FINAL FORM + +0FD22 +ARABIC LIGATURE SAD WITH YEH FINAL FORM + +0FD23 +ARABIC LIGATURE DAD WITH ALEF MAKSURA FINAL FORM + +0FD24 +ARABIC LIGATURE DAD WITH YEH FINAL FORM + +0FD25 +ARABIC LIGATURE SHEEN WITH JEEM FINAL FORM + +0FD26 +ARABIC LIGATURE SHEEN WITH HAH FINAL FORM + +0FD27 +ARABIC LIGATURE SHEEN WITH KHAH FINAL FORM + +0FD28 +ARABIC LIGATURE SHEEN WITH MEEM FINAL FORM + +0FD29 +ARABIC LIGATURE SHEEN WITH REH FINAL FORM + +0FD2A +ARABIC LIGATURE SEEN WITH REH FINAL FORM + +0FD2B +ARABIC LIGATURE SAD WITH REH FINAL FORM + +0FD2C +ARABIC LIGATURE DAD WITH REH FINAL FORM + +0FD2D +ARABIC LIGATURE SHEEN WITH JEEM INITIAL FORM + +0FD2E +ARABIC LIGATURE SHEEN WITH HAH INITIAL FORM + +0FD2F +ARABIC LIGATURE SHEEN WITH KHAH INITIAL FORM + +0FD30 +ARABIC LIGATURE SHEEN WITH MEEM INITIAL FORM + +0FD31 +ARABIC LIGATURE SEEN WITH HEH INITIAL FORM + +0FD32 +ARABIC LIGATURE SHEEN WITH HEH INITIAL FORM + +0FD33 +ARABIC LIGATURE TAH WITH MEEM INITIAL FORM + +0FD34 +ARABIC LIGATURE SEEN WITH JEEM MEDIAL FORM + +0FD35 +ARABIC LIGATURE SEEN WITH HAH MEDIAL FORM + +0FD36 +ARABIC LIGATURE SEEN WITH KHAH MEDIAL FORM + +0FD37 +ARABIC LIGATURE SHEEN WITH JEEM MEDIAL FORM + +0FD38 +ARABIC LIGATURE SHEEN WITH HAH MEDIAL FORM + +0FD39 +ARABIC LIGATURE SHEEN WITH KHAH MEDIAL FORM + +0FD3A +ARABIC LIGATURE TAH WITH MEEM MEDIAL FORM + +0FD3B +ARABIC LIGATURE ZAH WITH MEEM MEDIAL FORM + +0FD3C +ARABIC LIGATURE ALEF WITH FATHATAN FINAL FORM + +0FD3D +ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM + +0FD3E +ORNATE LEFT PARENTHESIS + +0FD3F +ORNATE RIGHT PARENTHESIS + +0FD40 +ARABIC LIGATURE RAHIMAHU ALLAAH + +0FD41 +ARABIC LIGATURE RADI ALLAAHU ANH + +0FD42 +ARABIC LIGATURE RADI ALLAAHU ANHAA + +0FD43 +ARABIC LIGATURE RADI ALLAAHU ANHUM + +0FD44 +ARABIC LIGATURE RADI ALLAAHU ANHUMAA + +0FD45 +ARABIC LIGATURE RADI ALLAAHU ANHUNNA + +0FD46 +ARABIC LIGATURE SALLALLAAHU ALAYHI WA-AALIH + +0FD47 +ARABIC LIGATURE ALAYHI AS-SALAAM + +0FD48 +ARABIC LIGATURE ALAYHIM AS-SALAAM + +0FD49 +ARABIC LIGATURE ALAYHIMAA AS-SALAAM + +0FD4A +ARABIC LIGATURE ALAYHI AS-SALAATU WAS-SALAAM + +0FD4B +ARABIC LIGATURE QUDDISA SIRRAH + +0FD4C +ARABIC LIGATURE SALLALLAHU ALAYHI WAAALIHEE WA-SALLAM + +0FD4D +ARABIC LIGATURE ALAYHAA AS-SALAAM + +0FD4E +ARABIC LIGATURE TABAARAKA WA-TAAALAA + +0FD4F +ARABIC LIGATURE RAHIMAHUM ALLAAH + +0FD50 +ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIAL FORM + +0FD51 +ARABIC LIGATURE TEH WITH HAH WITH JEEM FINAL FORM + +0FD52 +ARABIC LIGATURE TEH WITH HAH WITH JEEM INITIAL FORM + +0FD53 +ARABIC LIGATURE TEH WITH HAH WITH MEEM INITIAL FORM + +0FD54 +ARABIC LIGATURE TEH WITH KHAH WITH MEEM INITIAL FORM + +0FD55 +ARABIC LIGATURE TEH WITH MEEM WITH JEEM INITIAL FORM + +0FD56 +ARABIC LIGATURE TEH WITH MEEM WITH HAH INITIAL FORM + +0FD57 +ARABIC LIGATURE TEH WITH MEEM WITH KHAH INITIAL FORM + +0FD58 +ARABIC LIGATURE JEEM WITH MEEM WITH HAH FINAL FORM + +0FD59 +ARABIC LIGATURE JEEM WITH MEEM WITH HAH INITIAL FORM + +0FD5A +ARABIC LIGATURE HAH WITH MEEM WITH YEH FINAL FORM + +0FD5B +ARABIC LIGATURE HAH WITH MEEM WITH ALEF MAKSURA FINAL FORM + +0FD5C +ARABIC LIGATURE SEEN WITH HAH WITH JEEM INITIAL FORM + +0FD5D +ARABIC LIGATURE SEEN WITH JEEM WITH HAH INITIAL FORM + +0FD5E +ARABIC LIGATURE SEEN WITH JEEM WITH ALEF MAKSURA FINAL FORM + +0FD5F +ARABIC LIGATURE SEEN WITH MEEM WITH HAH FINAL FORM + +0FD60 +ARABIC LIGATURE SEEN WITH MEEM WITH HAH INITIAL FORM + +0FD61 +ARABIC LIGATURE SEEN WITH MEEM WITH JEEM INITIAL FORM + +0FD62 +ARABIC LIGATURE SEEN WITH MEEM WITH MEEM FINAL FORM + +0FD63 +ARABIC LIGATURE SEEN WITH MEEM WITH MEEM INITIAL FORM + +0FD64 +ARABIC LIGATURE SAD WITH HAH WITH HAH FINAL FORM + +0FD65 +ARABIC LIGATURE SAD WITH HAH WITH HAH INITIAL FORM + +0FD66 +ARABIC LIGATURE SAD WITH MEEM WITH MEEM FINAL FORM + +0FD67 +ARABIC LIGATURE SHEEN WITH HAH WITH MEEM FINAL FORM + +0FD68 +ARABIC LIGATURE SHEEN WITH HAH WITH MEEM INITIAL FORM + +0FD69 +ARABIC LIGATURE SHEEN WITH JEEM WITH YEH FINAL FORM + +0FD6A +ARABIC LIGATURE SHEEN WITH MEEM WITH KHAH FINAL FORM + +0FD6B +ARABIC LIGATURE SHEEN WITH MEEM WITH KHAH INITIAL FORM + +0FD6C +ARABIC LIGATURE SHEEN WITH MEEM WITH MEEM FINAL FORM + +0FD6D +ARABIC LIGATURE SHEEN WITH MEEM WITH MEEM INITIAL FORM + +0FD6E +ARABIC LIGATURE DAD WITH HAH WITH ALEF MAKSURA FINAL FORM + +0FD6F +ARABIC LIGATURE DAD WITH KHAH WITH MEEM FINAL FORM + +0FD70 +ARABIC LIGATURE DAD WITH KHAH WITH MEEM INITIAL FORM + +0FD71 +ARABIC LIGATURE TAH WITH MEEM WITH HAH FINAL FORM + +0FD72 +ARABIC LIGATURE TAH WITH MEEM WITH HAH INITIAL FORM + +0FD73 +ARABIC LIGATURE TAH WITH MEEM WITH MEEM INITIAL FORM + +0FD74 +ARABIC LIGATURE TAH WITH MEEM WITH YEH FINAL FORM + +0FD75 +ARABIC LIGATURE AIN WITH JEEM WITH MEEM FINAL FORM + +0FD76 +ARABIC LIGATURE AIN WITH MEEM WITH MEEM FINAL FORM + +0FD77 +ARABIC LIGATURE AIN WITH MEEM WITH MEEM INITIAL FORM + +0FD78 +ARABIC LIGATURE AIN WITH MEEM WITH ALEF MAKSURA FINAL FORM + +0FD79 +ARABIC LIGATURE GHAIN WITH MEEM WITH MEEM FINAL FORM + +0FD7A +ARABIC LIGATURE GHAIN WITH MEEM WITH YEH FINAL FORM + +0FD7B +ARABIC LIGATURE GHAIN WITH MEEM WITH ALEF MAKSURA FINAL FORM + +0FD7C +ARABIC LIGATURE FEH WITH KHAH WITH MEEM FINAL FORM + +0FD7D +ARABIC LIGATURE FEH WITH KHAH WITH MEEM INITIAL FORM + +0FD7E +ARABIC LIGATURE QAF WITH MEEM WITH HAH FINAL FORM + +0FD7F +ARABIC LIGATURE QAF WITH MEEM WITH MEEM FINAL FORM + +0FD80 +ARABIC LIGATURE LAM WITH HAH WITH MEEM FINAL FORM + +0FD81 +ARABIC LIGATURE LAM WITH HAH WITH YEH FINAL FORM + +0FD82 +ARABIC LIGATURE LAM WITH HAH WITH ALEF MAKSURA FINAL FORM + +0FD83 +ARABIC LIGATURE LAM WITH JEEM WITH JEEM INITIAL FORM + +0FD84 +ARABIC LIGATURE LAM WITH JEEM WITH JEEM FINAL FORM + +0FD85 +ARABIC LIGATURE LAM WITH KHAH WITH MEEM FINAL FORM + +0FD86 +ARABIC LIGATURE LAM WITH KHAH WITH MEEM INITIAL FORM + +0FD87 +ARABIC LIGATURE LAM WITH MEEM WITH HAH FINAL FORM + +0FD88 +ARABIC LIGATURE LAM WITH MEEM WITH HAH INITIAL FORM + +0FD89 +ARABIC LIGATURE MEEM WITH HAH WITH JEEM INITIAL FORM + +0FD8A +ARABIC LIGATURE MEEM WITH HAH WITH MEEM INITIAL FORM + +0FD8B +ARABIC LIGATURE MEEM WITH HAH WITH YEH FINAL FORM + +0FD8C +ARABIC LIGATURE MEEM WITH JEEM WITH HAH INITIAL FORM + +0FD8D +ARABIC LIGATURE MEEM WITH JEEM WITH MEEM INITIAL FORM + +0FD8E +ARABIC LIGATURE MEEM WITH KHAH WITH JEEM INITIAL FORM + +0FD8F +ARABIC LIGATURE MEEM WITH KHAH WITH MEEM INITIAL FORM + +0FD90 +ARABIC LIGATURE RAHMATU ALLAAHI ALAYH + +0FD91 +ARABIC LIGATURE RAHMATU ALLAAHI ALAYHAA + +0FD92 +ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM + +0FD93 +ARABIC LIGATURE HEH WITH MEEM WITH JEEM INITIAL FORM + +0FD94 +ARABIC LIGATURE HEH WITH MEEM WITH MEEM INITIAL FORM + +0FD95 +ARABIC LIGATURE NOON WITH HAH WITH MEEM INITIAL FORM + +0FD96 +ARABIC LIGATURE NOON WITH HAH WITH ALEF MAKSURA FINAL FORM + +0FD97 +ARABIC LIGATURE NOON WITH JEEM WITH MEEM FINAL FORM + +0FD98 +ARABIC LIGATURE NOON WITH JEEM WITH MEEM INITIAL FORM + +0FD99 +ARABIC LIGATURE NOON WITH JEEM WITH ALEF MAKSURA FINAL FORM + +0FD9A +ARABIC LIGATURE NOON WITH MEEM WITH YEH FINAL FORM + +0FD9B +ARABIC LIGATURE NOON WITH MEEM WITH ALEF MAKSURA FINAL FORM + +0FD9C +ARABIC LIGATURE YEH WITH MEEM WITH MEEM FINAL FORM + +0FD9D +ARABIC LIGATURE YEH WITH MEEM WITH MEEM INITIAL FORM + +0FD9E +ARABIC LIGATURE BEH WITH KHAH WITH YEH FINAL FORM + +0FD9F +ARABIC LIGATURE TEH WITH JEEM WITH YEH FINAL FORM + +0FDA0 +ARABIC LIGATURE TEH WITH JEEM WITH ALEF MAKSURA FINAL FORM + +0FDA1 +ARABIC LIGATURE TEH WITH KHAH WITH YEH FINAL FORM + +0FDA2 +ARABIC LIGATURE TEH WITH KHAH WITH ALEF MAKSURA FINAL FORM + +0FDA3 +ARABIC LIGATURE TEH WITH MEEM WITH YEH FINAL FORM + +0FDA4 +ARABIC LIGATURE TEH WITH MEEM WITH ALEF MAKSURA FINAL FORM + +0FDA5 +ARABIC LIGATURE JEEM WITH MEEM WITH YEH FINAL FORM + +0FDA6 +ARABIC LIGATURE JEEM WITH HAH WITH ALEF MAKSURA FINAL FORM + +0FDA7 +ARABIC LIGATURE JEEM WITH MEEM WITH ALEF MAKSURA FINAL FORM + +0FDA8 +ARABIC LIGATURE SEEN WITH KHAH WITH ALEF MAKSURA FINAL FORM + +0FDA9 +ARABIC LIGATURE SAD WITH HAH WITH YEH FINAL FORM + +0FDAA +ARABIC LIGATURE SHEEN WITH HAH WITH YEH FINAL FORM + +0FDAB +ARABIC LIGATURE DAD WITH HAH WITH YEH FINAL FORM + +0FDAC +ARABIC LIGATURE LAM WITH JEEM WITH YEH FINAL FORM + +0FDAD +ARABIC LIGATURE LAM WITH MEEM WITH YEH FINAL FORM + +0FDAE +ARABIC LIGATURE YEH WITH HAH WITH YEH FINAL FORM + +0FDAF +ARABIC LIGATURE YEH WITH JEEM WITH YEH FINAL FORM + +0FDB0 +ARABIC LIGATURE YEH WITH MEEM WITH YEH FINAL FORM + +0FDB1 +ARABIC LIGATURE MEEM WITH MEEM WITH YEH FINAL FORM + +0FDB2 +ARABIC LIGATURE QAF WITH MEEM WITH YEH FINAL FORM + +0FDB3 +ARABIC LIGATURE NOON WITH HAH WITH YEH FINAL FORM + +0FDB4 +ARABIC LIGATURE QAF WITH MEEM WITH HAH INITIAL FORM + +0FDB5 +ARABIC LIGATURE LAM WITH HAH WITH MEEM INITIAL FORM + +0FDB6 +ARABIC LIGATURE AIN WITH MEEM WITH YEH FINAL FORM + +0FDB7 +ARABIC LIGATURE KAF WITH MEEM WITH YEH FINAL FORM + +0FDB8 +ARABIC LIGATURE NOON WITH JEEM WITH HAH INITIAL FORM + +0FDB9 +ARABIC LIGATURE MEEM WITH KHAH WITH YEH FINAL FORM + +0FDBA +ARABIC LIGATURE LAM WITH JEEM WITH MEEM INITIAL FORM + +0FDBB +ARABIC LIGATURE KAF WITH MEEM WITH MEEM FINAL FORM + +0FDBC +ARABIC LIGATURE LAM WITH JEEM WITH MEEM FINAL FORM + +0FDBD +ARABIC LIGATURE NOON WITH JEEM WITH HAH FINAL FORM + +0FDBE +ARABIC LIGATURE JEEM WITH HAH WITH YEH FINAL FORM + +0FDBF +ARABIC LIGATURE HAH WITH JEEM WITH YEH FINAL FORM + +0FDC0 +ARABIC LIGATURE MEEM WITH JEEM WITH YEH FINAL FORM + +0FDC1 +ARABIC LIGATURE FEH WITH MEEM WITH YEH FINAL FORM + +0FDC2 +ARABIC LIGATURE BEH WITH HAH WITH YEH FINAL FORM + +0FDC3 +ARABIC LIGATURE KAF WITH MEEM WITH MEEM INITIAL FORM + +0FDC4 +ARABIC LIGATURE AIN WITH JEEM WITH MEEM INITIAL FORM + +0FDC5 +ARABIC LIGATURE SAD WITH MEEM WITH MEEM INITIAL FORM + +0FDC6 +ARABIC LIGATURE SEEN WITH KHAH WITH YEH FINAL FORM + +0FDC7 +ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM + +0FDC8 +ARABIC LIGATURE RAHIMAHU ALLAAH TAAALAA + +0FDC9 +ARABIC LIGATURE RADI ALLAAHU TAAALAA ANH + +0FDCA +ARABIC LIGATURE RADI ALLAAHU TAAALAA ANHAA + +0FDCB +ARABIC LIGATURE RADI ALLAAHU TAAALAA ANHUMAA + +0FDCC +ARABIC LIGATURE SALLALLAHU ALAYHI WA-ALAA AALIHEE WA-SALLAM + +0FDCD +ARABIC LIGATURE AJJAL ALLAAHU TAAALAA FARAJAHU ASH-SHAREEF + +0FDCE +ARABIC LIGATURE KARRAMA ALLAAHU WAJHAH + +0FDCF +ARABIC LIGATURE SALAAMUHU ALAYNAA + +0FDF0 +ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM + +0FDF1 +ARABIC LIGATURE QALA USED AS KORANIC STOP SIGN ISOLATED FORM + +0FDF2 +ARABIC LIGATURE ALLAH ISOLATED FORM + +0FDF3 +ARABIC LIGATURE AKBAR ISOLATED FORM + +0FDF4 +ARABIC LIGATURE MOHAMMAD ISOLATED FORM + +0FDF5 +ARABIC LIGATURE SALAM ISOLATED FORM + +0FDF6 +ARABIC LIGATURE RASOUL ISOLATED FORM + +0FDF7 +ARABIC LIGATURE ALAYHE ISOLATED FORM + +0FDF8 +ARABIC LIGATURE WASALLAM ISOLATED FORM + +0FDF9 +ARABIC LIGATURE SALLA ISOLATED FORM + +0FDFA +ARABIC LIGATURE SALLALLAHOU ALAYHE WASALLAM + +0FDFB +ARABIC LIGATURE JALLAJALALOUHOU + +0FDFC +RIAL SIGN + +0FDFD +ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM + +0FDFE +ARABIC LIGATURE SUBHAANAHU WA TAAALAA + +0FDFF +ARABIC LIGATURE AZZA WA JALL + +0FE00 +VARIATION SELECTOR-1 + +0FE00 +VS1 + +0FE01 +VARIATION SELECTOR-2 + +0FE01 +VS2 + +0FE02 +VARIATION SELECTOR-3 + +0FE02 +VS3 + +0FE03 +VARIATION SELECTOR-4 + +0FE03 +VS4 + +0FE04 +VARIATION SELECTOR-5 + +0FE04 +VS5 + +0FE05 +VARIATION SELECTOR-6 + +0FE05 +VS6 + +0FE06 +VARIATION SELECTOR-7 + +0FE06 +VS7 + +0FE07 +VARIATION SELECTOR-8 + +0FE07 +VS8 + +0FE08 +VARIATION SELECTOR-9 + +0FE08 +VS9 + +0FE09 +VARIATION SELECTOR-10 + +0FE09 +VS10 + +0FE0A +VARIATION SELECTOR-11 + +0FE0A +VS11 + +0FE0B +VARIATION SELECTOR-12 + +0FE0B +VS12 + +0FE0C +VARIATION SELECTOR-13 + +0FE0C +VS13 + +0FE0D +VARIATION SELECTOR-14 + +0FE0D +VS14 + +0FE0E +VARIATION SELECTOR-15 + +0FE0E +VS15 + +0FE0F +VARIATION SELECTOR-16 + +0FE0F +VS16 + +0FE10 +PRESENTATION FORM FOR VERTICAL COMMA + +0FE11 +PRESENTATION FORM FOR VERTICAL IDEOGRAPHIC COMMA + +0FE12 +PRESENTATION FORM FOR VERTICAL IDEOGRAPHIC FULL STOP + +0FE13 +PRESENTATION FORM FOR VERTICAL COLON + +0FE14 +PRESENTATION FORM FOR VERTICAL SEMICOLON + +0FE15 +PRESENTATION FORM FOR VERTICAL EXCLAMATION MARK + +0FE16 +PRESENTATION FORM FOR VERTICAL QUESTION MARK + +0FE17 +PRESENTATION FORM FOR VERTICAL LEFT WHITE LENTICULAR BRACKET + +0FE18 +PRESENTATION FORM FOR VERTICAL RIGHT WHITE LENTICULAR BRACKET + +0FE18 +PRESENTATION FORM FOR VERTICAL RIGHT WHITE LENTICULAR BRAKCET + +0FE19 +PRESENTATION FORM FOR VERTICAL HORIZONTAL ELLIPSIS + +0FE20 +COMBINING LIGATURE LEFT HALF + +0FE21 +COMBINING LIGATURE RIGHT HALF + +0FE22 +COMBINING DOUBLE TILDE LEFT HALF + +0FE23 +COMBINING DOUBLE TILDE RIGHT HALF + +0FE24 +COMBINING MACRON LEFT HALF + +0FE25 +COMBINING MACRON RIGHT HALF + +0FE26 +COMBINING CONJOINING MACRON + +0FE27 +COMBINING LIGATURE LEFT HALF BELOW + +0FE28 +COMBINING LIGATURE RIGHT HALF BELOW + +0FE29 +COMBINING TILDE LEFT HALF BELOW + +0FE2A +COMBINING TILDE RIGHT HALF BELOW + +0FE2B +COMBINING MACRON LEFT HALF BELOW + +0FE2C +COMBINING MACRON RIGHT HALF BELOW + +0FE2D +COMBINING CONJOINING MACRON BELOW + +0FE2E +COMBINING CYRILLIC TITLO LEFT HALF + +0FE2F +COMBINING CYRILLIC TITLO RIGHT HALF + +0FE30 +PRESENTATION FORM FOR VERTICAL TWO DOT LEADER + +0FE31 +PRESENTATION FORM FOR VERTICAL EM DASH + +0FE32 +PRESENTATION FORM FOR VERTICAL EN DASH + +0FE33 +PRESENTATION FORM FOR VERTICAL LOW LINE + +0FE34 +PRESENTATION FORM FOR VERTICAL WAVY LOW LINE + +0FE35 +PRESENTATION FORM FOR VERTICAL LEFT PARENTHESIS + +0FE36 +PRESENTATION FORM FOR VERTICAL RIGHT PARENTHESIS + +0FE37 +PRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKET + +0FE38 +PRESENTATION FORM FOR VERTICAL RIGHT CURLY BRACKET + +0FE39 +PRESENTATION FORM FOR VERTICAL LEFT TORTOISE SHELL BRACKET + +0FE3A +PRESENTATION FORM FOR VERTICAL RIGHT TORTOISE SHELL BRACKET + +0FE3B +PRESENTATION FORM FOR VERTICAL LEFT BLACK LENTICULAR BRACKET + +0FE3C +PRESENTATION FORM FOR VERTICAL RIGHT BLACK LENTICULAR BRACKET + +0FE3D +PRESENTATION FORM FOR VERTICAL LEFT DOUBLE ANGLE BRACKET + +0FE3E +PRESENTATION FORM FOR VERTICAL RIGHT DOUBLE ANGLE BRACKET + +0FE3F +PRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKET + +0FE40 +PRESENTATION FORM FOR VERTICAL RIGHT ANGLE BRACKET + +0FE41 +PRESENTATION FORM FOR VERTICAL LEFT CORNER BRACKET + +0FE42 +PRESENTATION FORM FOR VERTICAL RIGHT CORNER BRACKET + +0FE43 +PRESENTATION FORM FOR VERTICAL LEFT WHITE CORNER BRACKET + +0FE44 +PRESENTATION FORM FOR VERTICAL RIGHT WHITE CORNER BRACKET + +0FE45 +SESAME DOT + +0FE46 +WHITE SESAME DOT + +0FE47 +PRESENTATION FORM FOR VERTICAL LEFT SQUARE BRACKET + +0FE48 +PRESENTATION FORM FOR VERTICAL RIGHT SQUARE BRACKET + +0FE49 +DASHED OVERLINE + +0FE4A +CENTRELINE OVERLINE + +0FE4B +WAVY OVERLINE + +0FE4C +DOUBLE WAVY OVERLINE + +0FE4D +DASHED LOW LINE + +0FE4E +CENTRELINE LOW LINE + +0FE4F +WAVY LOW LINE + +0FE50 +SMALL COMMA + +0FE51 +SMALL IDEOGRAPHIC COMMA + +0FE52 +SMALL FULL STOP + +0FE54 +SMALL SEMICOLON + +0FE55 +SMALL COLON + +0FE56 +SMALL QUESTION MARK + +0FE57 +SMALL EXCLAMATION MARK + +0FE58 +SMALL EM DASH + +0FE59 +SMALL LEFT PARENTHESIS + +0FE5A +SMALL RIGHT PARENTHESIS + +0FE5B +SMALL LEFT CURLY BRACKET + +0FE5C +SMALL RIGHT CURLY BRACKET + +0FE5D +SMALL LEFT TORTOISE SHELL BRACKET + +0FE5E +SMALL RIGHT TORTOISE SHELL BRACKET + +0FE5F +SMALL NUMBER SIGN + +0FE60 +SMALL AMPERSAND + +0FE61 +SMALL ASTERISK + +0FE62 +SMALL PLUS SIGN + +0FE63 +SMALL HYPHEN-MINUS + +0FE64 +SMALL LESS-THAN SIGN + +0FE65 +SMALL GREATER-THAN SIGN + +0FE66 +SMALL EQUALS SIGN + +0FE68 +SMALL REVERSE SOLIDUS + +0FE69 +SMALL DOLLAR SIGN + +0FE6A +SMALL PERCENT SIGN + +0FE6B +SMALL COMMERCIAL AT + +0FE70 +ARABIC FATHATAN ISOLATED FORM + +0FE71 +ARABIC TATWEEL WITH FATHATAN ABOVE + +0FE72 +ARABIC DAMMATAN ISOLATED FORM + +0FE73 +ARABIC TAIL FRAGMENT + +0FE74 +ARABIC KASRATAN ISOLATED FORM + +0FE76 +ARABIC FATHA ISOLATED FORM + +0FE77 +ARABIC FATHA MEDIAL FORM + +0FE78 +ARABIC DAMMA ISOLATED FORM + +0FE79 +ARABIC DAMMA MEDIAL FORM + +0FE7A +ARABIC KASRA ISOLATED FORM + +0FE7B +ARABIC KASRA MEDIAL FORM + +0FE7C +ARABIC SHADDA ISOLATED FORM + +0FE7D +ARABIC SHADDA MEDIAL FORM + +0FE7E +ARABIC SUKUN ISOLATED FORM + +0FE7F +ARABIC SUKUN MEDIAL FORM + +0FE80 +ARABIC LETTER HAMZA ISOLATED FORM + +0FE81 +ARABIC LETTER ALEF WITH MADDA ABOVE ISOLATED FORM + +0FE82 +ARABIC LETTER ALEF WITH MADDA ABOVE FINAL FORM + +0FE83 +ARABIC LETTER ALEF WITH HAMZA ABOVE ISOLATED FORM + +0FE84 +ARABIC LETTER ALEF WITH HAMZA ABOVE FINAL FORM + +0FE85 +ARABIC LETTER WAW WITH HAMZA ABOVE ISOLATED FORM + +0FE86 +ARABIC LETTER WAW WITH HAMZA ABOVE FINAL FORM + +0FE87 +ARABIC LETTER ALEF WITH HAMZA BELOW ISOLATED FORM + +0FE88 +ARABIC LETTER ALEF WITH HAMZA BELOW FINAL FORM + +0FE89 +ARABIC LETTER YEH WITH HAMZA ABOVE ISOLATED FORM + +0FE8A +ARABIC LETTER YEH WITH HAMZA ABOVE FINAL FORM + +0FE8B +ARABIC LETTER YEH WITH HAMZA ABOVE INITIAL FORM + +0FE8C +ARABIC LETTER YEH WITH HAMZA ABOVE MEDIAL FORM + +0FE8D +ARABIC LETTER ALEF ISOLATED FORM + +0FE8E +ARABIC LETTER ALEF FINAL FORM + +0FE8F +ARABIC LETTER BEH ISOLATED FORM + +0FE90 +ARABIC LETTER BEH FINAL FORM + +0FE91 +ARABIC LETTER BEH INITIAL FORM + +0FE92 +ARABIC LETTER BEH MEDIAL FORM + +0FE93 +ARABIC LETTER TEH MARBUTA ISOLATED FORM + +0FE94 +ARABIC LETTER TEH MARBUTA FINAL FORM + +0FE95 +ARABIC LETTER TEH ISOLATED FORM + +0FE96 +ARABIC LETTER TEH FINAL FORM + +0FE97 +ARABIC LETTER TEH INITIAL FORM + +0FE98 +ARABIC LETTER TEH MEDIAL FORM + +0FE99 +ARABIC LETTER THEH ISOLATED FORM + +0FE9A +ARABIC LETTER THEH FINAL FORM + +0FE9B +ARABIC LETTER THEH INITIAL FORM + +0FE9C +ARABIC LETTER THEH MEDIAL FORM + +0FE9D +ARABIC LETTER JEEM ISOLATED FORM + +0FE9E +ARABIC LETTER JEEM FINAL FORM + +0FE9F +ARABIC LETTER JEEM INITIAL FORM + +0FEA0 +ARABIC LETTER JEEM MEDIAL FORM + +0FEA1 +ARABIC LETTER HAH ISOLATED FORM + +0FEA2 +ARABIC LETTER HAH FINAL FORM + +0FEA3 +ARABIC LETTER HAH INITIAL FORM + +0FEA4 +ARABIC LETTER HAH MEDIAL FORM + +0FEA5 +ARABIC LETTER KHAH ISOLATED FORM + +0FEA6 +ARABIC LETTER KHAH FINAL FORM + +0FEA7 +ARABIC LETTER KHAH INITIAL FORM + +0FEA8 +ARABIC LETTER KHAH MEDIAL FORM + +0FEA9 +ARABIC LETTER DAL ISOLATED FORM + +0FEAA +ARABIC LETTER DAL FINAL FORM + +0FEAB +ARABIC LETTER THAL ISOLATED FORM + +0FEAC +ARABIC LETTER THAL FINAL FORM + +0FEAD +ARABIC LETTER REH ISOLATED FORM + +0FEAE +ARABIC LETTER REH FINAL FORM + +0FEAF +ARABIC LETTER ZAIN ISOLATED FORM + +0FEB0 +ARABIC LETTER ZAIN FINAL FORM + +0FEB1 +ARABIC LETTER SEEN ISOLATED FORM + +0FEB2 +ARABIC LETTER SEEN FINAL FORM + +0FEB3 +ARABIC LETTER SEEN INITIAL FORM + +0FEB4 +ARABIC LETTER SEEN MEDIAL FORM + +0FEB5 +ARABIC LETTER SHEEN ISOLATED FORM + +0FEB6 +ARABIC LETTER SHEEN FINAL FORM + +0FEB7 +ARABIC LETTER SHEEN INITIAL FORM + +0FEB8 +ARABIC LETTER SHEEN MEDIAL FORM + +0FEB9 +ARABIC LETTER SAD ISOLATED FORM + +0FEBA +ARABIC LETTER SAD FINAL FORM + +0FEBB +ARABIC LETTER SAD INITIAL FORM + +0FEBC +ARABIC LETTER SAD MEDIAL FORM + +0FEBD +ARABIC LETTER DAD ISOLATED FORM + +0FEBE +ARABIC LETTER DAD FINAL FORM + +0FEBF +ARABIC LETTER DAD INITIAL FORM + +0FEC0 +ARABIC LETTER DAD MEDIAL FORM + +0FEC1 +ARABIC LETTER TAH ISOLATED FORM + +0FEC2 +ARABIC LETTER TAH FINAL FORM + +0FEC3 +ARABIC LETTER TAH INITIAL FORM + +0FEC4 +ARABIC LETTER TAH MEDIAL FORM + +0FEC5 +ARABIC LETTER ZAH ISOLATED FORM + +0FEC6 +ARABIC LETTER ZAH FINAL FORM + +0FEC7 +ARABIC LETTER ZAH INITIAL FORM + +0FEC8 +ARABIC LETTER ZAH MEDIAL FORM + +0FEC9 +ARABIC LETTER AIN ISOLATED FORM + +0FECA +ARABIC LETTER AIN FINAL FORM + +0FECB +ARABIC LETTER AIN INITIAL FORM + +0FECC +ARABIC LETTER AIN MEDIAL FORM + +0FECD +ARABIC LETTER GHAIN ISOLATED FORM + +0FECE +ARABIC LETTER GHAIN FINAL FORM + +0FECF +ARABIC LETTER GHAIN INITIAL FORM + +0FED0 +ARABIC LETTER GHAIN MEDIAL FORM + +0FED1 +ARABIC LETTER FEH ISOLATED FORM + +0FED2 +ARABIC LETTER FEH FINAL FORM + +0FED3 +ARABIC LETTER FEH INITIAL FORM + +0FED4 +ARABIC LETTER FEH MEDIAL FORM + +0FED5 +ARABIC LETTER QAF ISOLATED FORM + +0FED6 +ARABIC LETTER QAF FINAL FORM + +0FED7 +ARABIC LETTER QAF INITIAL FORM + +0FED8 +ARABIC LETTER QAF MEDIAL FORM + +0FED9 +ARABIC LETTER KAF ISOLATED FORM + +0FEDA +ARABIC LETTER KAF FINAL FORM + +0FEDB +ARABIC LETTER KAF INITIAL FORM + +0FEDC +ARABIC LETTER KAF MEDIAL FORM + +0FEDD +ARABIC LETTER LAM ISOLATED FORM + +0FEDE +ARABIC LETTER LAM FINAL FORM + +0FEDF +ARABIC LETTER LAM INITIAL FORM + +0FEE0 +ARABIC LETTER LAM MEDIAL FORM + +0FEE1 +ARABIC LETTER MEEM ISOLATED FORM + +0FEE2 +ARABIC LETTER MEEM FINAL FORM + +0FEE3 +ARABIC LETTER MEEM INITIAL FORM + +0FEE4 +ARABIC LETTER MEEM MEDIAL FORM + +0FEE5 +ARABIC LETTER NOON ISOLATED FORM + +0FEE6 +ARABIC LETTER NOON FINAL FORM + +0FEE7 +ARABIC LETTER NOON INITIAL FORM + +0FEE8 +ARABIC LETTER NOON MEDIAL FORM + +0FEE9 +ARABIC LETTER HEH ISOLATED FORM + +0FEEA +ARABIC LETTER HEH FINAL FORM + +0FEEB +ARABIC LETTER HEH INITIAL FORM + +0FEEC +ARABIC LETTER HEH MEDIAL FORM + +0FEED +ARABIC LETTER WAW ISOLATED FORM + +0FEEE +ARABIC LETTER WAW FINAL FORM + +0FEEF +ARABIC LETTER ALEF MAKSURA ISOLATED FORM + +0FEF0 +ARABIC LETTER ALEF MAKSURA FINAL FORM + +0FEF1 +ARABIC LETTER YEH ISOLATED FORM + +0FEF2 +ARABIC LETTER YEH FINAL FORM + +0FEF3 +ARABIC LETTER YEH INITIAL FORM + +0FEF4 +ARABIC LETTER YEH MEDIAL FORM + +0FEF5 +ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM + +0FEF6 +ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM + +0FEF7 +ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM + +0FEF8 +ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM + +0FEF9 +ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM + +0FEFA +ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM + +0FEFB +ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM + +0FEFC +ARABIC LIGATURE LAM WITH ALEF FINAL FORM + +0FEFF +ZERO WIDTH NO-BREAK SPACE + +0FEFF +BYTE ORDER MARK + +0FEFF +BOM + +0FEFF +ZWNBSP + +0FF01 +FULLWIDTH EXCLAMATION MARK + +0FF02 +FULLWIDTH QUOTATION MARK + +0FF03 +FULLWIDTH NUMBER SIGN + +0FF04 +FULLWIDTH DOLLAR SIGN + +0FF05 +FULLWIDTH PERCENT SIGN + +0FF06 +FULLWIDTH AMPERSAND + +0FF07 +FULLWIDTH APOSTROPHE + +0FF08 +FULLWIDTH LEFT PARENTHESIS + +0FF09 +FULLWIDTH RIGHT PARENTHESIS + +0FF0A +FULLWIDTH ASTERISK + +0FF0B +FULLWIDTH PLUS SIGN + +0FF0C +FULLWIDTH COMMA + +0FF0D +FULLWIDTH HYPHEN-MINUS + +0FF0E +FULLWIDTH FULL STOP + +0FF0F +FULLWIDTH SOLIDUS + +0FF10 +FULLWIDTH DIGIT ZERO + +0FF11 +FULLWIDTH DIGIT ONE + +0FF12 +FULLWIDTH DIGIT TWO + +0FF13 +FULLWIDTH DIGIT THREE + +0FF14 +FULLWIDTH DIGIT FOUR + +0FF15 +FULLWIDTH DIGIT FIVE + +0FF16 +FULLWIDTH DIGIT SIX + +0FF17 +FULLWIDTH DIGIT SEVEN + +0FF18 +FULLWIDTH DIGIT EIGHT + +0FF19 +FULLWIDTH DIGIT NINE + +0FF1A +FULLWIDTH COLON + +0FF1B +FULLWIDTH SEMICOLON + +0FF1C +FULLWIDTH LESS-THAN SIGN + +0FF1D +FULLWIDTH EQUALS SIGN + +0FF1E +FULLWIDTH GREATER-THAN SIGN + +0FF1F +FULLWIDTH QUESTION MARK + +0FF20 +FULLWIDTH COMMERCIAL AT + +0FF21 +FULLWIDTH LATIN CAPITAL LETTER A + +0FF22 +FULLWIDTH LATIN CAPITAL LETTER B + +0FF23 +FULLWIDTH LATIN CAPITAL LETTER C + +0FF24 +FULLWIDTH LATIN CAPITAL LETTER D + +0FF25 +FULLWIDTH LATIN CAPITAL LETTER E + +0FF26 +FULLWIDTH LATIN CAPITAL LETTER F + +0FF27 +FULLWIDTH LATIN CAPITAL LETTER G + +0FF28 +FULLWIDTH LATIN CAPITAL LETTER H + +0FF29 +FULLWIDTH LATIN CAPITAL LETTER I + +0FF2A +FULLWIDTH LATIN CAPITAL LETTER J + +0FF2B +FULLWIDTH LATIN CAPITAL LETTER K + +0FF2C +FULLWIDTH LATIN CAPITAL LETTER L + +0FF2D +FULLWIDTH LATIN CAPITAL LETTER M + +0FF2E +FULLWIDTH LATIN CAPITAL LETTER N + +0FF2F +FULLWIDTH LATIN CAPITAL LETTER O + +0FF30 +FULLWIDTH LATIN CAPITAL LETTER P + +0FF31 +FULLWIDTH LATIN CAPITAL LETTER Q + +0FF32 +FULLWIDTH LATIN CAPITAL LETTER R + +0FF33 +FULLWIDTH LATIN CAPITAL LETTER S + +0FF34 +FULLWIDTH LATIN CAPITAL LETTER T + +0FF35 +FULLWIDTH LATIN CAPITAL LETTER U + +0FF36 +FULLWIDTH LATIN CAPITAL LETTER V + +0FF37 +FULLWIDTH LATIN CAPITAL LETTER W + +0FF38 +FULLWIDTH LATIN CAPITAL LETTER X + +0FF39 +FULLWIDTH LATIN CAPITAL LETTER Y + +0FF3A +FULLWIDTH LATIN CAPITAL LETTER Z + +0FF3B +FULLWIDTH LEFT SQUARE BRACKET + +0FF3C +FULLWIDTH REVERSE SOLIDUS + +0FF3D +FULLWIDTH RIGHT SQUARE BRACKET + +0FF3E +FULLWIDTH CIRCUMFLEX ACCENT + +0FF3F +FULLWIDTH LOW LINE + +0FF40 +FULLWIDTH GRAVE ACCENT + +0FF41 +FULLWIDTH LATIN SMALL LETTER A + +0FF42 +FULLWIDTH LATIN SMALL LETTER B + +0FF43 +FULLWIDTH LATIN SMALL LETTER C + +0FF44 +FULLWIDTH LATIN SMALL LETTER D + +0FF45 +FULLWIDTH LATIN SMALL LETTER E + +0FF46 +FULLWIDTH LATIN SMALL LETTER F + +0FF47 +FULLWIDTH LATIN SMALL LETTER G + +0FF48 +FULLWIDTH LATIN SMALL LETTER H + +0FF49 +FULLWIDTH LATIN SMALL LETTER I + +0FF4A +FULLWIDTH LATIN SMALL LETTER J + +0FF4B +FULLWIDTH LATIN SMALL LETTER K + +0FF4C +FULLWIDTH LATIN SMALL LETTER L + +0FF4D +FULLWIDTH LATIN SMALL LETTER M + +0FF4E +FULLWIDTH LATIN SMALL LETTER N + +0FF4F +FULLWIDTH LATIN SMALL LETTER O + +0FF50 +FULLWIDTH LATIN SMALL LETTER P + +0FF51 +FULLWIDTH LATIN SMALL LETTER Q + +0FF52 +FULLWIDTH LATIN SMALL LETTER R + +0FF53 +FULLWIDTH LATIN SMALL LETTER S + +0FF54 +FULLWIDTH LATIN SMALL LETTER T + +0FF55 +FULLWIDTH LATIN SMALL LETTER U + +0FF56 +FULLWIDTH LATIN SMALL LETTER V + +0FF57 +FULLWIDTH LATIN SMALL LETTER W + +0FF58 +FULLWIDTH LATIN SMALL LETTER X + +0FF59 +FULLWIDTH LATIN SMALL LETTER Y + +0FF5A +FULLWIDTH LATIN SMALL LETTER Z + +0FF5B +FULLWIDTH LEFT CURLY BRACKET + +0FF5C +FULLWIDTH VERTICAL LINE + +0FF5D +FULLWIDTH RIGHT CURLY BRACKET + +0FF5E +FULLWIDTH TILDE + +0FF5F +FULLWIDTH LEFT WHITE PARENTHESIS + +0FF60 +FULLWIDTH RIGHT WHITE PARENTHESIS + +0FF61 +HALFWIDTH IDEOGRAPHIC FULL STOP + +0FF62 +HALFWIDTH LEFT CORNER BRACKET + +0FF63 +HALFWIDTH RIGHT CORNER BRACKET + +0FF64 +HALFWIDTH IDEOGRAPHIC COMMA + +0FF65 +HALFWIDTH KATAKANA MIDDLE DOT + +0FF66 +HALFWIDTH KATAKANA LETTER WO + +0FF67 +HALFWIDTH KATAKANA LETTER SMALL A + +0FF68 +HALFWIDTH KATAKANA LETTER SMALL I + +0FF69 +HALFWIDTH KATAKANA LETTER SMALL U + +0FF6A +HALFWIDTH KATAKANA LETTER SMALL E + +0FF6B +HALFWIDTH KATAKANA LETTER SMALL O + +0FF6C +HALFWIDTH KATAKANA LETTER SMALL YA + +0FF6D +HALFWIDTH KATAKANA LETTER SMALL YU + +0FF6E +HALFWIDTH KATAKANA LETTER SMALL YO + +0FF6F +HALFWIDTH KATAKANA LETTER SMALL TU + +0FF70 +HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK + +0FF71 +HALFWIDTH KATAKANA LETTER A + +0FF72 +HALFWIDTH KATAKANA LETTER I + +0FF73 +HALFWIDTH KATAKANA LETTER U + +0FF74 +HALFWIDTH KATAKANA LETTER E + +0FF75 +HALFWIDTH KATAKANA LETTER O + +0FF76 +HALFWIDTH KATAKANA LETTER KA + +0FF77 +HALFWIDTH KATAKANA LETTER KI + +0FF78 +HALFWIDTH KATAKANA LETTER KU + +0FF79 +HALFWIDTH KATAKANA LETTER KE + +0FF7A +HALFWIDTH KATAKANA LETTER KO + +0FF7B +HALFWIDTH KATAKANA LETTER SA + +0FF7C +HALFWIDTH KATAKANA LETTER SI + +0FF7D +HALFWIDTH KATAKANA LETTER SU + +0FF7E +HALFWIDTH KATAKANA LETTER SE + +0FF7F +HALFWIDTH KATAKANA LETTER SO + +0FF80 +HALFWIDTH KATAKANA LETTER TA + +0FF81 +HALFWIDTH KATAKANA LETTER TI + +0FF82 +HALFWIDTH KATAKANA LETTER TU + +0FF83 +HALFWIDTH KATAKANA LETTER TE + +0FF84 +HALFWIDTH KATAKANA LETTER TO + +0FF85 +HALFWIDTH KATAKANA LETTER NA + +0FF86 +HALFWIDTH KATAKANA LETTER NI + +0FF87 +HALFWIDTH KATAKANA LETTER NU + +0FF88 +HALFWIDTH KATAKANA LETTER NE + +0FF89 +HALFWIDTH KATAKANA LETTER NO + +0FF8A +HALFWIDTH KATAKANA LETTER HA + +0FF8B +HALFWIDTH KATAKANA LETTER HI + +0FF8C +HALFWIDTH KATAKANA LETTER HU + +0FF8D +HALFWIDTH KATAKANA LETTER HE + +0FF8E +HALFWIDTH KATAKANA LETTER HO + +0FF8F +HALFWIDTH KATAKANA LETTER MA + +0FF90 +HALFWIDTH KATAKANA LETTER MI + +0FF91 +HALFWIDTH KATAKANA LETTER MU + +0FF92 +HALFWIDTH KATAKANA LETTER ME + +0FF93 +HALFWIDTH KATAKANA LETTER MO + +0FF94 +HALFWIDTH KATAKANA LETTER YA + +0FF95 +HALFWIDTH KATAKANA LETTER YU + +0FF96 +HALFWIDTH KATAKANA LETTER YO + +0FF97 +HALFWIDTH KATAKANA LETTER RA + +0FF98 +HALFWIDTH KATAKANA LETTER RI + +0FF99 +HALFWIDTH KATAKANA LETTER RU + +0FF9A +HALFWIDTH KATAKANA LETTER RE + +0FF9B +HALFWIDTH KATAKANA LETTER RO + +0FF9C +HALFWIDTH KATAKANA LETTER WA + +0FF9D +HALFWIDTH KATAKANA LETTER N + +0FF9E +HALFWIDTH KATAKANA VOICED SOUND MARK + +0FF9F +HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK + +0FFA0 +HALFWIDTH HANGUL FILLER + +0FFA1 +HALFWIDTH HANGUL LETTER KIYEOK + +0FFA2 +HALFWIDTH HANGUL LETTER SSANGKIYEOK + +0FFA3 +HALFWIDTH HANGUL LETTER KIYEOK-SIOS + +0FFA4 +HALFWIDTH HANGUL LETTER NIEUN + +0FFA5 +HALFWIDTH HANGUL LETTER NIEUN-CIEUC + +0FFA6 +HALFWIDTH HANGUL LETTER NIEUN-HIEUH + +0FFA7 +HALFWIDTH HANGUL LETTER TIKEUT + +0FFA8 +HALFWIDTH HANGUL LETTER SSANGTIKEUT + +0FFA9 +HALFWIDTH HANGUL LETTER RIEUL + +0FFAA +HALFWIDTH HANGUL LETTER RIEUL-KIYEOK + +0FFAB +HALFWIDTH HANGUL LETTER RIEUL-MIEUM + +0FFAC +HALFWIDTH HANGUL LETTER RIEUL-PIEUP + +0FFAD +HALFWIDTH HANGUL LETTER RIEUL-SIOS + +0FFAE +HALFWIDTH HANGUL LETTER RIEUL-THIEUTH + +0FFAF +HALFWIDTH HANGUL LETTER RIEUL-PHIEUPH + +0FFB0 +HALFWIDTH HANGUL LETTER RIEUL-HIEUH + +0FFB1 +HALFWIDTH HANGUL LETTER MIEUM + +0FFB2 +HALFWIDTH HANGUL LETTER PIEUP + +0FFB3 +HALFWIDTH HANGUL LETTER SSANGPIEUP + +0FFB4 +HALFWIDTH HANGUL LETTER PIEUP-SIOS + +0FFB5 +HALFWIDTH HANGUL LETTER SIOS + +0FFB6 +HALFWIDTH HANGUL LETTER SSANGSIOS + +0FFB7 +HALFWIDTH HANGUL LETTER IEUNG + +0FFB8 +HALFWIDTH HANGUL LETTER CIEUC + +0FFB9 +HALFWIDTH HANGUL LETTER SSANGCIEUC + +0FFBA +HALFWIDTH HANGUL LETTER CHIEUCH + +0FFBB +HALFWIDTH HANGUL LETTER KHIEUKH + +0FFBC +HALFWIDTH HANGUL LETTER THIEUTH + +0FFBD +HALFWIDTH HANGUL LETTER PHIEUPH + +0FFBE +HALFWIDTH HANGUL LETTER HIEUH + +0FFC2 +HALFWIDTH HANGUL LETTER A + +0FFC3 +HALFWIDTH HANGUL LETTER AE + +0FFC4 +HALFWIDTH HANGUL LETTER YA + +0FFC5 +HALFWIDTH HANGUL LETTER YAE + +0FFC6 +HALFWIDTH HANGUL LETTER EO + +0FFC7 +HALFWIDTH HANGUL LETTER E + +0FFCA +HALFWIDTH HANGUL LETTER YEO + +0FFCB +HALFWIDTH HANGUL LETTER YE + +0FFCC +HALFWIDTH HANGUL LETTER O + +0FFCD +HALFWIDTH HANGUL LETTER WA + +0FFCE +HALFWIDTH HANGUL LETTER WAE + +0FFCF +HALFWIDTH HANGUL LETTER OE + +0FFD2 +HALFWIDTH HANGUL LETTER YO + +0FFD3 +HALFWIDTH HANGUL LETTER U + +0FFD4 +HALFWIDTH HANGUL LETTER WEO + +0FFD5 +HALFWIDTH HANGUL LETTER WE + +0FFD6 +HALFWIDTH HANGUL LETTER WI + +0FFD7 +HALFWIDTH HANGUL LETTER YU + +0FFDA +HALFWIDTH HANGUL LETTER EU + +0FFDB +HALFWIDTH HANGUL LETTER YI + +0FFDC +HALFWIDTH HANGUL LETTER I + +0FFE0 +FULLWIDTH CENT SIGN + +0FFE1 +FULLWIDTH POUND SIGN + +0FFE2 +FULLWIDTH NOT SIGN + +0FFE3 +FULLWIDTH MACRON + +0FFE4 +FULLWIDTH BROKEN BAR + +0FFE5 +FULLWIDTH YEN SIGN + +0FFE6 +FULLWIDTH WON SIGN + +0FFE8 +HALFWIDTH FORMS LIGHT VERTICAL + +0FFE9 +HALFWIDTH LEFTWARDS ARROW + +0FFEA +HALFWIDTH UPWARDS ARROW + +0FFEB +HALFWIDTH RIGHTWARDS ARROW + +0FFEC +HALFWIDTH DOWNWARDS ARROW + +0FFED +HALFWIDTH BLACK SQUARE + +0FFEE +HALFWIDTH WHITE CIRCLE + +0FFF9 +INTERLINEAR ANNOTATION ANCHOR + +0FFFA +INTERLINEAR ANNOTATION SEPARATOR + +0FFFB +INTERLINEAR ANNOTATION TERMINATOR + +0FFFC +OBJECT REPLACEMENT CHARACTER + +0FFFD +REPLACEMENT CHARACTER + +10000 +LINEAR B SYLLABLE B008 A + +10001 +LINEAR B SYLLABLE B038 E + +10002 +LINEAR B SYLLABLE B028 I + +10003 +LINEAR B SYLLABLE B061 O + +10004 +LINEAR B SYLLABLE B010 U + +10005 +LINEAR B SYLLABLE B001 DA + +10006 +LINEAR B SYLLABLE B045 DE + +10007 +LINEAR B SYLLABLE B007 DI + +10008 +LINEAR B SYLLABLE B014 DO + +10009 +LINEAR B SYLLABLE B051 DU + +1000A +LINEAR B SYLLABLE B057 JA + +1000B +LINEAR B SYLLABLE B046 JE + +1000D +LINEAR B SYLLABLE B036 JO + +1000E +LINEAR B SYLLABLE B065 JU + +1000F +LINEAR B SYLLABLE B077 KA + +10010 +LINEAR B SYLLABLE B044 KE + +10011 +LINEAR B SYLLABLE B067 KI + +10012 +LINEAR B SYLLABLE B070 KO + +10013 +LINEAR B SYLLABLE B081 KU + +10014 +LINEAR B SYLLABLE B080 MA + +10015 +LINEAR B SYLLABLE B013 ME + +10016 +LINEAR B SYLLABLE B073 MI + +10017 +LINEAR B SYLLABLE B015 MO + +10018 +LINEAR B SYLLABLE B023 MU + +10019 +LINEAR B SYLLABLE B006 NA + +1001A +LINEAR B SYLLABLE B024 NE + +1001B +LINEAR B SYLLABLE B030 NI + +1001C +LINEAR B SYLLABLE B052 NO + +1001D +LINEAR B SYLLABLE B055 NU + +1001E +LINEAR B SYLLABLE B003 PA + +1001F +LINEAR B SYLLABLE B072 PE + +10020 +LINEAR B SYLLABLE B039 PI + +10021 +LINEAR B SYLLABLE B011 PO + +10022 +LINEAR B SYLLABLE B050 PU + +10023 +LINEAR B SYLLABLE B016 QA + +10024 +LINEAR B SYLLABLE B078 QE + +10025 +LINEAR B SYLLABLE B021 QI + +10026 +LINEAR B SYLLABLE B032 QO + +10028 +LINEAR B SYLLABLE B060 RA + +10029 +LINEAR B SYLLABLE B027 RE + +1002A +LINEAR B SYLLABLE B053 RI + +1002B +LINEAR B SYLLABLE B002 RO + +1002C +LINEAR B SYLLABLE B026 RU + +1002D +LINEAR B SYLLABLE B031 SA + +1002E +LINEAR B SYLLABLE B009 SE + +1002F +LINEAR B SYLLABLE B041 SI + +10030 +LINEAR B SYLLABLE B012 SO + +10031 +LINEAR B SYLLABLE B058 SU + +10032 +LINEAR B SYLLABLE B059 TA + +10033 +LINEAR B SYLLABLE B004 TE + +10034 +LINEAR B SYLLABLE B037 TI + +10035 +LINEAR B SYLLABLE B005 TO + +10036 +LINEAR B SYLLABLE B069 TU + +10037 +LINEAR B SYLLABLE B054 WA + +10038 +LINEAR B SYLLABLE B075 WE + +10039 +LINEAR B SYLLABLE B040 WI + +1003A +LINEAR B SYLLABLE B042 WO + +1003C +LINEAR B SYLLABLE B017 ZA + +1003D +LINEAR B SYLLABLE B074 ZE + +1003F +LINEAR B SYLLABLE B020 ZO + +10040 +LINEAR B SYLLABLE B025 A2 + +10041 +LINEAR B SYLLABLE B043 A3 + +10042 +LINEAR B SYLLABLE B085 AU + +10043 +LINEAR B SYLLABLE B071 DWE + +10044 +LINEAR B SYLLABLE B090 DWO + +10045 +LINEAR B SYLLABLE B048 NWA + +10046 +LINEAR B SYLLABLE B029 PU2 + +10047 +LINEAR B SYLLABLE B062 PTE + +10048 +LINEAR B SYLLABLE B076 RA2 + +10049 +LINEAR B SYLLABLE B033 RA3 + +1004A +LINEAR B SYLLABLE B068 RO2 + +1004B +LINEAR B SYLLABLE B066 TA2 + +1004C +LINEAR B SYLLABLE B087 TWE + +1004D +LINEAR B SYLLABLE B091 TWO + +10050 +LINEAR B SYMBOL B018 + +10051 +LINEAR B SYMBOL B019 + +10052 +LINEAR B SYMBOL B022 + +10053 +LINEAR B SYMBOL B034 + +10054 +LINEAR B SYMBOL B047 + +10055 +LINEAR B SYMBOL B049 + +10056 +LINEAR B SYMBOL B056 + +10057 +LINEAR B SYMBOL B063 + +10058 +LINEAR B SYMBOL B064 + +10059 +LINEAR B SYMBOL B079 + +1005A +LINEAR B SYMBOL B082 + +1005B +LINEAR B SYMBOL B083 + +1005C +LINEAR B SYMBOL B086 + +1005D +LINEAR B SYMBOL B089 + +10080 +LINEAR B IDEOGRAM B100 MAN + +10081 +LINEAR B IDEOGRAM B102 WOMAN + +10082 +LINEAR B IDEOGRAM B104 DEER + +10083 +LINEAR B IDEOGRAM B105 EQUID + +10084 +LINEAR B IDEOGRAM B105F MARE + +10085 +LINEAR B IDEOGRAM B105M STALLION + +10086 +LINEAR B IDEOGRAM B106F EWE + +10087 +LINEAR B IDEOGRAM B106M RAM + +10088 +LINEAR B IDEOGRAM B107F SHE-GOAT + +10089 +LINEAR B IDEOGRAM B107M HE-GOAT + +1008A +LINEAR B IDEOGRAM B108F SOW + +1008B +LINEAR B IDEOGRAM B108M BOAR + +1008C +LINEAR B IDEOGRAM B109F COW + +1008D +LINEAR B IDEOGRAM B109M BULL + +1008E +LINEAR B IDEOGRAM B120 WHEAT + +1008F +LINEAR B IDEOGRAM B121 BARLEY + +10090 +LINEAR B IDEOGRAM B122 OLIVE + +10091 +LINEAR B IDEOGRAM B123 SPICE + +10092 +LINEAR B IDEOGRAM B125 CYPERUS + +10093 +LINEAR B MONOGRAM B127 KAPO + +10094 +LINEAR B MONOGRAM B128 KANAKO + +10095 +LINEAR B IDEOGRAM B130 OIL + +10096 +LINEAR B IDEOGRAM B131 WINE + +10097 +LINEAR B IDEOGRAM B132 + +10098 +LINEAR B MONOGRAM B133 AREPA + +10099 +LINEAR B MONOGRAM B135 MERI + +1009A +LINEAR B IDEOGRAM B140 BRONZE + +1009B +LINEAR B IDEOGRAM B141 GOLD + +1009C +LINEAR B IDEOGRAM B142 + +1009D +LINEAR B IDEOGRAM B145 WOOL + +1009E +LINEAR B IDEOGRAM B146 + +1009F +LINEAR B IDEOGRAM B150 + +100A0 +LINEAR B IDEOGRAM B151 HORN + +100A1 +LINEAR B IDEOGRAM B152 + +100A2 +LINEAR B IDEOGRAM B153 + +100A3 +LINEAR B IDEOGRAM B154 + +100A4 +LINEAR B MONOGRAM B156 TURO2 + +100A5 +LINEAR B IDEOGRAM B157 + +100A6 +LINEAR B IDEOGRAM B158 + +100A7 +LINEAR B IDEOGRAM B159 CLOTH + +100A8 +LINEAR B IDEOGRAM B160 + +100A9 +LINEAR B IDEOGRAM B161 + +100AA +LINEAR B IDEOGRAM B162 GARMENT + +100AB +LINEAR B IDEOGRAM B163 ARMOUR + +100AC +LINEAR B IDEOGRAM B164 + +100AD +LINEAR B IDEOGRAM B165 + +100AE +LINEAR B IDEOGRAM B166 + +100AF +LINEAR B IDEOGRAM B167 + +100B0 +LINEAR B IDEOGRAM B168 + +100B1 +LINEAR B IDEOGRAM B169 + +100B2 +LINEAR B IDEOGRAM B170 + +100B3 +LINEAR B IDEOGRAM B171 + +100B4 +LINEAR B IDEOGRAM B172 + +100B5 +LINEAR B IDEOGRAM B173 MONTH + +100B6 +LINEAR B IDEOGRAM B174 + +100B7 +LINEAR B IDEOGRAM B176 TREE + +100B8 +LINEAR B IDEOGRAM B177 + +100B9 +LINEAR B IDEOGRAM B178 + +100BA +LINEAR B IDEOGRAM B179 + +100BB +LINEAR B IDEOGRAM B180 + +100BC +LINEAR B IDEOGRAM B181 + +100BD +LINEAR B IDEOGRAM B182 + +100BE +LINEAR B IDEOGRAM B183 + +100BF +LINEAR B IDEOGRAM B184 + +100C0 +LINEAR B IDEOGRAM B185 + +100C1 +LINEAR B IDEOGRAM B189 + +100C2 +LINEAR B IDEOGRAM B190 + +100C3 +LINEAR B IDEOGRAM B191 HELMET + +100C4 +LINEAR B IDEOGRAM B220 FOOTSTOOL + +100C5 +LINEAR B IDEOGRAM B225 BATHTUB + +100C6 +LINEAR B IDEOGRAM B230 SPEAR + +100C7 +LINEAR B IDEOGRAM B231 ARROW + +100C8 +LINEAR B IDEOGRAM B232 + +100C9 +LINEAR B IDEOGRAM B233 SWORD + +100CA +LINEAR B IDEOGRAM B234 + +100CB +LINEAR B IDEOGRAM B236 + +100CC +LINEAR B IDEOGRAM B240 WHEELED CHARIOT + +100CD +LINEAR B IDEOGRAM B241 CHARIOT + +100CE +LINEAR B IDEOGRAM B242 CHARIOT FRAME + +100CF +LINEAR B IDEOGRAM B243 WHEEL + +100D0 +LINEAR B IDEOGRAM B245 + +100D1 +LINEAR B IDEOGRAM B246 + +100D2 +LINEAR B MONOGRAM B247 DIPTE + +100D3 +LINEAR B IDEOGRAM B248 + +100D4 +LINEAR B IDEOGRAM B249 + +100D5 +LINEAR B IDEOGRAM B251 + +100D6 +LINEAR B IDEOGRAM B252 + +100D7 +LINEAR B IDEOGRAM B253 + +100D8 +LINEAR B IDEOGRAM B254 DART + +100D9 +LINEAR B IDEOGRAM B255 + +100DA +LINEAR B IDEOGRAM B256 + +100DB +LINEAR B IDEOGRAM B257 + +100DC +LINEAR B IDEOGRAM B258 + +100DD +LINEAR B IDEOGRAM B259 + +100DE +LINEAR B IDEOGRAM VESSEL B155 + +100DF +LINEAR B IDEOGRAM VESSEL B200 + +100E0 +LINEAR B IDEOGRAM VESSEL B201 + +100E1 +LINEAR B IDEOGRAM VESSEL B202 + +100E2 +LINEAR B IDEOGRAM VESSEL B203 + +100E3 +LINEAR B IDEOGRAM VESSEL B204 + +100E4 +LINEAR B IDEOGRAM VESSEL B205 + +100E5 +LINEAR B IDEOGRAM VESSEL B206 + +100E6 +LINEAR B IDEOGRAM VESSEL B207 + +100E7 +LINEAR B IDEOGRAM VESSEL B208 + +100E8 +LINEAR B IDEOGRAM VESSEL B209 + +100E9 +LINEAR B IDEOGRAM VESSEL B210 + +100EA +LINEAR B IDEOGRAM VESSEL B211 + +100EB +LINEAR B IDEOGRAM VESSEL B212 + +100EC +LINEAR B IDEOGRAM VESSEL B213 + +100ED +LINEAR B IDEOGRAM VESSEL B214 + +100EE +LINEAR B IDEOGRAM VESSEL B215 + +100EF +LINEAR B IDEOGRAM VESSEL B216 + +100F0 +LINEAR B IDEOGRAM VESSEL B217 + +100F1 +LINEAR B IDEOGRAM VESSEL B218 + +100F2 +LINEAR B IDEOGRAM VESSEL B219 + +100F3 +LINEAR B IDEOGRAM VESSEL B221 + +100F4 +LINEAR B IDEOGRAM VESSEL B222 + +100F5 +LINEAR B IDEOGRAM VESSEL B226 + +100F6 +LINEAR B IDEOGRAM VESSEL B227 + +100F7 +LINEAR B IDEOGRAM VESSEL B228 + +100F8 +LINEAR B IDEOGRAM VESSEL B229 + +100F9 +LINEAR B IDEOGRAM VESSEL B250 + +100FA +LINEAR B IDEOGRAM VESSEL B305 + +10100 +AEGEAN WORD SEPARATOR LINE + +10101 +AEGEAN WORD SEPARATOR DOT + +10102 +AEGEAN CHECK MARK + +10107 +AEGEAN NUMBER ONE + +10108 +AEGEAN NUMBER TWO + +10109 +AEGEAN NUMBER THREE + +1010A +AEGEAN NUMBER FOUR + +1010B +AEGEAN NUMBER FIVE + +1010C +AEGEAN NUMBER SIX + +1010D +AEGEAN NUMBER SEVEN + +1010E +AEGEAN NUMBER EIGHT + +1010F +AEGEAN NUMBER NINE + +10110 +AEGEAN NUMBER TEN + +10111 +AEGEAN NUMBER TWENTY + +10112 +AEGEAN NUMBER THIRTY + +10113 +AEGEAN NUMBER FORTY + +10114 +AEGEAN NUMBER FIFTY + +10115 +AEGEAN NUMBER SIXTY + +10116 +AEGEAN NUMBER SEVENTY + +10117 +AEGEAN NUMBER EIGHTY + +10118 +AEGEAN NUMBER NINETY + +10119 +AEGEAN NUMBER ONE HUNDRED + +1011A +AEGEAN NUMBER TWO HUNDRED + +1011B +AEGEAN NUMBER THREE HUNDRED + +1011C +AEGEAN NUMBER FOUR HUNDRED + +1011D +AEGEAN NUMBER FIVE HUNDRED + +1011E +AEGEAN NUMBER SIX HUNDRED + +1011F +AEGEAN NUMBER SEVEN HUNDRED + +10120 +AEGEAN NUMBER EIGHT HUNDRED + +10121 +AEGEAN NUMBER NINE HUNDRED + +10122 +AEGEAN NUMBER ONE THOUSAND + +10123 +AEGEAN NUMBER TWO THOUSAND + +10124 +AEGEAN NUMBER THREE THOUSAND + +10125 +AEGEAN NUMBER FOUR THOUSAND + +10126 +AEGEAN NUMBER FIVE THOUSAND + +10127 +AEGEAN NUMBER SIX THOUSAND + +10128 +AEGEAN NUMBER SEVEN THOUSAND + +10129 +AEGEAN NUMBER EIGHT THOUSAND + +1012A +AEGEAN NUMBER NINE THOUSAND + +1012B +AEGEAN NUMBER TEN THOUSAND + +1012C +AEGEAN NUMBER TWENTY THOUSAND + +1012D +AEGEAN NUMBER THIRTY THOUSAND + +1012E +AEGEAN NUMBER FORTY THOUSAND + +1012F +AEGEAN NUMBER FIFTY THOUSAND + +10130 +AEGEAN NUMBER SIXTY THOUSAND + +10131 +AEGEAN NUMBER SEVENTY THOUSAND + +10132 +AEGEAN NUMBER EIGHTY THOUSAND + +10133 +AEGEAN NUMBER NINETY THOUSAND + +10137 +AEGEAN WEIGHT BASE UNIT + +10138 +AEGEAN WEIGHT FIRST SUBUNIT + +10139 +AEGEAN WEIGHT SECOND SUBUNIT + +1013A +AEGEAN WEIGHT THIRD SUBUNIT + +1013B +AEGEAN WEIGHT FOURTH SUBUNIT + +1013C +AEGEAN DRY MEASURE FIRST SUBUNIT + +1013D +AEGEAN LIQUID MEASURE FIRST SUBUNIT + +1013E +AEGEAN MEASURE SECOND SUBUNIT + +1013F +AEGEAN MEASURE THIRD SUBUNIT + +10140 +GREEK ACROPHONIC ATTIC ONE QUARTER + +10141 +GREEK ACROPHONIC ATTIC ONE HALF + +10142 +GREEK ACROPHONIC ATTIC ONE DRACHMA + +10143 +GREEK ACROPHONIC ATTIC FIVE + +10144 +GREEK ACROPHONIC ATTIC FIFTY + +10145 +GREEK ACROPHONIC ATTIC FIVE HUNDRED + +10146 +GREEK ACROPHONIC ATTIC FIVE THOUSAND + +10147 +GREEK ACROPHONIC ATTIC FIFTY THOUSAND + +10148 +GREEK ACROPHONIC ATTIC FIVE TALENTS + +10149 +GREEK ACROPHONIC ATTIC TEN TALENTS + +1014A +GREEK ACROPHONIC ATTIC FIFTY TALENTS + +1014B +GREEK ACROPHONIC ATTIC ONE HUNDRED TALENTS + +1014C +GREEK ACROPHONIC ATTIC FIVE HUNDRED TALENTS + +1014D +GREEK ACROPHONIC ATTIC ONE THOUSAND TALENTS + +1014E +GREEK ACROPHONIC ATTIC FIVE THOUSAND TALENTS + +1014F +GREEK ACROPHONIC ATTIC FIVE STATERS + +10150 +GREEK ACROPHONIC ATTIC TEN STATERS + +10151 +GREEK ACROPHONIC ATTIC FIFTY STATERS + +10152 +GREEK ACROPHONIC ATTIC ONE HUNDRED STATERS + +10153 +GREEK ACROPHONIC ATTIC FIVE HUNDRED STATERS + +10154 +GREEK ACROPHONIC ATTIC ONE THOUSAND STATERS + +10155 +GREEK ACROPHONIC ATTIC TEN THOUSAND STATERS + +10156 +GREEK ACROPHONIC ATTIC FIFTY THOUSAND STATERS + +10157 +GREEK ACROPHONIC ATTIC TEN MNAS + +10158 +GREEK ACROPHONIC HERAEUM ONE PLETHRON + +10159 +GREEK ACROPHONIC THESPIAN ONE + +1015A +GREEK ACROPHONIC HERMIONIAN ONE + +1015B +GREEK ACROPHONIC EPIDAUREAN TWO + +1015C +GREEK ACROPHONIC THESPIAN TWO + +1015D +GREEK ACROPHONIC CYRENAIC TWO DRACHMAS + +1015E +GREEK ACROPHONIC EPIDAUREAN TWO DRACHMAS + +1015F +GREEK ACROPHONIC TROEZENIAN FIVE + +10160 +GREEK ACROPHONIC TROEZENIAN TEN + +10161 +GREEK ACROPHONIC TROEZENIAN TEN ALTERNATE FORM + +10162 +GREEK ACROPHONIC HERMIONIAN TEN + +10163 +GREEK ACROPHONIC MESSENIAN TEN + +10164 +GREEK ACROPHONIC THESPIAN TEN + +10165 +GREEK ACROPHONIC THESPIAN THIRTY + +10166 +GREEK ACROPHONIC TROEZENIAN FIFTY + +10167 +GREEK ACROPHONIC TROEZENIAN FIFTY ALTERNATE FORM + +10168 +GREEK ACROPHONIC HERMIONIAN FIFTY + +10169 +GREEK ACROPHONIC THESPIAN FIFTY + +1016A +GREEK ACROPHONIC THESPIAN ONE HUNDRED + +1016B +GREEK ACROPHONIC THESPIAN THREE HUNDRED + +1016C +GREEK ACROPHONIC EPIDAUREAN FIVE HUNDRED + +1016D +GREEK ACROPHONIC TROEZENIAN FIVE HUNDRED + +1016E +GREEK ACROPHONIC THESPIAN FIVE HUNDRED + +1016F +GREEK ACROPHONIC CARYSTIAN FIVE HUNDRED + +10170 +GREEK ACROPHONIC NAXIAN FIVE HUNDRED + +10171 +GREEK ACROPHONIC THESPIAN ONE THOUSAND + +10172 +GREEK ACROPHONIC THESPIAN FIVE THOUSAND + +10173 +GREEK ACROPHONIC DELPHIC FIVE MNAS + +10174 +GREEK ACROPHONIC STRATIAN FIFTY MNAS + +10175 +GREEK ONE HALF SIGN + +10176 +GREEK ONE HALF SIGN ALTERNATE FORM + +10177 +GREEK TWO THIRDS SIGN + +10178 +GREEK THREE QUARTERS SIGN + +10179 +GREEK YEAR SIGN + +1017A +GREEK TALENT SIGN + +1017B +GREEK DRACHMA SIGN + +1017C +GREEK OBOL SIGN + +1017D +GREEK TWO OBOLS SIGN + +1017E +GREEK THREE OBOLS SIGN + +1017F +GREEK FOUR OBOLS SIGN + +10180 +GREEK FIVE OBOLS SIGN + +10181 +GREEK METRETES SIGN + +10182 +GREEK KYATHOS BASE SIGN + +10183 +GREEK LITRA SIGN + +10184 +GREEK OUNKIA SIGN + +10185 +GREEK XESTES SIGN + +10186 +GREEK ARTABE SIGN + +10187 +GREEK AROURA SIGN + +10188 +GREEK GRAMMA SIGN + +10189 +GREEK TRYBLION BASE SIGN + +1018A +GREEK ZERO SIGN + +1018B +GREEK ONE QUARTER SIGN + +1018C +GREEK SINUSOID SIGN + +1018D +GREEK INDICTION SIGN + +1018E +NOMISMA SIGN + +10190 +ROMAN SEXTANS SIGN + +10191 +ROMAN UNCIA SIGN + +10192 +ROMAN SEMUNCIA SIGN + +10193 +ROMAN SEXTULA SIGN + +10194 +ROMAN DIMIDIA SEXTULA SIGN + +10195 +ROMAN SILIQUA SIGN + +10196 +ROMAN DENARIUS SIGN + +10197 +ROMAN QUINARIUS SIGN + +10198 +ROMAN SESTERTIUS SIGN + +10199 +ROMAN DUPONDIUS SIGN + +1019A +ROMAN AS SIGN + +1019B +ROMAN CENTURIAL SIGN + +1019C +ASCIA SYMBOL + +101A0 +GREEK SYMBOL TAU RHO + +101D0 +PHAISTOS DISC SIGN PEDESTRIAN + +101D1 +PHAISTOS DISC SIGN PLUMED HEAD + +101D2 +PHAISTOS DISC SIGN TATTOOED HEAD + +101D3 +PHAISTOS DISC SIGN CAPTIVE + +101D4 +PHAISTOS DISC SIGN CHILD + +101D5 +PHAISTOS DISC SIGN WOMAN + +101D6 +PHAISTOS DISC SIGN HELMET + +101D7 +PHAISTOS DISC SIGN GAUNTLET + +101D8 +PHAISTOS DISC SIGN TIARA + +101D9 +PHAISTOS DISC SIGN ARROW + +101DA +PHAISTOS DISC SIGN BOW + +101DB +PHAISTOS DISC SIGN SHIELD + +101DC +PHAISTOS DISC SIGN CLUB + +101DD +PHAISTOS DISC SIGN MANACLES + +101DE +PHAISTOS DISC SIGN MATTOCK + +101DF +PHAISTOS DISC SIGN SAW + +101E0 +PHAISTOS DISC SIGN LID + +101E1 +PHAISTOS DISC SIGN BOOMERANG + +101E2 +PHAISTOS DISC SIGN CARPENTRY PLANE + +101E3 +PHAISTOS DISC SIGN DOLIUM + +101E4 +PHAISTOS DISC SIGN COMB + +101E5 +PHAISTOS DISC SIGN SLING + +101E6 +PHAISTOS DISC SIGN COLUMN + +101E7 +PHAISTOS DISC SIGN BEEHIVE + +101E8 +PHAISTOS DISC SIGN SHIP + +101E9 +PHAISTOS DISC SIGN HORN + +101EA +PHAISTOS DISC SIGN HIDE + +101EB +PHAISTOS DISC SIGN BULLS LEG + +101EC +PHAISTOS DISC SIGN CAT + +101ED +PHAISTOS DISC SIGN RAM + +101EE +PHAISTOS DISC SIGN EAGLE + +101EF +PHAISTOS DISC SIGN DOVE + +101F0 +PHAISTOS DISC SIGN TUNNY + +101F1 +PHAISTOS DISC SIGN BEE + +101F2 +PHAISTOS DISC SIGN PLANE TREE + +101F3 +PHAISTOS DISC SIGN VINE + +101F4 +PHAISTOS DISC SIGN PAPYRUS + +101F5 +PHAISTOS DISC SIGN ROSETTE + +101F6 +PHAISTOS DISC SIGN LILY + +101F7 +PHAISTOS DISC SIGN OX BACK + +101F8 +PHAISTOS DISC SIGN FLUTE + +101F9 +PHAISTOS DISC SIGN GRATER + +101FA +PHAISTOS DISC SIGN STRAINER + +101FB +PHAISTOS DISC SIGN SMALL AXE + +101FC +PHAISTOS DISC SIGN WAVY BAND + +101FD +PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE + +10280 +LYCIAN LETTER A + +10281 +LYCIAN LETTER E + +10282 +LYCIAN LETTER B + +10283 +LYCIAN LETTER BH + +10284 +LYCIAN LETTER G + +10285 +LYCIAN LETTER D + +10286 +LYCIAN LETTER I + +10287 +LYCIAN LETTER W + +10288 +LYCIAN LETTER Z + +10289 +LYCIAN LETTER TH + +1028A +LYCIAN LETTER J + +1028B +LYCIAN LETTER K + +1028C +LYCIAN LETTER Q + +1028D +LYCIAN LETTER L + +1028E +LYCIAN LETTER M + +1028F +LYCIAN LETTER N + +10290 +LYCIAN LETTER MM + +10291 +LYCIAN LETTER NN + +10292 +LYCIAN LETTER U + +10293 +LYCIAN LETTER P + +10294 +LYCIAN LETTER KK + +10295 +LYCIAN LETTER R + +10296 +LYCIAN LETTER S + +10297 +LYCIAN LETTER T + +10298 +LYCIAN LETTER TT + +10299 +LYCIAN LETTER AN + +1029A +LYCIAN LETTER EN + +1029B +LYCIAN LETTER H + +1029C +LYCIAN LETTER X + +102A0 +CARIAN LETTER A + +102A1 +CARIAN LETTER P2 + +102A2 +CARIAN LETTER D + +102A3 +CARIAN LETTER L + +102A4 +CARIAN LETTER UUU + +102A5 +CARIAN LETTER R + +102A6 +CARIAN LETTER LD + +102A7 +CARIAN LETTER A2 + +102A8 +CARIAN LETTER Q + +102A9 +CARIAN LETTER B + +102AA +CARIAN LETTER M + +102AB +CARIAN LETTER O + +102AC +CARIAN LETTER D2 + +102AD +CARIAN LETTER T + +102AE +CARIAN LETTER SH + +102AF +CARIAN LETTER SH2 + +102B0 +CARIAN LETTER S + +102B1 +CARIAN LETTER C-18 + +102B2 +CARIAN LETTER U + +102B3 +CARIAN LETTER NN + +102B4 +CARIAN LETTER X + +102B5 +CARIAN LETTER N + +102B6 +CARIAN LETTER TT2 + +102B7 +CARIAN LETTER P + +102B8 +CARIAN LETTER SS + +102B9 +CARIAN LETTER I + +102BA +CARIAN LETTER E + +102BB +CARIAN LETTER UUUU + +102BC +CARIAN LETTER K + +102BD +CARIAN LETTER K2 + +102BE +CARIAN LETTER ND + +102BF +CARIAN LETTER UU + +102C0 +CARIAN LETTER G + +102C1 +CARIAN LETTER G2 + +102C2 +CARIAN LETTER ST + +102C3 +CARIAN LETTER ST2 + +102C4 +CARIAN LETTER NG + +102C5 +CARIAN LETTER II + +102C6 +CARIAN LETTER C-39 + +102C7 +CARIAN LETTER TT + +102C8 +CARIAN LETTER UUU2 + +102C9 +CARIAN LETTER RR + +102CA +CARIAN LETTER MB + +102CB +CARIAN LETTER MB2 + +102CC +CARIAN LETTER MB3 + +102CD +CARIAN LETTER MB4 + +102CE +CARIAN LETTER LD2 + +102CF +CARIAN LETTER E2 + +102D0 +CARIAN LETTER UUU3 + +102E0 +COPTIC EPACT THOUSANDS MARK + +102E1 +COPTIC EPACT DIGIT ONE + +102E2 +COPTIC EPACT DIGIT TWO + +102E3 +COPTIC EPACT DIGIT THREE + +102E4 +COPTIC EPACT DIGIT FOUR + +102E5 +COPTIC EPACT DIGIT FIVE + +102E6 +COPTIC EPACT DIGIT SIX + +102E7 +COPTIC EPACT DIGIT SEVEN + +102E8 +COPTIC EPACT DIGIT EIGHT + +102E9 +COPTIC EPACT DIGIT NINE + +102EA +COPTIC EPACT NUMBER TEN + +102EB +COPTIC EPACT NUMBER TWENTY + +102EC +COPTIC EPACT NUMBER THIRTY + +102ED +COPTIC EPACT NUMBER FORTY + +102EE +COPTIC EPACT NUMBER FIFTY + +102EF +COPTIC EPACT NUMBER SIXTY + +102F0 +COPTIC EPACT NUMBER SEVENTY + +102F1 +COPTIC EPACT NUMBER EIGHTY + +102F2 +COPTIC EPACT NUMBER NINETY + +102F3 +COPTIC EPACT NUMBER ONE HUNDRED + +102F4 +COPTIC EPACT NUMBER TWO HUNDRED + +102F5 +COPTIC EPACT NUMBER THREE HUNDRED + +102F6 +COPTIC EPACT NUMBER FOUR HUNDRED + +102F7 +COPTIC EPACT NUMBER FIVE HUNDRED + +102F8 +COPTIC EPACT NUMBER SIX HUNDRED + +102F9 +COPTIC EPACT NUMBER SEVEN HUNDRED + +102FA +COPTIC EPACT NUMBER EIGHT HUNDRED + +102FB +COPTIC EPACT NUMBER NINE HUNDRED + +10300 +OLD ITALIC LETTER A + +10301 +OLD ITALIC LETTER BE + +10302 +OLD ITALIC LETTER KE + +10303 +OLD ITALIC LETTER DE + +10304 +OLD ITALIC LETTER E + +10305 +OLD ITALIC LETTER VE + +10306 +OLD ITALIC LETTER ZE + +10307 +OLD ITALIC LETTER HE + +10308 +OLD ITALIC LETTER THE + +10309 +OLD ITALIC LETTER I + +1030A +OLD ITALIC LETTER KA + +1030B +OLD ITALIC LETTER EL + +1030C +OLD ITALIC LETTER EM + +1030D +OLD ITALIC LETTER EN + +1030E +OLD ITALIC LETTER ESH + +1030F +OLD ITALIC LETTER O + +10310 +OLD ITALIC LETTER PE + +10311 +OLD ITALIC LETTER SHE + +10312 +OLD ITALIC LETTER KU + +10313 +OLD ITALIC LETTER ER + +10314 +OLD ITALIC LETTER ES + +10315 +OLD ITALIC LETTER TE + +10316 +OLD ITALIC LETTER U + +10317 +OLD ITALIC LETTER EKS + +10318 +OLD ITALIC LETTER PHE + +10319 +OLD ITALIC LETTER KHE + +1031A +OLD ITALIC LETTER EF + +1031B +OLD ITALIC LETTER ERS + +1031C +OLD ITALIC LETTER CHE + +1031D +OLD ITALIC LETTER II + +1031E +OLD ITALIC LETTER UU + +1031F +OLD ITALIC LETTER ESS + +10320 +OLD ITALIC NUMERAL ONE + +10321 +OLD ITALIC NUMERAL FIVE + +10322 +OLD ITALIC NUMERAL TEN + +10323 +OLD ITALIC NUMERAL FIFTY + +1032D +OLD ITALIC LETTER YE + +1032E +OLD ITALIC LETTER NORTHERN TSE + +1032F +OLD ITALIC LETTER SOUTHERN TSE + +10330 +GOTHIC LETTER AHSA + +10331 +GOTHIC LETTER BAIRKAN + +10332 +GOTHIC LETTER GIBA + +10333 +GOTHIC LETTER DAGS + +10334 +GOTHIC LETTER AIHVUS + +10335 +GOTHIC LETTER QAIRTHRA + +10336 +GOTHIC LETTER IUJA + +10337 +GOTHIC LETTER HAGL + +10338 +GOTHIC LETTER THIUTH + +10339 +GOTHIC LETTER EIS + +1033A +GOTHIC LETTER KUSMA + +1033B +GOTHIC LETTER LAGUS + +1033C +GOTHIC LETTER MANNA + +1033D +GOTHIC LETTER NAUTHS + +1033E +GOTHIC LETTER JER + +1033F +GOTHIC LETTER URUS + +10340 +GOTHIC LETTER PAIRTHRA + +10341 +GOTHIC LETTER NINETY + +10342 +GOTHIC LETTER RAIDA + +10343 +GOTHIC LETTER SAUIL + +10344 +GOTHIC LETTER TEIWS + +10345 +GOTHIC LETTER WINJA + +10346 +GOTHIC LETTER FAIHU + +10347 +GOTHIC LETTER IGGWS + +10348 +GOTHIC LETTER HWAIR + +10349 +GOTHIC LETTER OTHAL + +1034A +GOTHIC LETTER NINE HUNDRED + +10350 +OLD PERMIC LETTER AN + +10351 +OLD PERMIC LETTER BUR + +10352 +OLD PERMIC LETTER GAI + +10353 +OLD PERMIC LETTER DOI + +10354 +OLD PERMIC LETTER E + +10355 +OLD PERMIC LETTER ZHOI + +10356 +OLD PERMIC LETTER DZHOI + +10357 +OLD PERMIC LETTER ZATA + +10358 +OLD PERMIC LETTER DZITA + +10359 +OLD PERMIC LETTER I + +1035A +OLD PERMIC LETTER KOKE + +1035B +OLD PERMIC LETTER LEI + +1035C +OLD PERMIC LETTER MENOE + +1035D +OLD PERMIC LETTER NENOE + +1035E +OLD PERMIC LETTER VOOI + +1035F +OLD PERMIC LETTER PEEI + +10360 +OLD PERMIC LETTER REI + +10361 +OLD PERMIC LETTER SII + +10362 +OLD PERMIC LETTER TAI + +10363 +OLD PERMIC LETTER U + +10364 +OLD PERMIC LETTER CHERY + +10365 +OLD PERMIC LETTER SHOOI + +10366 +OLD PERMIC LETTER SHCHOOI + +10367 +OLD PERMIC LETTER YRY + +10368 +OLD PERMIC LETTER YERU + +10369 +OLD PERMIC LETTER O + +1036A +OLD PERMIC LETTER OO + +1036B +OLD PERMIC LETTER EF + +1036C +OLD PERMIC LETTER HA + +1036D +OLD PERMIC LETTER TSIU + +1036E +OLD PERMIC LETTER VER + +1036F +OLD PERMIC LETTER YER + +10370 +OLD PERMIC LETTER YERI + +10371 +OLD PERMIC LETTER YAT + +10372 +OLD PERMIC LETTER IE + +10373 +OLD PERMIC LETTER YU + +10374 +OLD PERMIC LETTER YA + +10375 +OLD PERMIC LETTER IA + +10376 +COMBINING OLD PERMIC LETTER AN + +10377 +COMBINING OLD PERMIC LETTER DOI + +10378 +COMBINING OLD PERMIC LETTER ZATA + +10379 +COMBINING OLD PERMIC LETTER NENOE + +1037A +COMBINING OLD PERMIC LETTER SII + +10380 +UGARITIC LETTER ALPA + +10381 +UGARITIC LETTER BETA + +10382 +UGARITIC LETTER GAMLA + +10383 +UGARITIC LETTER KHA + +10384 +UGARITIC LETTER DELTA + +10385 +UGARITIC LETTER HO + +10386 +UGARITIC LETTER WO + +10387 +UGARITIC LETTER ZETA + +10388 +UGARITIC LETTER HOTA + +10389 +UGARITIC LETTER TET + +1038A +UGARITIC LETTER YOD + +1038B +UGARITIC LETTER KAF + +1038C +UGARITIC LETTER SHIN + +1038D +UGARITIC LETTER LAMDA + +1038E +UGARITIC LETTER MEM + +1038F +UGARITIC LETTER DHAL + +10390 +UGARITIC LETTER NUN + +10391 +UGARITIC LETTER ZU + +10392 +UGARITIC LETTER SAMKA + +10393 +UGARITIC LETTER AIN + +10394 +UGARITIC LETTER PU + +10395 +UGARITIC LETTER SADE + +10396 +UGARITIC LETTER QOPA + +10397 +UGARITIC LETTER RASHA + +10398 +UGARITIC LETTER THANNA + +10399 +UGARITIC LETTER GHAIN + +1039A +UGARITIC LETTER TO + +1039B +UGARITIC LETTER I + +1039C +UGARITIC LETTER U + +1039D +UGARITIC LETTER SSU + +1039F +UGARITIC WORD DIVIDER + +103A0 +OLD PERSIAN SIGN A + +103A1 +OLD PERSIAN SIGN I + +103A2 +OLD PERSIAN SIGN U + +103A3 +OLD PERSIAN SIGN KA + +103A4 +OLD PERSIAN SIGN KU + +103A5 +OLD PERSIAN SIGN GA + +103A6 +OLD PERSIAN SIGN GU + +103A7 +OLD PERSIAN SIGN XA + +103A8 +OLD PERSIAN SIGN CA + +103A9 +OLD PERSIAN SIGN JA + +103AA +OLD PERSIAN SIGN JI + +103AB +OLD PERSIAN SIGN TA + +103AC +OLD PERSIAN SIGN TU + +103AD +OLD PERSIAN SIGN DA + +103AE +OLD PERSIAN SIGN DI + +103AF +OLD PERSIAN SIGN DU + +103B0 +OLD PERSIAN SIGN THA + +103B1 +OLD PERSIAN SIGN PA + +103B2 +OLD PERSIAN SIGN BA + +103B3 +OLD PERSIAN SIGN FA + +103B4 +OLD PERSIAN SIGN NA + +103B5 +OLD PERSIAN SIGN NU + +103B6 +OLD PERSIAN SIGN MA + +103B7 +OLD PERSIAN SIGN MI + +103B8 +OLD PERSIAN SIGN MU + +103B9 +OLD PERSIAN SIGN YA + +103BA +OLD PERSIAN SIGN VA + +103BB +OLD PERSIAN SIGN VI + +103BC +OLD PERSIAN SIGN RA + +103BD +OLD PERSIAN SIGN RU + +103BE +OLD PERSIAN SIGN LA + +103BF +OLD PERSIAN SIGN SA + +103C0 +OLD PERSIAN SIGN ZA + +103C1 +OLD PERSIAN SIGN SHA + +103C2 +OLD PERSIAN SIGN SSA + +103C3 +OLD PERSIAN SIGN HA + +103C8 +OLD PERSIAN SIGN AURAMAZDAA + +103C9 +OLD PERSIAN SIGN AURAMAZDAA-2 + +103CA +OLD PERSIAN SIGN AURAMAZDAAHA + +103CB +OLD PERSIAN SIGN XSHAAYATHIYA + +103CC +OLD PERSIAN SIGN DAHYAAUSH + +103CD +OLD PERSIAN SIGN DAHYAAUSH-2 + +103CE +OLD PERSIAN SIGN BAGA + +103CF +OLD PERSIAN SIGN BUUMISH + +103D0 +OLD PERSIAN WORD DIVIDER + +103D1 +OLD PERSIAN NUMBER ONE + +103D2 +OLD PERSIAN NUMBER TWO + +103D3 +OLD PERSIAN NUMBER TEN + +103D4 +OLD PERSIAN NUMBER TWENTY + +103D5 +OLD PERSIAN NUMBER HUNDRED + +10400 +DESERET CAPITAL LETTER LONG I + +10401 +DESERET CAPITAL LETTER LONG E + +10402 +DESERET CAPITAL LETTER LONG A + +10403 +DESERET CAPITAL LETTER LONG AH + +10404 +DESERET CAPITAL LETTER LONG O + +10405 +DESERET CAPITAL LETTER LONG OO + +10406 +DESERET CAPITAL LETTER SHORT I + +10407 +DESERET CAPITAL LETTER SHORT E + +10408 +DESERET CAPITAL LETTER SHORT A + +10409 +DESERET CAPITAL LETTER SHORT AH + +1040A +DESERET CAPITAL LETTER SHORT O + +1040B +DESERET CAPITAL LETTER SHORT OO + +1040C +DESERET CAPITAL LETTER AY + +1040D +DESERET CAPITAL LETTER OW + +1040E +DESERET CAPITAL LETTER WU + +1040F +DESERET CAPITAL LETTER YEE + +10410 +DESERET CAPITAL LETTER H + +10411 +DESERET CAPITAL LETTER PEE + +10412 +DESERET CAPITAL LETTER BEE + +10413 +DESERET CAPITAL LETTER TEE + +10414 +DESERET CAPITAL LETTER DEE + +10415 +DESERET CAPITAL LETTER CHEE + +10416 +DESERET CAPITAL LETTER JEE + +10417 +DESERET CAPITAL LETTER KAY + +10418 +DESERET CAPITAL LETTER GAY + +10419 +DESERET CAPITAL LETTER EF + +1041A +DESERET CAPITAL LETTER VEE + +1041B +DESERET CAPITAL LETTER ETH + +1041C +DESERET CAPITAL LETTER THEE + +1041D +DESERET CAPITAL LETTER ES + +1041E +DESERET CAPITAL LETTER ZEE + +1041F +DESERET CAPITAL LETTER ESH + +10420 +DESERET CAPITAL LETTER ZHEE + +10421 +DESERET CAPITAL LETTER ER + +10422 +DESERET CAPITAL LETTER EL + +10423 +DESERET CAPITAL LETTER EM + +10424 +DESERET CAPITAL LETTER EN + +10425 +DESERET CAPITAL LETTER ENG + +10426 +DESERET CAPITAL LETTER OI + +10427 +DESERET CAPITAL LETTER EW + +10428 +DESERET SMALL LETTER LONG I + +10429 +DESERET SMALL LETTER LONG E + +1042A +DESERET SMALL LETTER LONG A + +1042B +DESERET SMALL LETTER LONG AH + +1042C +DESERET SMALL LETTER LONG O + +1042D +DESERET SMALL LETTER LONG OO + +1042E +DESERET SMALL LETTER SHORT I + +1042F +DESERET SMALL LETTER SHORT E + +10430 +DESERET SMALL LETTER SHORT A + +10431 +DESERET SMALL LETTER SHORT AH + +10432 +DESERET SMALL LETTER SHORT O + +10433 +DESERET SMALL LETTER SHORT OO + +10434 +DESERET SMALL LETTER AY + +10435 +DESERET SMALL LETTER OW + +10436 +DESERET SMALL LETTER WU + +10437 +DESERET SMALL LETTER YEE + +10438 +DESERET SMALL LETTER H + +10439 +DESERET SMALL LETTER PEE + +1043A +DESERET SMALL LETTER BEE + +1043B +DESERET SMALL LETTER TEE + +1043C +DESERET SMALL LETTER DEE + +1043D +DESERET SMALL LETTER CHEE + +1043E +DESERET SMALL LETTER JEE + +1043F +DESERET SMALL LETTER KAY + +10440 +DESERET SMALL LETTER GAY + +10441 +DESERET SMALL LETTER EF + +10442 +DESERET SMALL LETTER VEE + +10443 +DESERET SMALL LETTER ETH + +10444 +DESERET SMALL LETTER THEE + +10445 +DESERET SMALL LETTER ES + +10446 +DESERET SMALL LETTER ZEE + +10447 +DESERET SMALL LETTER ESH + +10448 +DESERET SMALL LETTER ZHEE + +10449 +DESERET SMALL LETTER ER + +1044A +DESERET SMALL LETTER EL + +1044B +DESERET SMALL LETTER EM + +1044C +DESERET SMALL LETTER EN + +1044D +DESERET SMALL LETTER ENG + +1044E +DESERET SMALL LETTER OI + +1044F +DESERET SMALL LETTER EW + +10450 +SHAVIAN LETTER PEEP + +10451 +SHAVIAN LETTER TOT + +10452 +SHAVIAN LETTER KICK + +10453 +SHAVIAN LETTER FEE + +10454 +SHAVIAN LETTER THIGH + +10455 +SHAVIAN LETTER SO + +10456 +SHAVIAN LETTER SURE + +10457 +SHAVIAN LETTER CHURCH + +10458 +SHAVIAN LETTER YEA + +10459 +SHAVIAN LETTER HUNG + +1045A +SHAVIAN LETTER BIB + +1045B +SHAVIAN LETTER DEAD + +1045C +SHAVIAN LETTER GAG + +1045D +SHAVIAN LETTER VOW + +1045E +SHAVIAN LETTER THEY + +1045F +SHAVIAN LETTER ZOO + +10460 +SHAVIAN LETTER MEASURE + +10461 +SHAVIAN LETTER JUDGE + +10462 +SHAVIAN LETTER WOE + +10463 +SHAVIAN LETTER HA-HA + +10464 +SHAVIAN LETTER LOLL + +10465 +SHAVIAN LETTER MIME + +10466 +SHAVIAN LETTER IF + +10467 +SHAVIAN LETTER EGG + +10468 +SHAVIAN LETTER ASH + +10469 +SHAVIAN LETTER ADO + +1046A +SHAVIAN LETTER ON + +1046B +SHAVIAN LETTER WOOL + +1046C +SHAVIAN LETTER OUT + +1046D +SHAVIAN LETTER AH + +1046E +SHAVIAN LETTER ROAR + +1046F +SHAVIAN LETTER NUN + +10470 +SHAVIAN LETTER EAT + +10471 +SHAVIAN LETTER AGE + +10472 +SHAVIAN LETTER ICE + +10473 +SHAVIAN LETTER UP + +10474 +SHAVIAN LETTER OAK + +10475 +SHAVIAN LETTER OOZE + +10476 +SHAVIAN LETTER OIL + +10477 +SHAVIAN LETTER AWE + +10478 +SHAVIAN LETTER ARE + +10479 +SHAVIAN LETTER OR + +1047A +SHAVIAN LETTER AIR + +1047B +SHAVIAN LETTER ERR + +1047C +SHAVIAN LETTER ARRAY + +1047D +SHAVIAN LETTER EAR + +1047E +SHAVIAN LETTER IAN + +1047F +SHAVIAN LETTER YEW + +10480 +OSMANYA LETTER ALEF + +10481 +OSMANYA LETTER BA + +10482 +OSMANYA LETTER TA + +10483 +OSMANYA LETTER JA + +10484 +OSMANYA LETTER XA + +10485 +OSMANYA LETTER KHA + +10486 +OSMANYA LETTER DEEL + +10487 +OSMANYA LETTER RA + +10488 +OSMANYA LETTER SA + +10489 +OSMANYA LETTER SHIIN + +1048A +OSMANYA LETTER DHA + +1048B +OSMANYA LETTER CAYN + +1048C +OSMANYA LETTER GA + +1048D +OSMANYA LETTER FA + +1048E +OSMANYA LETTER QAAF + +1048F +OSMANYA LETTER KAAF + +10490 +OSMANYA LETTER LAAN + +10491 +OSMANYA LETTER MIIN + +10492 +OSMANYA LETTER NUUN + +10493 +OSMANYA LETTER WAW + +10494 +OSMANYA LETTER HA + +10495 +OSMANYA LETTER YA + +10496 +OSMANYA LETTER A + +10497 +OSMANYA LETTER E + +10498 +OSMANYA LETTER I + +10499 +OSMANYA LETTER O + +1049A +OSMANYA LETTER U + +1049B +OSMANYA LETTER AA + +1049C +OSMANYA LETTER EE + +1049D +OSMANYA LETTER OO + +104A0 +OSMANYA DIGIT ZERO + +104A1 +OSMANYA DIGIT ONE + +104A2 +OSMANYA DIGIT TWO + +104A3 +OSMANYA DIGIT THREE + +104A4 +OSMANYA DIGIT FOUR + +104A5 +OSMANYA DIGIT FIVE + +104A6 +OSMANYA DIGIT SIX + +104A7 +OSMANYA DIGIT SEVEN + +104A8 +OSMANYA DIGIT EIGHT + +104A9 +OSMANYA DIGIT NINE + +104B0 +OSAGE CAPITAL LETTER A + +104B1 +OSAGE CAPITAL LETTER AI + +104B2 +OSAGE CAPITAL LETTER AIN + +104B3 +OSAGE CAPITAL LETTER AH + +104B4 +OSAGE CAPITAL LETTER BRA + +104B5 +OSAGE CAPITAL LETTER CHA + +104B6 +OSAGE CAPITAL LETTER EHCHA + +104B7 +OSAGE CAPITAL LETTER E + +104B8 +OSAGE CAPITAL LETTER EIN + +104B9 +OSAGE CAPITAL LETTER HA + +104BA +OSAGE CAPITAL LETTER HYA + +104BB +OSAGE CAPITAL LETTER I + +104BC +OSAGE CAPITAL LETTER KA + +104BD +OSAGE CAPITAL LETTER EHKA + +104BE +OSAGE CAPITAL LETTER KYA + +104BF +OSAGE CAPITAL LETTER LA + +104C0 +OSAGE CAPITAL LETTER MA + +104C1 +OSAGE CAPITAL LETTER NA + +104C2 +OSAGE CAPITAL LETTER O + +104C3 +OSAGE CAPITAL LETTER OIN + +104C4 +OSAGE CAPITAL LETTER PA + +104C5 +OSAGE CAPITAL LETTER EHPA + +104C6 +OSAGE CAPITAL LETTER SA + +104C7 +OSAGE CAPITAL LETTER SHA + +104C8 +OSAGE CAPITAL LETTER TA + +104C9 +OSAGE CAPITAL LETTER EHTA + +104CA +OSAGE CAPITAL LETTER TSA + +104CB +OSAGE CAPITAL LETTER EHTSA + +104CC +OSAGE CAPITAL LETTER TSHA + +104CD +OSAGE CAPITAL LETTER DHA + +104CE +OSAGE CAPITAL LETTER U + +104CF +OSAGE CAPITAL LETTER WA + +104D0 +OSAGE CAPITAL LETTER KHA + +104D1 +OSAGE CAPITAL LETTER GHA + +104D2 +OSAGE CAPITAL LETTER ZA + +104D3 +OSAGE CAPITAL LETTER ZHA + +104D8 +OSAGE SMALL LETTER A + +104D9 +OSAGE SMALL LETTER AI + +104DA +OSAGE SMALL LETTER AIN + +104DB +OSAGE SMALL LETTER AH + +104DC +OSAGE SMALL LETTER BRA + +104DD +OSAGE SMALL LETTER CHA + +104DE +OSAGE SMALL LETTER EHCHA + +104DF +OSAGE SMALL LETTER E + +104E0 +OSAGE SMALL LETTER EIN + +104E1 +OSAGE SMALL LETTER HA + +104E2 +OSAGE SMALL LETTER HYA + +104E3 +OSAGE SMALL LETTER I + +104E4 +OSAGE SMALL LETTER KA + +104E5 +OSAGE SMALL LETTER EHKA + +104E6 +OSAGE SMALL LETTER KYA + +104E7 +OSAGE SMALL LETTER LA + +104E8 +OSAGE SMALL LETTER MA + +104E9 +OSAGE SMALL LETTER NA + +104EA +OSAGE SMALL LETTER O + +104EB +OSAGE SMALL LETTER OIN + +104EC +OSAGE SMALL LETTER PA + +104ED +OSAGE SMALL LETTER EHPA + +104EE +OSAGE SMALL LETTER SA + +104EF +OSAGE SMALL LETTER SHA + +104F0 +OSAGE SMALL LETTER TA + +104F1 +OSAGE SMALL LETTER EHTA + +104F2 +OSAGE SMALL LETTER TSA + +104F3 +OSAGE SMALL LETTER EHTSA + +104F4 +OSAGE SMALL LETTER TSHA + +104F5 +OSAGE SMALL LETTER DHA + +104F6 +OSAGE SMALL LETTER U + +104F7 +OSAGE SMALL LETTER WA + +104F8 +OSAGE SMALL LETTER KHA + +104F9 +OSAGE SMALL LETTER GHA + +104FA +OSAGE SMALL LETTER ZA + +104FB +OSAGE SMALL LETTER ZHA + +10500 +ELBASAN LETTER A + +10501 +ELBASAN LETTER BE + +10502 +ELBASAN LETTER CE + +10503 +ELBASAN LETTER CHE + +10504 +ELBASAN LETTER DE + +10505 +ELBASAN LETTER NDE + +10506 +ELBASAN LETTER DHE + +10507 +ELBASAN LETTER EI + +10508 +ELBASAN LETTER E + +10509 +ELBASAN LETTER FE + +1050A +ELBASAN LETTER GE + +1050B +ELBASAN LETTER GJE + +1050C +ELBASAN LETTER HE + +1050D +ELBASAN LETTER I + +1050E +ELBASAN LETTER JE + +1050F +ELBASAN LETTER KE + +10510 +ELBASAN LETTER LE + +10511 +ELBASAN LETTER LLE + +10512 +ELBASAN LETTER ME + +10513 +ELBASAN LETTER NE + +10514 +ELBASAN LETTER NA + +10515 +ELBASAN LETTER NJE + +10516 +ELBASAN LETTER O + +10517 +ELBASAN LETTER PE + +10518 +ELBASAN LETTER QE + +10519 +ELBASAN LETTER RE + +1051A +ELBASAN LETTER RRE + +1051B +ELBASAN LETTER SE + +1051C +ELBASAN LETTER SHE + +1051D +ELBASAN LETTER TE + +1051E +ELBASAN LETTER THE + +1051F +ELBASAN LETTER U + +10520 +ELBASAN LETTER VE + +10521 +ELBASAN LETTER XE + +10522 +ELBASAN LETTER Y + +10523 +ELBASAN LETTER ZE + +10524 +ELBASAN LETTER ZHE + +10525 +ELBASAN LETTER GHE + +10526 +ELBASAN LETTER GHAMMA + +10527 +ELBASAN LETTER KHE + +10530 +CAUCASIAN ALBANIAN LETTER ALT + +10531 +CAUCASIAN ALBANIAN LETTER BET + +10532 +CAUCASIAN ALBANIAN LETTER GIM + +10533 +CAUCASIAN ALBANIAN LETTER DAT + +10534 +CAUCASIAN ALBANIAN LETTER EB + +10535 +CAUCASIAN ALBANIAN LETTER ZARL + +10536 +CAUCASIAN ALBANIAN LETTER EYN + +10537 +CAUCASIAN ALBANIAN LETTER ZHIL + +10538 +CAUCASIAN ALBANIAN LETTER TAS + +10539 +CAUCASIAN ALBANIAN LETTER CHA + +1053A +CAUCASIAN ALBANIAN LETTER YOWD + +1053B +CAUCASIAN ALBANIAN LETTER ZHA + +1053C +CAUCASIAN ALBANIAN LETTER IRB + +1053D +CAUCASIAN ALBANIAN LETTER SHA + +1053E +CAUCASIAN ALBANIAN LETTER LAN + +1053F +CAUCASIAN ALBANIAN LETTER INYA + +10540 +CAUCASIAN ALBANIAN LETTER XEYN + +10541 +CAUCASIAN ALBANIAN LETTER DYAN + +10542 +CAUCASIAN ALBANIAN LETTER CAR + +10543 +CAUCASIAN ALBANIAN LETTER JHOX + +10544 +CAUCASIAN ALBANIAN LETTER KAR + +10545 +CAUCASIAN ALBANIAN LETTER LYIT + +10546 +CAUCASIAN ALBANIAN LETTER HEYT + +10547 +CAUCASIAN ALBANIAN LETTER QAY + +10548 +CAUCASIAN ALBANIAN LETTER AOR + +10549 +CAUCASIAN ALBANIAN LETTER CHOY + +1054A +CAUCASIAN ALBANIAN LETTER CHI + +1054B +CAUCASIAN ALBANIAN LETTER CYAY + +1054C +CAUCASIAN ALBANIAN LETTER MAQ + +1054D +CAUCASIAN ALBANIAN LETTER QAR + +1054E +CAUCASIAN ALBANIAN LETTER NOWC + +1054F +CAUCASIAN ALBANIAN LETTER DZYAY + +10550 +CAUCASIAN ALBANIAN LETTER SHAK + +10551 +CAUCASIAN ALBANIAN LETTER JAYN + +10552 +CAUCASIAN ALBANIAN LETTER ON + +10553 +CAUCASIAN ALBANIAN LETTER TYAY + +10554 +CAUCASIAN ALBANIAN LETTER FAM + +10555 +CAUCASIAN ALBANIAN LETTER DZAY + +10556 +CAUCASIAN ALBANIAN LETTER CHAT + +10557 +CAUCASIAN ALBANIAN LETTER PEN + +10558 +CAUCASIAN ALBANIAN LETTER GHEYS + +10559 +CAUCASIAN ALBANIAN LETTER RAT + +1055A +CAUCASIAN ALBANIAN LETTER SEYK + +1055B +CAUCASIAN ALBANIAN LETTER VEYZ + +1055C +CAUCASIAN ALBANIAN LETTER TIWR + +1055D +CAUCASIAN ALBANIAN LETTER SHOY + +1055E +CAUCASIAN ALBANIAN LETTER IWN + +1055F +CAUCASIAN ALBANIAN LETTER CYAW + +10560 +CAUCASIAN ALBANIAN LETTER CAYN + +10561 +CAUCASIAN ALBANIAN LETTER YAYD + +10562 +CAUCASIAN ALBANIAN LETTER PIWR + +10563 +CAUCASIAN ALBANIAN LETTER KIW + +1056F +CAUCASIAN ALBANIAN CITATION MARK + +10570 +VITHKUQI CAPITAL LETTER A + +10571 +VITHKUQI CAPITAL LETTER BBE + +10572 +VITHKUQI CAPITAL LETTER BE + +10573 +VITHKUQI CAPITAL LETTER CE + +10574 +VITHKUQI CAPITAL LETTER CHE + +10575 +VITHKUQI CAPITAL LETTER DE + +10576 +VITHKUQI CAPITAL LETTER DHE + +10577 +VITHKUQI CAPITAL LETTER EI + +10578 +VITHKUQI CAPITAL LETTER E + +10579 +VITHKUQI CAPITAL LETTER FE + +1057A +VITHKUQI CAPITAL LETTER GA + +1057C +VITHKUQI CAPITAL LETTER HA + +1057D +VITHKUQI CAPITAL LETTER HHA + +1057E +VITHKUQI CAPITAL LETTER I + +1057F +VITHKUQI CAPITAL LETTER IJE + +10580 +VITHKUQI CAPITAL LETTER JE + +10581 +VITHKUQI CAPITAL LETTER KA + +10582 +VITHKUQI CAPITAL LETTER LA + +10583 +VITHKUQI CAPITAL LETTER LLA + +10584 +VITHKUQI CAPITAL LETTER ME + +10585 +VITHKUQI CAPITAL LETTER NE + +10586 +VITHKUQI CAPITAL LETTER NJE + +10587 +VITHKUQI CAPITAL LETTER O + +10588 +VITHKUQI CAPITAL LETTER PE + +10589 +VITHKUQI CAPITAL LETTER QA + +1058A +VITHKUQI CAPITAL LETTER RE + +1058C +VITHKUQI CAPITAL LETTER SE + +1058D +VITHKUQI CAPITAL LETTER SHE + +1058E +VITHKUQI CAPITAL LETTER TE + +1058F +VITHKUQI CAPITAL LETTER THE + +10590 +VITHKUQI CAPITAL LETTER U + +10591 +VITHKUQI CAPITAL LETTER VE + +10592 +VITHKUQI CAPITAL LETTER XE + +10594 +VITHKUQI CAPITAL LETTER Y + +10595 +VITHKUQI CAPITAL LETTER ZE + +10597 +VITHKUQI SMALL LETTER A + +10598 +VITHKUQI SMALL LETTER BBE + +10599 +VITHKUQI SMALL LETTER BE + +1059A +VITHKUQI SMALL LETTER CE + +1059B +VITHKUQI SMALL LETTER CHE + +1059C +VITHKUQI SMALL LETTER DE + +1059D +VITHKUQI SMALL LETTER DHE + +1059E +VITHKUQI SMALL LETTER EI + +1059F +VITHKUQI SMALL LETTER E + +105A0 +VITHKUQI SMALL LETTER FE + +105A1 +VITHKUQI SMALL LETTER GA + +105A3 +VITHKUQI SMALL LETTER HA + +105A4 +VITHKUQI SMALL LETTER HHA + +105A5 +VITHKUQI SMALL LETTER I + +105A6 +VITHKUQI SMALL LETTER IJE + +105A7 +VITHKUQI SMALL LETTER JE + +105A8 +VITHKUQI SMALL LETTER KA + +105A9 +VITHKUQI SMALL LETTER LA + +105AA +VITHKUQI SMALL LETTER LLA + +105AB +VITHKUQI SMALL LETTER ME + +105AC +VITHKUQI SMALL LETTER NE + +105AD +VITHKUQI SMALL LETTER NJE + +105AE +VITHKUQI SMALL LETTER O + +105AF +VITHKUQI SMALL LETTER PE + +105B0 +VITHKUQI SMALL LETTER QA + +105B1 +VITHKUQI SMALL LETTER RE + +105B3 +VITHKUQI SMALL LETTER SE + +105B4 +VITHKUQI SMALL LETTER SHE + +105B5 +VITHKUQI SMALL LETTER TE + +105B6 +VITHKUQI SMALL LETTER THE + +105B7 +VITHKUQI SMALL LETTER U + +105B8 +VITHKUQI SMALL LETTER VE + +105B9 +VITHKUQI SMALL LETTER XE + +105BB +VITHKUQI SMALL LETTER Y + +105BC +VITHKUQI SMALL LETTER ZE + +105C0 +TODHRI LETTER A + +105C1 +TODHRI LETTER AS + +105C2 +TODHRI LETTER BA + +105C3 +TODHRI LETTER MBA + +105C4 +TODHRI LETTER CA + +105C5 +TODHRI LETTER CHA + +105C6 +TODHRI LETTER DA + +105C7 +TODHRI LETTER NDA + +105C8 +TODHRI LETTER DHA + +105C9 +TODHRI LETTER EI + +105CA +TODHRI LETTER E + +105CB +TODHRI LETTER FA + +105CC +TODHRI LETTER GA + +105CD +TODHRI LETTER NGA + +105CE +TODHRI LETTER GJA + +105CF +TODHRI LETTER NGJA + +105D0 +TODHRI LETTER HA + +105D1 +TODHRI LETTER HJA + +105D2 +TODHRI LETTER I + +105D3 +TODHRI LETTER JA + +105D4 +TODHRI LETTER KA + +105D5 +TODHRI LETTER LA + +105D6 +TODHRI LETTER LLA + +105D7 +TODHRI LETTER MA + +105D8 +TODHRI LETTER NA + +105D9 +TODHRI LETTER NJAN + +105DA +TODHRI LETTER O + +105DB +TODHRI LETTER PA + +105DC +TODHRI LETTER QA + +105DD +TODHRI LETTER RA + +105DE +TODHRI LETTER RRA + +105DF +TODHRI LETTER SA + +105E0 +TODHRI LETTER SHA + +105E1 +TODHRI LETTER SHTA + +105E2 +TODHRI LETTER TA + +105E3 +TODHRI LETTER THA + +105E4 +TODHRI LETTER U + +105E5 +TODHRI LETTER VA + +105E6 +TODHRI LETTER XA + +105E7 +TODHRI LETTER NXA + +105E8 +TODHRI LETTER XHA + +105E9 +TODHRI LETTER NXHA + +105EA +TODHRI LETTER Y + +105EB +TODHRI LETTER JY + +105EC +TODHRI LETTER ZA + +105ED +TODHRI LETTER ZHA + +105EE +TODHRI LETTER GHA + +105EF +TODHRI LETTER STA + +105F0 +TODHRI LETTER SKAN + +105F1 +TODHRI LETTER KHA + +105F2 +TODHRI LETTER PSA + +105F3 +TODHRI LETTER OO + +10600 +LINEAR A SIGN AB001 + +10601 +LINEAR A SIGN AB002 + +10602 +LINEAR A SIGN AB003 + +10603 +LINEAR A SIGN AB004 + +10604 +LINEAR A SIGN AB005 + +10605 +LINEAR A SIGN AB006 + +10606 +LINEAR A SIGN AB007 + +10607 +LINEAR A SIGN AB008 + +10608 +LINEAR A SIGN AB009 + +10609 +LINEAR A SIGN AB010 + +1060A +LINEAR A SIGN AB011 + +1060B +LINEAR A SIGN AB013 + +1060C +LINEAR A SIGN AB016 + +1060D +LINEAR A SIGN AB017 + +1060E +LINEAR A SIGN AB020 + +1060F +LINEAR A SIGN AB021 + +10610 +LINEAR A SIGN AB021F + +10611 +LINEAR A SIGN AB021M + +10612 +LINEAR A SIGN AB022 + +10613 +LINEAR A SIGN AB022F + +10614 +LINEAR A SIGN AB022M + +10615 +LINEAR A SIGN AB023 + +10616 +LINEAR A SIGN AB023M + +10617 +LINEAR A SIGN AB024 + +10618 +LINEAR A SIGN AB026 + +10619 +LINEAR A SIGN AB027 + +1061A +LINEAR A SIGN AB028 + +1061B +LINEAR A SIGN A028B + +1061C +LINEAR A SIGN AB029 + +1061D +LINEAR A SIGN AB030 + +1061E +LINEAR A SIGN AB031 + +1061F +LINEAR A SIGN AB034 + +10620 +LINEAR A SIGN AB037 + +10621 +LINEAR A SIGN AB038 + +10622 +LINEAR A SIGN AB039 + +10623 +LINEAR A SIGN AB040 + +10624 +LINEAR A SIGN AB041 + +10625 +LINEAR A SIGN AB044 + +10626 +LINEAR A SIGN AB045 + +10627 +LINEAR A SIGN AB046 + +10628 +LINEAR A SIGN AB047 + +10629 +LINEAR A SIGN AB048 + +1062A +LINEAR A SIGN AB049 + +1062B +LINEAR A SIGN AB050 + +1062C +LINEAR A SIGN AB051 + +1062D +LINEAR A SIGN AB053 + +1062E +LINEAR A SIGN AB054 + +1062F +LINEAR A SIGN AB055 + +10630 +LINEAR A SIGN AB056 + +10631 +LINEAR A SIGN AB057 + +10632 +LINEAR A SIGN AB058 + +10633 +LINEAR A SIGN AB059 + +10634 +LINEAR A SIGN AB060 + +10635 +LINEAR A SIGN AB061 + +10636 +LINEAR A SIGN AB065 + +10637 +LINEAR A SIGN AB066 + +10638 +LINEAR A SIGN AB067 + +10639 +LINEAR A SIGN AB069 + +1063A +LINEAR A SIGN AB070 + +1063B +LINEAR A SIGN AB073 + +1063C +LINEAR A SIGN AB074 + +1063D +LINEAR A SIGN AB076 + +1063E +LINEAR A SIGN AB077 + +1063F +LINEAR A SIGN AB078 + +10640 +LINEAR A SIGN AB079 + +10641 +LINEAR A SIGN AB080 + +10642 +LINEAR A SIGN AB081 + +10643 +LINEAR A SIGN AB082 + +10644 +LINEAR A SIGN AB085 + +10645 +LINEAR A SIGN AB086 + +10646 +LINEAR A SIGN AB087 + +10647 +LINEAR A SIGN A100-102 + +10648 +LINEAR A SIGN AB118 + +10649 +LINEAR A SIGN AB120 + +1064A +LINEAR A SIGN A120B + +1064B +LINEAR A SIGN AB122 + +1064C +LINEAR A SIGN AB123 + +1064D +LINEAR A SIGN AB131A + +1064E +LINEAR A SIGN AB131B + +1064F +LINEAR A SIGN A131C + +10650 +LINEAR A SIGN AB164 + +10651 +LINEAR A SIGN AB171 + +10652 +LINEAR A SIGN AB180 + +10653 +LINEAR A SIGN AB188 + +10654 +LINEAR A SIGN AB191 + +10655 +LINEAR A SIGN A301 + +10656 +LINEAR A SIGN A302 + +10657 +LINEAR A SIGN A303 + +10658 +LINEAR A SIGN A304 + +10659 +LINEAR A SIGN A305 + +1065A +LINEAR A SIGN A306 + +1065B +LINEAR A SIGN A307 + +1065C +LINEAR A SIGN A308 + +1065D +LINEAR A SIGN A309A + +1065E +LINEAR A SIGN A309B + +1065F +LINEAR A SIGN A309C + +10660 +LINEAR A SIGN A310 + +10661 +LINEAR A SIGN A311 + +10662 +LINEAR A SIGN A312 + +10663 +LINEAR A SIGN A313A + +10664 +LINEAR A SIGN A313B + +10665 +LINEAR A SIGN A313C + +10666 +LINEAR A SIGN A314 + +10667 +LINEAR A SIGN A315 + +10668 +LINEAR A SIGN A316 + +10669 +LINEAR A SIGN A317 + +1066A +LINEAR A SIGN A318 + +1066B +LINEAR A SIGN A319 + +1066C +LINEAR A SIGN A320 + +1066D +LINEAR A SIGN A321 + +1066E +LINEAR A SIGN A322 + +1066F +LINEAR A SIGN A323 + +10670 +LINEAR A SIGN A324 + +10671 +LINEAR A SIGN A325 + +10672 +LINEAR A SIGN A326 + +10673 +LINEAR A SIGN A327 + +10674 +LINEAR A SIGN A328 + +10675 +LINEAR A SIGN A329 + +10676 +LINEAR A SIGN A330 + +10677 +LINEAR A SIGN A331 + +10678 +LINEAR A SIGN A332 + +10679 +LINEAR A SIGN A333 + +1067A +LINEAR A SIGN A334 + +1067B +LINEAR A SIGN A335 + +1067C +LINEAR A SIGN A336 + +1067D +LINEAR A SIGN A337 + +1067E +LINEAR A SIGN A338 + +1067F +LINEAR A SIGN A339 + +10680 +LINEAR A SIGN A340 + +10681 +LINEAR A SIGN A341 + +10682 +LINEAR A SIGN A342 + +10683 +LINEAR A SIGN A343 + +10684 +LINEAR A SIGN A344 + +10685 +LINEAR A SIGN A345 + +10686 +LINEAR A SIGN A346 + +10687 +LINEAR A SIGN A347 + +10688 +LINEAR A SIGN A348 + +10689 +LINEAR A SIGN A349 + +1068A +LINEAR A SIGN A350 + +1068B +LINEAR A SIGN A351 + +1068C +LINEAR A SIGN A352 + +1068D +LINEAR A SIGN A353 + +1068E +LINEAR A SIGN A354 + +1068F +LINEAR A SIGN A355 + +10690 +LINEAR A SIGN A356 + +10691 +LINEAR A SIGN A357 + +10692 +LINEAR A SIGN A358 + +10693 +LINEAR A SIGN A359 + +10694 +LINEAR A SIGN A360 + +10695 +LINEAR A SIGN A361 + +10696 +LINEAR A SIGN A362 + +10697 +LINEAR A SIGN A363 + +10698 +LINEAR A SIGN A364 + +10699 +LINEAR A SIGN A365 + +1069A +LINEAR A SIGN A366 + +1069B +LINEAR A SIGN A367 + +1069C +LINEAR A SIGN A368 + +1069D +LINEAR A SIGN A369 + +1069E +LINEAR A SIGN A370 + +1069F +LINEAR A SIGN A371 + +106A0 +LINEAR A SIGN A400-VAS + +106A1 +LINEAR A SIGN A401-VAS + +106A2 +LINEAR A SIGN A402-VAS + +106A3 +LINEAR A SIGN A403-VAS + +106A4 +LINEAR A SIGN A404-VAS + +106A5 +LINEAR A SIGN A405-VAS + +106A6 +LINEAR A SIGN A406-VAS + +106A7 +LINEAR A SIGN A407-VAS + +106A8 +LINEAR A SIGN A408-VAS + +106A9 +LINEAR A SIGN A409-VAS + +106AA +LINEAR A SIGN A410-VAS + +106AB +LINEAR A SIGN A411-VAS + +106AC +LINEAR A SIGN A412-VAS + +106AD +LINEAR A SIGN A413-VAS + +106AE +LINEAR A SIGN A414-VAS + +106AF +LINEAR A SIGN A415-VAS + +106B0 +LINEAR A SIGN A416-VAS + +106B1 +LINEAR A SIGN A417-VAS + +106B2 +LINEAR A SIGN A418-VAS + +106B3 +LINEAR A SIGN A501 + +106B4 +LINEAR A SIGN A502 + +106B5 +LINEAR A SIGN A503 + +106B6 +LINEAR A SIGN A504 + +106B7 +LINEAR A SIGN A505 + +106B8 +LINEAR A SIGN A506 + +106B9 +LINEAR A SIGN A508 + +106BA +LINEAR A SIGN A509 + +106BB +LINEAR A SIGN A510 + +106BC +LINEAR A SIGN A511 + +106BD +LINEAR A SIGN A512 + +106BE +LINEAR A SIGN A513 + +106BF +LINEAR A SIGN A515 + +106C0 +LINEAR A SIGN A516 + +106C1 +LINEAR A SIGN A520 + +106C2 +LINEAR A SIGN A521 + +106C3 +LINEAR A SIGN A523 + +106C4 +LINEAR A SIGN A524 + +106C5 +LINEAR A SIGN A525 + +106C6 +LINEAR A SIGN A526 + +106C7 +LINEAR A SIGN A527 + +106C8 +LINEAR A SIGN A528 + +106C9 +LINEAR A SIGN A529 + +106CA +LINEAR A SIGN A530 + +106CB +LINEAR A SIGN A531 + +106CC +LINEAR A SIGN A532 + +106CD +LINEAR A SIGN A534 + +106CE +LINEAR A SIGN A535 + +106CF +LINEAR A SIGN A536 + +106D0 +LINEAR A SIGN A537 + +106D1 +LINEAR A SIGN A538 + +106D2 +LINEAR A SIGN A539 + +106D3 +LINEAR A SIGN A540 + +106D4 +LINEAR A SIGN A541 + +106D5 +LINEAR A SIGN A542 + +106D6 +LINEAR A SIGN A545 + +106D7 +LINEAR A SIGN A547 + +106D8 +LINEAR A SIGN A548 + +106D9 +LINEAR A SIGN A549 + +106DA +LINEAR A SIGN A550 + +106DB +LINEAR A SIGN A551 + +106DC +LINEAR A SIGN A552 + +106DD +LINEAR A SIGN A553 + +106DE +LINEAR A SIGN A554 + +106DF +LINEAR A SIGN A555 + +106E0 +LINEAR A SIGN A556 + +106E1 +LINEAR A SIGN A557 + +106E2 +LINEAR A SIGN A559 + +106E3 +LINEAR A SIGN A563 + +106E4 +LINEAR A SIGN A564 + +106E5 +LINEAR A SIGN A565 + +106E6 +LINEAR A SIGN A566 + +106E7 +LINEAR A SIGN A568 + +106E8 +LINEAR A SIGN A569 + +106E9 +LINEAR A SIGN A570 + +106EA +LINEAR A SIGN A571 + +106EB +LINEAR A SIGN A572 + +106EC +LINEAR A SIGN A573 + +106ED +LINEAR A SIGN A574 + +106EE +LINEAR A SIGN A575 + +106EF +LINEAR A SIGN A576 + +106F0 +LINEAR A SIGN A577 + +106F1 +LINEAR A SIGN A578 + +106F2 +LINEAR A SIGN A579 + +106F3 +LINEAR A SIGN A580 + +106F4 +LINEAR A SIGN A581 + +106F5 +LINEAR A SIGN A582 + +106F6 +LINEAR A SIGN A583 + +106F7 +LINEAR A SIGN A584 + +106F8 +LINEAR A SIGN A585 + +106F9 +LINEAR A SIGN A586 + +106FA +LINEAR A SIGN A587 + +106FB +LINEAR A SIGN A588 + +106FC +LINEAR A SIGN A589 + +106FD +LINEAR A SIGN A591 + +106FE +LINEAR A SIGN A592 + +106FF +LINEAR A SIGN A594 + +10700 +LINEAR A SIGN A595 + +10701 +LINEAR A SIGN A596 + +10702 +LINEAR A SIGN A598 + +10703 +LINEAR A SIGN A600 + +10704 +LINEAR A SIGN A601 + +10705 +LINEAR A SIGN A602 + +10706 +LINEAR A SIGN A603 + +10707 +LINEAR A SIGN A604 + +10708 +LINEAR A SIGN A606 + +10709 +LINEAR A SIGN A608 + +1070A +LINEAR A SIGN A609 + +1070B +LINEAR A SIGN A610 + +1070C +LINEAR A SIGN A611 + +1070D +LINEAR A SIGN A612 + +1070E +LINEAR A SIGN A613 + +1070F +LINEAR A SIGN A614 + +10710 +LINEAR A SIGN A615 + +10711 +LINEAR A SIGN A616 + +10712 +LINEAR A SIGN A617 + +10713 +LINEAR A SIGN A618 + +10714 +LINEAR A SIGN A619 + +10715 +LINEAR A SIGN A620 + +10716 +LINEAR A SIGN A621 + +10717 +LINEAR A SIGN A622 + +10718 +LINEAR A SIGN A623 + +10719 +LINEAR A SIGN A624 + +1071A +LINEAR A SIGN A626 + +1071B +LINEAR A SIGN A627 + +1071C +LINEAR A SIGN A628 + +1071D +LINEAR A SIGN A629 + +1071E +LINEAR A SIGN A634 + +1071F +LINEAR A SIGN A637 + +10720 +LINEAR A SIGN A638 + +10721 +LINEAR A SIGN A640 + +10722 +LINEAR A SIGN A642 + +10723 +LINEAR A SIGN A643 + +10724 +LINEAR A SIGN A644 + +10725 +LINEAR A SIGN A645 + +10726 +LINEAR A SIGN A646 + +10727 +LINEAR A SIGN A648 + +10728 +LINEAR A SIGN A649 + +10729 +LINEAR A SIGN A651 + +1072A +LINEAR A SIGN A652 + +1072B +LINEAR A SIGN A653 + +1072C +LINEAR A SIGN A654 + +1072D +LINEAR A SIGN A655 + +1072E +LINEAR A SIGN A656 + +1072F +LINEAR A SIGN A657 + +10730 +LINEAR A SIGN A658 + +10731 +LINEAR A SIGN A659 + +10732 +LINEAR A SIGN A660 + +10733 +LINEAR A SIGN A661 + +10734 +LINEAR A SIGN A662 + +10735 +LINEAR A SIGN A663 + +10736 +LINEAR A SIGN A664 + +10740 +LINEAR A SIGN A701 A + +10741 +LINEAR A SIGN A702 B + +10742 +LINEAR A SIGN A703 D + +10743 +LINEAR A SIGN A704 E + +10744 +LINEAR A SIGN A705 F + +10745 +LINEAR A SIGN A706 H + +10746 +LINEAR A SIGN A707 J + +10747 +LINEAR A SIGN A708 K + +10748 +LINEAR A SIGN A709 L + +10749 +LINEAR A SIGN A709-2 L2 + +1074A +LINEAR A SIGN A709-3 L3 + +1074B +LINEAR A SIGN A709-4 L4 + +1074C +LINEAR A SIGN A709-6 L6 + +1074D +LINEAR A SIGN A710 W + +1074E +LINEAR A SIGN A711 X + +1074F +LINEAR A SIGN A712 Y + +10750 +LINEAR A SIGN A713 OMEGA + +10751 +LINEAR A SIGN A714 ABB + +10752 +LINEAR A SIGN A715 BB + +10753 +LINEAR A SIGN A717 DD + +10754 +LINEAR A SIGN A726 EYYY + +10755 +LINEAR A SIGN A732 JE + +10760 +LINEAR A SIGN A800 + +10761 +LINEAR A SIGN A801 + +10762 +LINEAR A SIGN A802 + +10763 +LINEAR A SIGN A803 + +10764 +LINEAR A SIGN A804 + +10765 +LINEAR A SIGN A805 + +10766 +LINEAR A SIGN A806 + +10767 +LINEAR A SIGN A807 + +10780 +MODIFIER LETTER SMALL CAPITAL AA + +10781 +MODIFIER LETTER SUPERSCRIPT TRIANGULAR COLON + +10782 +MODIFIER LETTER SUPERSCRIPT HALF TRIANGULAR COLON + +10783 +MODIFIER LETTER SMALL AE + +10784 +MODIFIER LETTER SMALL CAPITAL B + +10785 +MODIFIER LETTER SMALL B WITH HOOK + +10787 +MODIFIER LETTER SMALL DZ DIGRAPH + +10788 +MODIFIER LETTER SMALL DZ DIGRAPH WITH RETROFLEX HOOK + +10789 +MODIFIER LETTER SMALL DZ DIGRAPH WITH CURL + +1078A +MODIFIER LETTER SMALL DEZH DIGRAPH + +1078B +MODIFIER LETTER SMALL D WITH TAIL + +1078C +MODIFIER LETTER SMALL D WITH HOOK + +1078D +MODIFIER LETTER SMALL D WITH HOOK AND TAIL + +1078E +MODIFIER LETTER SMALL REVERSED E + +1078F +MODIFIER LETTER SMALL CLOSED REVERSED OPEN E + +10790 +MODIFIER LETTER SMALL FENG DIGRAPH + +10791 +MODIFIER LETTER SMALL RAMS HORN + +10792 +MODIFIER LETTER SMALL CAPITAL G + +10793 +MODIFIER LETTER SMALL G WITH HOOK + +10794 +MODIFIER LETTER SMALL CAPITAL G WITH HOOK + +10795 +MODIFIER LETTER SMALL H WITH STROKE + +10796 +MODIFIER LETTER SMALL CAPITAL H + +10797 +MODIFIER LETTER SMALL HENG WITH HOOK + +10798 +MODIFIER LETTER SMALL DOTLESS J WITH STROKE AND HOOK + +10799 +MODIFIER LETTER SMALL LS DIGRAPH + +1079A +MODIFIER LETTER SMALL LZ DIGRAPH + +1079B +MODIFIER LETTER SMALL L WITH BELT + +1079C +MODIFIER LETTER SMALL CAPITAL L WITH BELT + +1079D +MODIFIER LETTER SMALL L WITH RETROFLEX HOOK AND BELT + +1079E +MODIFIER LETTER SMALL LEZH + +1079F +MODIFIER LETTER SMALL LEZH WITH RETROFLEX HOOK + +107A0 +MODIFIER LETTER SMALL TURNED Y + +107A1 +MODIFIER LETTER SMALL TURNED Y WITH BELT + +107A2 +MODIFIER LETTER SMALL O WITH STROKE + +107A3 +MODIFIER LETTER SMALL CAPITAL OE + +107A4 +MODIFIER LETTER SMALL CLOSED OMEGA + +107A5 +MODIFIER LETTER SMALL Q + +107A6 +MODIFIER LETTER SMALL TURNED R WITH LONG LEG + +107A7 +MODIFIER LETTER SMALL TURNED R WITH LONG LEG AND RETROFLEX HOOK + +107A8 +MODIFIER LETTER SMALL R WITH TAIL + +107A9 +MODIFIER LETTER SMALL R WITH FISHHOOK + +107AA +MODIFIER LETTER SMALL CAPITAL R + +107AB +MODIFIER LETTER SMALL TC DIGRAPH WITH CURL + +107AC +MODIFIER LETTER SMALL TS DIGRAPH + +107AD +MODIFIER LETTER SMALL TS DIGRAPH WITH RETROFLEX HOOK + +107AE +MODIFIER LETTER SMALL TESH DIGRAPH + +107AF +MODIFIER LETTER SMALL T WITH RETROFLEX HOOK + +107B0 +MODIFIER LETTER SMALL V WITH RIGHT HOOK + +107B2 +MODIFIER LETTER SMALL CAPITAL Y + +107B3 +MODIFIER LETTER GLOTTAL STOP WITH STROKE + +107B4 +MODIFIER LETTER REVERSED GLOTTAL STOP WITH STROKE + +107B5 +MODIFIER LETTER BILABIAL CLICK + +107B6 +MODIFIER LETTER DENTAL CLICK + +107B7 +MODIFIER LETTER LATERAL CLICK + +107B8 +MODIFIER LETTER ALVEOLAR CLICK + +107B9 +MODIFIER LETTER RETROFLEX CLICK WITH RETROFLEX HOOK + +107BA +MODIFIER LETTER SMALL S WITH CURL + +10800 +CYPRIOT SYLLABLE A + +10801 +CYPRIOT SYLLABLE E + +10802 +CYPRIOT SYLLABLE I + +10803 +CYPRIOT SYLLABLE O + +10804 +CYPRIOT SYLLABLE U + +10805 +CYPRIOT SYLLABLE JA + +10808 +CYPRIOT SYLLABLE JO + +1080A +CYPRIOT SYLLABLE KA + +1080B +CYPRIOT SYLLABLE KE + +1080C +CYPRIOT SYLLABLE KI + +1080D +CYPRIOT SYLLABLE KO + +1080E +CYPRIOT SYLLABLE KU + +1080F +CYPRIOT SYLLABLE LA + +10810 +CYPRIOT SYLLABLE LE + +10811 +CYPRIOT SYLLABLE LI + +10812 +CYPRIOT SYLLABLE LO + +10813 +CYPRIOT SYLLABLE LU + +10814 +CYPRIOT SYLLABLE MA + +10815 +CYPRIOT SYLLABLE ME + +10816 +CYPRIOT SYLLABLE MI + +10817 +CYPRIOT SYLLABLE MO + +10818 +CYPRIOT SYLLABLE MU + +10819 +CYPRIOT SYLLABLE NA + +1081A +CYPRIOT SYLLABLE NE + +1081B +CYPRIOT SYLLABLE NI + +1081C +CYPRIOT SYLLABLE NO + +1081D +CYPRIOT SYLLABLE NU + +1081E +CYPRIOT SYLLABLE PA + +1081F +CYPRIOT SYLLABLE PE + +10820 +CYPRIOT SYLLABLE PI + +10821 +CYPRIOT SYLLABLE PO + +10822 +CYPRIOT SYLLABLE PU + +10823 +CYPRIOT SYLLABLE RA + +10824 +CYPRIOT SYLLABLE RE + +10825 +CYPRIOT SYLLABLE RI + +10826 +CYPRIOT SYLLABLE RO + +10827 +CYPRIOT SYLLABLE RU + +10828 +CYPRIOT SYLLABLE SA + +10829 +CYPRIOT SYLLABLE SE + +1082A +CYPRIOT SYLLABLE SI + +1082B +CYPRIOT SYLLABLE SO + +1082C +CYPRIOT SYLLABLE SU + +1082D +CYPRIOT SYLLABLE TA + +1082E +CYPRIOT SYLLABLE TE + +1082F +CYPRIOT SYLLABLE TI + +10830 +CYPRIOT SYLLABLE TO + +10831 +CYPRIOT SYLLABLE TU + +10832 +CYPRIOT SYLLABLE WA + +10833 +CYPRIOT SYLLABLE WE + +10834 +CYPRIOT SYLLABLE WI + +10835 +CYPRIOT SYLLABLE WO + +10837 +CYPRIOT SYLLABLE XA + +10838 +CYPRIOT SYLLABLE XE + +1083C +CYPRIOT SYLLABLE ZA + +1083F +CYPRIOT SYLLABLE ZO + +10840 +IMPERIAL ARAMAIC LETTER ALEPH + +10841 +IMPERIAL ARAMAIC LETTER BETH + +10842 +IMPERIAL ARAMAIC LETTER GIMEL + +10843 +IMPERIAL ARAMAIC LETTER DALETH + +10844 +IMPERIAL ARAMAIC LETTER HE + +10845 +IMPERIAL ARAMAIC LETTER WAW + +10846 +IMPERIAL ARAMAIC LETTER ZAYIN + +10847 +IMPERIAL ARAMAIC LETTER HETH + +10848 +IMPERIAL ARAMAIC LETTER TETH + +10849 +IMPERIAL ARAMAIC LETTER YODH + +1084A +IMPERIAL ARAMAIC LETTER KAPH + +1084B +IMPERIAL ARAMAIC LETTER LAMEDH + +1084C +IMPERIAL ARAMAIC LETTER MEM + +1084D +IMPERIAL ARAMAIC LETTER NUN + +1084E +IMPERIAL ARAMAIC LETTER SAMEKH + +1084F +IMPERIAL ARAMAIC LETTER AYIN + +10850 +IMPERIAL ARAMAIC LETTER PE + +10851 +IMPERIAL ARAMAIC LETTER SADHE + +10852 +IMPERIAL ARAMAIC LETTER QOPH + +10853 +IMPERIAL ARAMAIC LETTER RESH + +10854 +IMPERIAL ARAMAIC LETTER SHIN + +10855 +IMPERIAL ARAMAIC LETTER TAW + +10857 +IMPERIAL ARAMAIC SECTION SIGN + +10858 +IMPERIAL ARAMAIC NUMBER ONE + +10859 +IMPERIAL ARAMAIC NUMBER TWO + +1085A +IMPERIAL ARAMAIC NUMBER THREE + +1085B +IMPERIAL ARAMAIC NUMBER TEN + +1085C +IMPERIAL ARAMAIC NUMBER TWENTY + +1085D +IMPERIAL ARAMAIC NUMBER ONE HUNDRED + +1085E +IMPERIAL ARAMAIC NUMBER ONE THOUSAND + +1085F +IMPERIAL ARAMAIC NUMBER TEN THOUSAND + +10860 +PALMYRENE LETTER ALEPH + +10861 +PALMYRENE LETTER BETH + +10862 +PALMYRENE LETTER GIMEL + +10863 +PALMYRENE LETTER DALETH + +10864 +PALMYRENE LETTER HE + +10865 +PALMYRENE LETTER WAW + +10866 +PALMYRENE LETTER ZAYIN + +10867 +PALMYRENE LETTER HETH + +10868 +PALMYRENE LETTER TETH + +10869 +PALMYRENE LETTER YODH + +1086A +PALMYRENE LETTER KAPH + +1086B +PALMYRENE LETTER LAMEDH + +1086C +PALMYRENE LETTER MEM + +1086D +PALMYRENE LETTER FINAL NUN + +1086E +PALMYRENE LETTER NUN + +1086F +PALMYRENE LETTER SAMEKH + +10870 +PALMYRENE LETTER AYIN + +10871 +PALMYRENE LETTER PE + +10872 +PALMYRENE LETTER SADHE + +10873 +PALMYRENE LETTER QOPH + +10874 +PALMYRENE LETTER RESH + +10875 +PALMYRENE LETTER SHIN + +10876 +PALMYRENE LETTER TAW + +10877 +PALMYRENE LEFT-POINTING FLEURON + +10878 +PALMYRENE RIGHT-POINTING FLEURON + +10879 +PALMYRENE NUMBER ONE + +1087A +PALMYRENE NUMBER TWO + +1087B +PALMYRENE NUMBER THREE + +1087C +PALMYRENE NUMBER FOUR + +1087D +PALMYRENE NUMBER FIVE + +1087E +PALMYRENE NUMBER TEN + +1087F +PALMYRENE NUMBER TWENTY + +10880 +NABATAEAN LETTER FINAL ALEPH + +10881 +NABATAEAN LETTER ALEPH + +10882 +NABATAEAN LETTER FINAL BETH + +10883 +NABATAEAN LETTER BETH + +10884 +NABATAEAN LETTER GIMEL + +10885 +NABATAEAN LETTER DALETH + +10886 +NABATAEAN LETTER FINAL HE + +10887 +NABATAEAN LETTER HE + +10888 +NABATAEAN LETTER WAW + +10889 +NABATAEAN LETTER ZAYIN + +1088A +NABATAEAN LETTER HETH + +1088B +NABATAEAN LETTER TETH + +1088C +NABATAEAN LETTER FINAL YODH + +1088D +NABATAEAN LETTER YODH + +1088E +NABATAEAN LETTER FINAL KAPH + +1088F +NABATAEAN LETTER KAPH + +10890 +NABATAEAN LETTER FINAL LAMEDH + +10891 +NABATAEAN LETTER LAMEDH + +10892 +NABATAEAN LETTER FINAL MEM + +10893 +NABATAEAN LETTER MEM + +10894 +NABATAEAN LETTER FINAL NUN + +10895 +NABATAEAN LETTER NUN + +10896 +NABATAEAN LETTER SAMEKH + +10897 +NABATAEAN LETTER AYIN + +10898 +NABATAEAN LETTER PE + +10899 +NABATAEAN LETTER SADHE + +1089A +NABATAEAN LETTER QOPH + +1089B +NABATAEAN LETTER RESH + +1089C +NABATAEAN LETTER FINAL SHIN + +1089D +NABATAEAN LETTER SHIN + +1089E +NABATAEAN LETTER TAW + +108A7 +NABATAEAN NUMBER ONE + +108A8 +NABATAEAN NUMBER TWO + +108A9 +NABATAEAN NUMBER THREE + +108AA +NABATAEAN NUMBER FOUR + +108AB +NABATAEAN CRUCIFORM NUMBER FOUR + +108AC +NABATAEAN NUMBER FIVE + +108AD +NABATAEAN NUMBER TEN + +108AE +NABATAEAN NUMBER TWENTY + +108AF +NABATAEAN NUMBER ONE HUNDRED + +108E0 +HATRAN LETTER ALEPH + +108E1 +HATRAN LETTER BETH + +108E2 +HATRAN LETTER GIMEL + +108E3 +HATRAN LETTER DALETH-RESH + +108E4 +HATRAN LETTER HE + +108E5 +HATRAN LETTER WAW + +108E6 +HATRAN LETTER ZAYN + +108E7 +HATRAN LETTER HETH + +108E8 +HATRAN LETTER TETH + +108E9 +HATRAN LETTER YODH + +108EA +HATRAN LETTER KAPH + +108EB +HATRAN LETTER LAMEDH + +108EC +HATRAN LETTER MEM + +108ED +HATRAN LETTER NUN + +108EE +HATRAN LETTER SAMEKH + +108EF +HATRAN LETTER AYN + +108F0 +HATRAN LETTER PE + +108F1 +HATRAN LETTER SADHE + +108F2 +HATRAN LETTER QOPH + +108F4 +HATRAN LETTER SHIN + +108F5 +HATRAN LETTER TAW + +108FB +HATRAN NUMBER ONE + +108FC +HATRAN NUMBER FIVE + +108FD +HATRAN NUMBER TEN + +108FE +HATRAN NUMBER TWENTY + +108FF +HATRAN NUMBER ONE HUNDRED + +10900 +PHOENICIAN LETTER ALF + +10901 +PHOENICIAN LETTER BET + +10902 +PHOENICIAN LETTER GAML + +10903 +PHOENICIAN LETTER DELT + +10904 +PHOENICIAN LETTER HE + +10905 +PHOENICIAN LETTER WAU + +10906 +PHOENICIAN LETTER ZAI + +10907 +PHOENICIAN LETTER HET + +10908 +PHOENICIAN LETTER TET + +10909 +PHOENICIAN LETTER YOD + +1090A +PHOENICIAN LETTER KAF + +1090B +PHOENICIAN LETTER LAMD + +1090C +PHOENICIAN LETTER MEM + +1090D +PHOENICIAN LETTER NUN + +1090E +PHOENICIAN LETTER SEMK + +1090F +PHOENICIAN LETTER AIN + +10910 +PHOENICIAN LETTER PE + +10911 +PHOENICIAN LETTER SADE + +10912 +PHOENICIAN LETTER QOF + +10913 +PHOENICIAN LETTER ROSH + +10914 +PHOENICIAN LETTER SHIN + +10915 +PHOENICIAN LETTER TAU + +10916 +PHOENICIAN NUMBER ONE + +10917 +PHOENICIAN NUMBER TEN + +10918 +PHOENICIAN NUMBER TWENTY + +10919 +PHOENICIAN NUMBER ONE HUNDRED + +1091A +PHOENICIAN NUMBER TWO + +1091B +PHOENICIAN NUMBER THREE + +1091F +PHOENICIAN WORD SEPARATOR + +10920 +LYDIAN LETTER A + +10921 +LYDIAN LETTER B + +10922 +LYDIAN LETTER G + +10923 +LYDIAN LETTER D + +10924 +LYDIAN LETTER E + +10925 +LYDIAN LETTER V + +10926 +LYDIAN LETTER I + +10927 +LYDIAN LETTER Y + +10928 +LYDIAN LETTER K + +10929 +LYDIAN LETTER L + +1092A +LYDIAN LETTER M + +1092B +LYDIAN LETTER N + +1092C +LYDIAN LETTER O + +1092D +LYDIAN LETTER R + +1092E +LYDIAN LETTER SS + +1092F +LYDIAN LETTER T + +10930 +LYDIAN LETTER U + +10931 +LYDIAN LETTER F + +10932 +LYDIAN LETTER Q + +10933 +LYDIAN LETTER S + +10934 +LYDIAN LETTER TT + +10935 +LYDIAN LETTER AN + +10936 +LYDIAN LETTER EN + +10937 +LYDIAN LETTER LY + +10938 +LYDIAN LETTER NN + +10939 +LYDIAN LETTER C + +1093F +LYDIAN TRIANGULAR MARK + +10940 +SIDETIC LETTER N01 + +10941 +SIDETIC LETTER N02 + +10942 +SIDETIC LETTER N03 + +10943 +SIDETIC LETTER N04 + +10944 +SIDETIC LETTER N05 + +10945 +SIDETIC LETTER N06 + +10946 +SIDETIC LETTER N07 + +10947 +SIDETIC LETTER N08 + +10948 +SIDETIC LETTER N09 + +10949 +SIDETIC LETTER N10 + +1094A +SIDETIC LETTER N11 + +1094B +SIDETIC LETTER N12 + +1094C +SIDETIC LETTER N13 + +1094D +SIDETIC LETTER N14 + +1094E +SIDETIC LETTER N15 + +1094F +SIDETIC LETTER N16 + +10950 +SIDETIC LETTER N17 + +10951 +SIDETIC LETTER N18 + +10952 +SIDETIC LETTER N19 + +10953 +SIDETIC LETTER N20 + +10954 +SIDETIC LETTER N21 + +10955 +SIDETIC LETTER N22 + +10956 +SIDETIC LETTER N23 + +10957 +SIDETIC LETTER N24 + +10958 +SIDETIC LETTER N25 + +10959 +SIDETIC LETTER N26 + +10980 +MEROITIC HIEROGLYPHIC LETTER A + +10981 +MEROITIC HIEROGLYPHIC LETTER E + +10982 +MEROITIC HIEROGLYPHIC LETTER I + +10983 +MEROITIC HIEROGLYPHIC LETTER O + +10984 +MEROITIC HIEROGLYPHIC LETTER YA + +10985 +MEROITIC HIEROGLYPHIC LETTER WA + +10986 +MEROITIC HIEROGLYPHIC LETTER BA + +10987 +MEROITIC HIEROGLYPHIC LETTER BA-2 + +10988 +MEROITIC HIEROGLYPHIC LETTER PA + +10989 +MEROITIC HIEROGLYPHIC LETTER MA + +1098A +MEROITIC HIEROGLYPHIC LETTER NA + +1098B +MEROITIC HIEROGLYPHIC LETTER NA-2 + +1098C +MEROITIC HIEROGLYPHIC LETTER NE + +1098D +MEROITIC HIEROGLYPHIC LETTER NE-2 + +1098E +MEROITIC HIEROGLYPHIC LETTER RA + +1098F +MEROITIC HIEROGLYPHIC LETTER RA-2 + +10990 +MEROITIC HIEROGLYPHIC LETTER LA + +10991 +MEROITIC HIEROGLYPHIC LETTER KHA + +10992 +MEROITIC HIEROGLYPHIC LETTER HHA + +10993 +MEROITIC HIEROGLYPHIC LETTER SA + +10994 +MEROITIC HIEROGLYPHIC LETTER SA-2 + +10995 +MEROITIC HIEROGLYPHIC LETTER SE + +10996 +MEROITIC HIEROGLYPHIC LETTER KA + +10997 +MEROITIC HIEROGLYPHIC LETTER QA + +10998 +MEROITIC HIEROGLYPHIC LETTER TA + +10999 +MEROITIC HIEROGLYPHIC LETTER TA-2 + +1099A +MEROITIC HIEROGLYPHIC LETTER TE + +1099B +MEROITIC HIEROGLYPHIC LETTER TE-2 + +1099C +MEROITIC HIEROGLYPHIC LETTER TO + +1099D +MEROITIC HIEROGLYPHIC LETTER DA + +1099E +MEROITIC HIEROGLYPHIC SYMBOL VIDJ + +1099F +MEROITIC HIEROGLYPHIC SYMBOL VIDJ-2 + +109A0 +MEROITIC CURSIVE LETTER A + +109A1 +MEROITIC CURSIVE LETTER E + +109A2 +MEROITIC CURSIVE LETTER I + +109A3 +MEROITIC CURSIVE LETTER O + +109A4 +MEROITIC CURSIVE LETTER YA + +109A5 +MEROITIC CURSIVE LETTER WA + +109A6 +MEROITIC CURSIVE LETTER BA + +109A7 +MEROITIC CURSIVE LETTER PA + +109A8 +MEROITIC CURSIVE LETTER MA + +109A9 +MEROITIC CURSIVE LETTER NA + +109AA +MEROITIC CURSIVE LETTER NE + +109AB +MEROITIC CURSIVE LETTER RA + +109AC +MEROITIC CURSIVE LETTER LA + +109AD +MEROITIC CURSIVE LETTER KHA + +109AE +MEROITIC CURSIVE LETTER HHA + +109AF +MEROITIC CURSIVE LETTER SA + +109B0 +MEROITIC CURSIVE LETTER ARCHAIC SA + +109B1 +MEROITIC CURSIVE LETTER SE + +109B2 +MEROITIC CURSIVE LETTER KA + +109B3 +MEROITIC CURSIVE LETTER QA + +109B4 +MEROITIC CURSIVE LETTER TA + +109B5 +MEROITIC CURSIVE LETTER TE + +109B6 +MEROITIC CURSIVE LETTER TO + +109B7 +MEROITIC CURSIVE LETTER DA + +109BC +MEROITIC CURSIVE FRACTION ELEVEN TWELFTHS + +109BD +MEROITIC CURSIVE FRACTION ONE HALF + +109BE +MEROITIC CURSIVE LOGOGRAM RMT + +109BF +MEROITIC CURSIVE LOGOGRAM IMN + +109C0 +MEROITIC CURSIVE NUMBER ONE + +109C1 +MEROITIC CURSIVE NUMBER TWO + +109C2 +MEROITIC CURSIVE NUMBER THREE + +109C3 +MEROITIC CURSIVE NUMBER FOUR + +109C4 +MEROITIC CURSIVE NUMBER FIVE + +109C5 +MEROITIC CURSIVE NUMBER SIX + +109C6 +MEROITIC CURSIVE NUMBER SEVEN + +109C7 +MEROITIC CURSIVE NUMBER EIGHT + +109C8 +MEROITIC CURSIVE NUMBER NINE + +109C9 +MEROITIC CURSIVE NUMBER TEN + +109CA +MEROITIC CURSIVE NUMBER TWENTY + +109CB +MEROITIC CURSIVE NUMBER THIRTY + +109CC +MEROITIC CURSIVE NUMBER FORTY + +109CD +MEROITIC CURSIVE NUMBER FIFTY + +109CE +MEROITIC CURSIVE NUMBER SIXTY + +109CF +MEROITIC CURSIVE NUMBER SEVENTY + +109D2 +MEROITIC CURSIVE NUMBER ONE HUNDRED + +109D3 +MEROITIC CURSIVE NUMBER TWO HUNDRED + +109D4 +MEROITIC CURSIVE NUMBER THREE HUNDRED + +109D5 +MEROITIC CURSIVE NUMBER FOUR HUNDRED + +109D6 +MEROITIC CURSIVE NUMBER FIVE HUNDRED + +109D7 +MEROITIC CURSIVE NUMBER SIX HUNDRED + +109D8 +MEROITIC CURSIVE NUMBER SEVEN HUNDRED + +109D9 +MEROITIC CURSIVE NUMBER EIGHT HUNDRED + +109DA +MEROITIC CURSIVE NUMBER NINE HUNDRED + +109DB +MEROITIC CURSIVE NUMBER ONE THOUSAND + +109DC +MEROITIC CURSIVE NUMBER TWO THOUSAND + +109DD +MEROITIC CURSIVE NUMBER THREE THOUSAND + +109DE +MEROITIC CURSIVE NUMBER FOUR THOUSAND + +109DF +MEROITIC CURSIVE NUMBER FIVE THOUSAND + +109E0 +MEROITIC CURSIVE NUMBER SIX THOUSAND + +109E1 +MEROITIC CURSIVE NUMBER SEVEN THOUSAND + +109E2 +MEROITIC CURSIVE NUMBER EIGHT THOUSAND + +109E3 +MEROITIC CURSIVE NUMBER NINE THOUSAND + +109E4 +MEROITIC CURSIVE NUMBER TEN THOUSAND + +109E5 +MEROITIC CURSIVE NUMBER TWENTY THOUSAND + +109E6 +MEROITIC CURSIVE NUMBER THIRTY THOUSAND + +109E7 +MEROITIC CURSIVE NUMBER FORTY THOUSAND + +109E8 +MEROITIC CURSIVE NUMBER FIFTY THOUSAND + +109E9 +MEROITIC CURSIVE NUMBER SIXTY THOUSAND + +109EA +MEROITIC CURSIVE NUMBER SEVENTY THOUSAND + +109EB +MEROITIC CURSIVE NUMBER EIGHTY THOUSAND + +109EC +MEROITIC CURSIVE NUMBER NINETY THOUSAND + +109ED +MEROITIC CURSIVE NUMBER ONE HUNDRED THOUSAND + +109EE +MEROITIC CURSIVE NUMBER TWO HUNDRED THOUSAND + +109EF +MEROITIC CURSIVE NUMBER THREE HUNDRED THOUSAND + +109F0 +MEROITIC CURSIVE NUMBER FOUR HUNDRED THOUSAND + +109F1 +MEROITIC CURSIVE NUMBER FIVE HUNDRED THOUSAND + +109F2 +MEROITIC CURSIVE NUMBER SIX HUNDRED THOUSAND + +109F3 +MEROITIC CURSIVE NUMBER SEVEN HUNDRED THOUSAND + +109F4 +MEROITIC CURSIVE NUMBER EIGHT HUNDRED THOUSAND + +109F5 +MEROITIC CURSIVE NUMBER NINE HUNDRED THOUSAND + +109F6 +MEROITIC CURSIVE FRACTION ONE TWELFTH + +109F7 +MEROITIC CURSIVE FRACTION TWO TWELFTHS + +109F8 +MEROITIC CURSIVE FRACTION THREE TWELFTHS + +109F9 +MEROITIC CURSIVE FRACTION FOUR TWELFTHS + +109FA +MEROITIC CURSIVE FRACTION FIVE TWELFTHS + +109FB +MEROITIC CURSIVE FRACTION SIX TWELFTHS + +109FC +MEROITIC CURSIVE FRACTION SEVEN TWELFTHS + +109FD +MEROITIC CURSIVE FRACTION EIGHT TWELFTHS + +109FE +MEROITIC CURSIVE FRACTION NINE TWELFTHS + +109FF +MEROITIC CURSIVE FRACTION TEN TWELFTHS + +10A00 +KHAROSHTHI LETTER A + +10A01 +KHAROSHTHI VOWEL SIGN I + +10A02 +KHAROSHTHI VOWEL SIGN U + +10A03 +KHAROSHTHI VOWEL SIGN VOCALIC R + +10A05 +KHAROSHTHI VOWEL SIGN E + +10A06 +KHAROSHTHI VOWEL SIGN O + +10A0C +KHAROSHTHI VOWEL LENGTH MARK + +10A0D +KHAROSHTHI SIGN DOUBLE RING BELOW + +10A0E +KHAROSHTHI SIGN ANUSVARA + +10A0F +KHAROSHTHI SIGN VISARGA + +10A10 +KHAROSHTHI LETTER KA + +10A11 +KHAROSHTHI LETTER KHA + +10A12 +KHAROSHTHI LETTER GA + +10A13 +KHAROSHTHI LETTER GHA + +10A15 +KHAROSHTHI LETTER CA + +10A16 +KHAROSHTHI LETTER CHA + +10A17 +KHAROSHTHI LETTER JA + +10A19 +KHAROSHTHI LETTER NYA + +10A1A +KHAROSHTHI LETTER TTA + +10A1B +KHAROSHTHI LETTER TTHA + +10A1C +KHAROSHTHI LETTER DDA + +10A1D +KHAROSHTHI LETTER DDHA + +10A1E +KHAROSHTHI LETTER NNA + +10A1F +KHAROSHTHI LETTER TA + +10A20 +KHAROSHTHI LETTER THA + +10A21 +KHAROSHTHI LETTER DA + +10A22 +KHAROSHTHI LETTER DHA + +10A23 +KHAROSHTHI LETTER NA + +10A24 +KHAROSHTHI LETTER PA + +10A25 +KHAROSHTHI LETTER PHA + +10A26 +KHAROSHTHI LETTER BA + +10A27 +KHAROSHTHI LETTER BHA + +10A28 +KHAROSHTHI LETTER MA + +10A29 +KHAROSHTHI LETTER YA + +10A2A +KHAROSHTHI LETTER RA + +10A2B +KHAROSHTHI LETTER LA + +10A2C +KHAROSHTHI LETTER VA + +10A2D +KHAROSHTHI LETTER SHA + +10A2E +KHAROSHTHI LETTER SSA + +10A2F +KHAROSHTHI LETTER SA + +10A30 +KHAROSHTHI LETTER ZA + +10A31 +KHAROSHTHI LETTER HA + +10A32 +KHAROSHTHI LETTER KKA + +10A33 +KHAROSHTHI LETTER TTTHA + +10A34 +KHAROSHTHI LETTER TTTA + +10A35 +KHAROSHTHI LETTER VHA + +10A38 +KHAROSHTHI SIGN BAR ABOVE + +10A39 +KHAROSHTHI SIGN CAUDA + +10A3A +KHAROSHTHI SIGN DOT BELOW + +10A3F +KHAROSHTHI VIRAMA + +10A40 +KHAROSHTHI DIGIT ONE + +10A41 +KHAROSHTHI DIGIT TWO + +10A42 +KHAROSHTHI DIGIT THREE + +10A43 +KHAROSHTHI DIGIT FOUR + +10A44 +KHAROSHTHI NUMBER TEN + +10A45 +KHAROSHTHI NUMBER TWENTY + +10A46 +KHAROSHTHI NUMBER ONE HUNDRED + +10A47 +KHAROSHTHI NUMBER ONE THOUSAND + +10A48 +KHAROSHTHI FRACTION ONE HALF + +10A50 +KHAROSHTHI PUNCTUATION DOT + +10A51 +KHAROSHTHI PUNCTUATION SMALL CIRCLE + +10A52 +KHAROSHTHI PUNCTUATION CIRCLE + +10A53 +KHAROSHTHI PUNCTUATION CRESCENT BAR + +10A54 +KHAROSHTHI PUNCTUATION MANGALAM + +10A55 +KHAROSHTHI PUNCTUATION LOTUS + +10A56 +KHAROSHTHI PUNCTUATION DANDA + +10A57 +KHAROSHTHI PUNCTUATION DOUBLE DANDA + +10A58 +KHAROSHTHI PUNCTUATION LINES + +10A60 +OLD SOUTH ARABIAN LETTER HE + +10A61 +OLD SOUTH ARABIAN LETTER LAMEDH + +10A62 +OLD SOUTH ARABIAN LETTER HETH + +10A63 +OLD SOUTH ARABIAN LETTER MEM + +10A64 +OLD SOUTH ARABIAN LETTER QOPH + +10A65 +OLD SOUTH ARABIAN LETTER WAW + +10A66 +OLD SOUTH ARABIAN LETTER SHIN + +10A67 +OLD SOUTH ARABIAN LETTER RESH + +10A68 +OLD SOUTH ARABIAN LETTER BETH + +10A69 +OLD SOUTH ARABIAN LETTER TAW + +10A6A +OLD SOUTH ARABIAN LETTER SAT + +10A6B +OLD SOUTH ARABIAN LETTER KAPH + +10A6C +OLD SOUTH ARABIAN LETTER NUN + +10A6D +OLD SOUTH ARABIAN LETTER KHETH + +10A6E +OLD SOUTH ARABIAN LETTER SADHE + +10A6F +OLD SOUTH ARABIAN LETTER SAMEKH + +10A70 +OLD SOUTH ARABIAN LETTER FE + +10A71 +OLD SOUTH ARABIAN LETTER ALEF + +10A72 +OLD SOUTH ARABIAN LETTER AYN + +10A73 +OLD SOUTH ARABIAN LETTER DHADHE + +10A74 +OLD SOUTH ARABIAN LETTER GIMEL + +10A75 +OLD SOUTH ARABIAN LETTER DALETH + +10A76 +OLD SOUTH ARABIAN LETTER GHAYN + +10A77 +OLD SOUTH ARABIAN LETTER TETH + +10A78 +OLD SOUTH ARABIAN LETTER ZAYN + +10A79 +OLD SOUTH ARABIAN LETTER DHALETH + +10A7A +OLD SOUTH ARABIAN LETTER YODH + +10A7B +OLD SOUTH ARABIAN LETTER THAW + +10A7C +OLD SOUTH ARABIAN LETTER THETH + +10A7D +OLD SOUTH ARABIAN NUMBER ONE + +10A7E +OLD SOUTH ARABIAN NUMBER FIFTY + +10A7F +OLD SOUTH ARABIAN NUMERIC INDICATOR + +10A80 +OLD NORTH ARABIAN LETTER HEH + +10A81 +OLD NORTH ARABIAN LETTER LAM + +10A82 +OLD NORTH ARABIAN LETTER HAH + +10A83 +OLD NORTH ARABIAN LETTER MEEM + +10A84 +OLD NORTH ARABIAN LETTER QAF + +10A85 +OLD NORTH ARABIAN LETTER WAW + +10A86 +OLD NORTH ARABIAN LETTER ES-2 + +10A87 +OLD NORTH ARABIAN LETTER REH + +10A88 +OLD NORTH ARABIAN LETTER BEH + +10A89 +OLD NORTH ARABIAN LETTER TEH + +10A8A +OLD NORTH ARABIAN LETTER ES-1 + +10A8B +OLD NORTH ARABIAN LETTER KAF + +10A8C +OLD NORTH ARABIAN LETTER NOON + +10A8D +OLD NORTH ARABIAN LETTER KHAH + +10A8E +OLD NORTH ARABIAN LETTER SAD + +10A8F +OLD NORTH ARABIAN LETTER ES-3 + +10A90 +OLD NORTH ARABIAN LETTER FEH + +10A91 +OLD NORTH ARABIAN LETTER ALEF + +10A92 +OLD NORTH ARABIAN LETTER AIN + +10A93 +OLD NORTH ARABIAN LETTER DAD + +10A94 +OLD NORTH ARABIAN LETTER GEEM + +10A95 +OLD NORTH ARABIAN LETTER DAL + +10A96 +OLD NORTH ARABIAN LETTER GHAIN + +10A97 +OLD NORTH ARABIAN LETTER TAH + +10A98 +OLD NORTH ARABIAN LETTER ZAIN + +10A99 +OLD NORTH ARABIAN LETTER THAL + +10A9A +OLD NORTH ARABIAN LETTER YEH + +10A9B +OLD NORTH ARABIAN LETTER THEH + +10A9C +OLD NORTH ARABIAN LETTER ZAH + +10A9D +OLD NORTH ARABIAN NUMBER ONE + +10A9E +OLD NORTH ARABIAN NUMBER TEN + +10A9F +OLD NORTH ARABIAN NUMBER TWENTY + +10AC0 +MANICHAEAN LETTER ALEPH + +10AC1 +MANICHAEAN LETTER BETH + +10AC2 +MANICHAEAN LETTER BHETH + +10AC3 +MANICHAEAN LETTER GIMEL + +10AC4 +MANICHAEAN LETTER GHIMEL + +10AC5 +MANICHAEAN LETTER DALETH + +10AC6 +MANICHAEAN LETTER HE + +10AC7 +MANICHAEAN LETTER WAW + +10AC8 +MANICHAEAN SIGN UD + +10AC9 +MANICHAEAN LETTER ZAYIN + +10ACA +MANICHAEAN LETTER ZHAYIN + +10ACB +MANICHAEAN LETTER JAYIN + +10ACC +MANICHAEAN LETTER JHAYIN + +10ACD +MANICHAEAN LETTER HETH + +10ACE +MANICHAEAN LETTER TETH + +10ACF +MANICHAEAN LETTER YODH + +10AD0 +MANICHAEAN LETTER KAPH + +10AD1 +MANICHAEAN LETTER XAPH + +10AD2 +MANICHAEAN LETTER KHAPH + +10AD3 +MANICHAEAN LETTER LAMEDH + +10AD4 +MANICHAEAN LETTER DHAMEDH + +10AD5 +MANICHAEAN LETTER THAMEDH + +10AD6 +MANICHAEAN LETTER MEM + +10AD7 +MANICHAEAN LETTER NUN + +10AD8 +MANICHAEAN LETTER SAMEKH + +10AD9 +MANICHAEAN LETTER AYIN + +10ADA +MANICHAEAN LETTER AAYIN + +10ADB +MANICHAEAN LETTER PE + +10ADC +MANICHAEAN LETTER FE + +10ADD +MANICHAEAN LETTER SADHE + +10ADE +MANICHAEAN LETTER QOPH + +10ADF +MANICHAEAN LETTER XOPH + +10AE0 +MANICHAEAN LETTER QHOPH + +10AE1 +MANICHAEAN LETTER RESH + +10AE2 +MANICHAEAN LETTER SHIN + +10AE3 +MANICHAEAN LETTER SSHIN + +10AE4 +MANICHAEAN LETTER TAW + +10AE5 +MANICHAEAN ABBREVIATION MARK ABOVE + +10AE6 +MANICHAEAN ABBREVIATION MARK BELOW + +10AEB +MANICHAEAN NUMBER ONE + +10AEC +MANICHAEAN NUMBER FIVE + +10AED +MANICHAEAN NUMBER TEN + +10AEE +MANICHAEAN NUMBER TWENTY + +10AEF +MANICHAEAN NUMBER ONE HUNDRED + +10AF0 +MANICHAEAN PUNCTUATION STAR + +10AF1 +MANICHAEAN PUNCTUATION FLEURON + +10AF2 +MANICHAEAN PUNCTUATION DOUBLE DOT WITHIN DOT + +10AF3 +MANICHAEAN PUNCTUATION DOT WITHIN DOT + +10AF4 +MANICHAEAN PUNCTUATION DOT + +10AF5 +MANICHAEAN PUNCTUATION TWO DOTS + +10AF6 +MANICHAEAN PUNCTUATION LINE FILLER + +10B00 +AVESTAN LETTER A + +10B01 +AVESTAN LETTER AA + +10B02 +AVESTAN LETTER AO + +10B03 +AVESTAN LETTER AAO + +10B04 +AVESTAN LETTER AN + +10B05 +AVESTAN LETTER AAN + +10B06 +AVESTAN LETTER AE + +10B07 +AVESTAN LETTER AEE + +10B08 +AVESTAN LETTER E + +10B09 +AVESTAN LETTER EE + +10B0A +AVESTAN LETTER O + +10B0B +AVESTAN LETTER OO + +10B0C +AVESTAN LETTER I + +10B0D +AVESTAN LETTER II + +10B0E +AVESTAN LETTER U + +10B0F +AVESTAN LETTER UU + +10B10 +AVESTAN LETTER KE + +10B11 +AVESTAN LETTER XE + +10B12 +AVESTAN LETTER XYE + +10B13 +AVESTAN LETTER XVE + +10B14 +AVESTAN LETTER GE + +10B15 +AVESTAN LETTER GGE + +10B16 +AVESTAN LETTER GHE + +10B17 +AVESTAN LETTER CE + +10B18 +AVESTAN LETTER JE + +10B19 +AVESTAN LETTER TE + +10B1A +AVESTAN LETTER THE + +10B1B +AVESTAN LETTER DE + +10B1C +AVESTAN LETTER DHE + +10B1D +AVESTAN LETTER TTE + +10B1E +AVESTAN LETTER PE + +10B1F +AVESTAN LETTER FE + +10B20 +AVESTAN LETTER BE + +10B21 +AVESTAN LETTER BHE + +10B22 +AVESTAN LETTER NGE + +10B23 +AVESTAN LETTER NGYE + +10B24 +AVESTAN LETTER NGVE + +10B25 +AVESTAN LETTER NE + +10B26 +AVESTAN LETTER NYE + +10B27 +AVESTAN LETTER NNE + +10B28 +AVESTAN LETTER ME + +10B29 +AVESTAN LETTER HME + +10B2A +AVESTAN LETTER YYE + +10B2B +AVESTAN LETTER YE + +10B2C +AVESTAN LETTER VE + +10B2D +AVESTAN LETTER RE + +10B2E +AVESTAN LETTER LE + +10B2F +AVESTAN LETTER SE + +10B30 +AVESTAN LETTER ZE + +10B31 +AVESTAN LETTER SHE + +10B32 +AVESTAN LETTER ZHE + +10B33 +AVESTAN LETTER SHYE + +10B34 +AVESTAN LETTER SSHE + +10B35 +AVESTAN LETTER HE + +10B39 +AVESTAN ABBREVIATION MARK + +10B3A +TINY TWO DOTS OVER ONE DOT PUNCTUATION + +10B3B +SMALL TWO DOTS OVER ONE DOT PUNCTUATION + +10B3C +LARGE TWO DOTS OVER ONE DOT PUNCTUATION + +10B3D +LARGE ONE DOT OVER TWO DOTS PUNCTUATION + +10B3E +LARGE TWO RINGS OVER ONE RING PUNCTUATION + +10B3F +LARGE ONE RING OVER TWO RINGS PUNCTUATION + +10B40 +INSCRIPTIONAL PARTHIAN LETTER ALEPH + +10B41 +INSCRIPTIONAL PARTHIAN LETTER BETH + +10B42 +INSCRIPTIONAL PARTHIAN LETTER GIMEL + +10B43 +INSCRIPTIONAL PARTHIAN LETTER DALETH + +10B44 +INSCRIPTIONAL PARTHIAN LETTER HE + +10B45 +INSCRIPTIONAL PARTHIAN LETTER WAW + +10B46 +INSCRIPTIONAL PARTHIAN LETTER ZAYIN + +10B47 +INSCRIPTIONAL PARTHIAN LETTER HETH + +10B48 +INSCRIPTIONAL PARTHIAN LETTER TETH + +10B49 +INSCRIPTIONAL PARTHIAN LETTER YODH + +10B4A +INSCRIPTIONAL PARTHIAN LETTER KAPH + +10B4B +INSCRIPTIONAL PARTHIAN LETTER LAMEDH + +10B4C +INSCRIPTIONAL PARTHIAN LETTER MEM + +10B4D +INSCRIPTIONAL PARTHIAN LETTER NUN + +10B4E +INSCRIPTIONAL PARTHIAN LETTER SAMEKH + +10B4F +INSCRIPTIONAL PARTHIAN LETTER AYIN + +10B50 +INSCRIPTIONAL PARTHIAN LETTER PE + +10B51 +INSCRIPTIONAL PARTHIAN LETTER SADHE + +10B52 +INSCRIPTIONAL PARTHIAN LETTER QOPH + +10B53 +INSCRIPTIONAL PARTHIAN LETTER RESH + +10B54 +INSCRIPTIONAL PARTHIAN LETTER SHIN + +10B55 +INSCRIPTIONAL PARTHIAN LETTER TAW + +10B58 +INSCRIPTIONAL PARTHIAN NUMBER ONE + +10B59 +INSCRIPTIONAL PARTHIAN NUMBER TWO + +10B5A +INSCRIPTIONAL PARTHIAN NUMBER THREE + +10B5B +INSCRIPTIONAL PARTHIAN NUMBER FOUR + +10B5C +INSCRIPTIONAL PARTHIAN NUMBER TEN + +10B5D +INSCRIPTIONAL PARTHIAN NUMBER TWENTY + +10B5E +INSCRIPTIONAL PARTHIAN NUMBER ONE HUNDRED + +10B5F +INSCRIPTIONAL PARTHIAN NUMBER ONE THOUSAND + +10B60 +INSCRIPTIONAL PAHLAVI LETTER ALEPH + +10B61 +INSCRIPTIONAL PAHLAVI LETTER BETH + +10B62 +INSCRIPTIONAL PAHLAVI LETTER GIMEL + +10B63 +INSCRIPTIONAL PAHLAVI LETTER DALETH + +10B64 +INSCRIPTIONAL PAHLAVI LETTER HE + +10B65 +INSCRIPTIONAL PAHLAVI LETTER WAW-AYIN-RESH + +10B66 +INSCRIPTIONAL PAHLAVI LETTER ZAYIN + +10B67 +INSCRIPTIONAL PAHLAVI LETTER HETH + +10B68 +INSCRIPTIONAL PAHLAVI LETTER TETH + +10B69 +INSCRIPTIONAL PAHLAVI LETTER YODH + +10B6A +INSCRIPTIONAL PAHLAVI LETTER KAPH + +10B6B +INSCRIPTIONAL PAHLAVI LETTER LAMEDH + +10B6C +INSCRIPTIONAL PAHLAVI LETTER MEM-QOPH + +10B6D +INSCRIPTIONAL PAHLAVI LETTER NUN + +10B6E +INSCRIPTIONAL PAHLAVI LETTER SAMEKH + +10B6F +INSCRIPTIONAL PAHLAVI LETTER PE + +10B70 +INSCRIPTIONAL PAHLAVI LETTER SADHE + +10B71 +INSCRIPTIONAL PAHLAVI LETTER SHIN + +10B72 +INSCRIPTIONAL PAHLAVI LETTER TAW + +10B78 +INSCRIPTIONAL PAHLAVI NUMBER ONE + +10B79 +INSCRIPTIONAL PAHLAVI NUMBER TWO + +10B7A +INSCRIPTIONAL PAHLAVI NUMBER THREE + +10B7B +INSCRIPTIONAL PAHLAVI NUMBER FOUR + +10B7C +INSCRIPTIONAL PAHLAVI NUMBER TEN + +10B7D +INSCRIPTIONAL PAHLAVI NUMBER TWENTY + +10B7E +INSCRIPTIONAL PAHLAVI NUMBER ONE HUNDRED + +10B7F +INSCRIPTIONAL PAHLAVI NUMBER ONE THOUSAND + +10B80 +PSALTER PAHLAVI LETTER ALEPH + +10B81 +PSALTER PAHLAVI LETTER BETH + +10B82 +PSALTER PAHLAVI LETTER GIMEL + +10B83 +PSALTER PAHLAVI LETTER DALETH + +10B84 +PSALTER PAHLAVI LETTER HE + +10B85 +PSALTER PAHLAVI LETTER WAW-AYIN-RESH + +10B86 +PSALTER PAHLAVI LETTER ZAYIN + +10B87 +PSALTER PAHLAVI LETTER HETH + +10B88 +PSALTER PAHLAVI LETTER YODH + +10B89 +PSALTER PAHLAVI LETTER KAPH + +10B8A +PSALTER PAHLAVI LETTER LAMEDH + +10B8B +PSALTER PAHLAVI LETTER MEM-QOPH + +10B8C +PSALTER PAHLAVI LETTER NUN + +10B8D +PSALTER PAHLAVI LETTER SAMEKH + +10B8E +PSALTER PAHLAVI LETTER PE + +10B8F +PSALTER PAHLAVI LETTER SADHE + +10B90 +PSALTER PAHLAVI LETTER SHIN + +10B91 +PSALTER PAHLAVI LETTER TAW + +10B99 +PSALTER PAHLAVI SECTION MARK + +10B9A +PSALTER PAHLAVI TURNED SECTION MARK + +10B9B +PSALTER PAHLAVI FOUR DOTS WITH CROSS + +10B9C +PSALTER PAHLAVI FOUR DOTS WITH DOT + +10BA9 +PSALTER PAHLAVI NUMBER ONE + +10BAA +PSALTER PAHLAVI NUMBER TWO + +10BAB +PSALTER PAHLAVI NUMBER THREE + +10BAC +PSALTER PAHLAVI NUMBER FOUR + +10BAD +PSALTER PAHLAVI NUMBER TEN + +10BAE +PSALTER PAHLAVI NUMBER TWENTY + +10BAF +PSALTER PAHLAVI NUMBER ONE HUNDRED + +10C00 +OLD TURKIC LETTER ORKHON A + +10C01 +OLD TURKIC LETTER YENISEI A + +10C02 +OLD TURKIC LETTER YENISEI AE + +10C03 +OLD TURKIC LETTER ORKHON I + +10C04 +OLD TURKIC LETTER YENISEI I + +10C05 +OLD TURKIC LETTER YENISEI E + +10C06 +OLD TURKIC LETTER ORKHON O + +10C07 +OLD TURKIC LETTER ORKHON OE + +10C08 +OLD TURKIC LETTER YENISEI OE + +10C09 +OLD TURKIC LETTER ORKHON AB + +10C0A +OLD TURKIC LETTER YENISEI AB + +10C0B +OLD TURKIC LETTER ORKHON AEB + +10C0C +OLD TURKIC LETTER YENISEI AEB + +10C0D +OLD TURKIC LETTER ORKHON AG + +10C0E +OLD TURKIC LETTER YENISEI AG + +10C0F +OLD TURKIC LETTER ORKHON AEG + +10C10 +OLD TURKIC LETTER YENISEI AEG + +10C11 +OLD TURKIC LETTER ORKHON AD + +10C12 +OLD TURKIC LETTER YENISEI AD + +10C13 +OLD TURKIC LETTER ORKHON AED + +10C14 +OLD TURKIC LETTER ORKHON EZ + +10C15 +OLD TURKIC LETTER YENISEI EZ + +10C16 +OLD TURKIC LETTER ORKHON AY + +10C17 +OLD TURKIC LETTER YENISEI AY + +10C18 +OLD TURKIC LETTER ORKHON AEY + +10C19 +OLD TURKIC LETTER YENISEI AEY + +10C1A +OLD TURKIC LETTER ORKHON AEK + +10C1B +OLD TURKIC LETTER YENISEI AEK + +10C1C +OLD TURKIC LETTER ORKHON OEK + +10C1D +OLD TURKIC LETTER YENISEI OEK + +10C1E +OLD TURKIC LETTER ORKHON AL + +10C1F +OLD TURKIC LETTER YENISEI AL + +10C20 +OLD TURKIC LETTER ORKHON AEL + +10C21 +OLD TURKIC LETTER ORKHON ELT + +10C22 +OLD TURKIC LETTER ORKHON EM + +10C23 +OLD TURKIC LETTER ORKHON AN + +10C24 +OLD TURKIC LETTER ORKHON AEN + +10C25 +OLD TURKIC LETTER YENISEI AEN + +10C26 +OLD TURKIC LETTER ORKHON ENT + +10C27 +OLD TURKIC LETTER YENISEI ENT + +10C28 +OLD TURKIC LETTER ORKHON ENC + +10C29 +OLD TURKIC LETTER YENISEI ENC + +10C2A +OLD TURKIC LETTER ORKHON ENY + +10C2B +OLD TURKIC LETTER YENISEI ENY + +10C2C +OLD TURKIC LETTER YENISEI ANG + +10C2D +OLD TURKIC LETTER ORKHON ENG + +10C2E +OLD TURKIC LETTER YENISEI AENG + +10C2F +OLD TURKIC LETTER ORKHON EP + +10C30 +OLD TURKIC LETTER ORKHON OP + +10C31 +OLD TURKIC LETTER ORKHON IC + +10C32 +OLD TURKIC LETTER ORKHON EC + +10C33 +OLD TURKIC LETTER YENISEI EC + +10C34 +OLD TURKIC LETTER ORKHON AQ + +10C35 +OLD TURKIC LETTER YENISEI AQ + +10C36 +OLD TURKIC LETTER ORKHON IQ + +10C37 +OLD TURKIC LETTER YENISEI IQ + +10C38 +OLD TURKIC LETTER ORKHON OQ + +10C39 +OLD TURKIC LETTER YENISEI OQ + +10C3A +OLD TURKIC LETTER ORKHON AR + +10C3B +OLD TURKIC LETTER YENISEI AR + +10C3C +OLD TURKIC LETTER ORKHON AER + +10C3D +OLD TURKIC LETTER ORKHON AS + +10C3E +OLD TURKIC LETTER ORKHON AES + +10C3F +OLD TURKIC LETTER ORKHON ASH + +10C40 +OLD TURKIC LETTER YENISEI ASH + +10C41 +OLD TURKIC LETTER ORKHON ESH + +10C42 +OLD TURKIC LETTER YENISEI ESH + +10C43 +OLD TURKIC LETTER ORKHON AT + +10C44 +OLD TURKIC LETTER YENISEI AT + +10C45 +OLD TURKIC LETTER ORKHON AET + +10C46 +OLD TURKIC LETTER YENISEI AET + +10C47 +OLD TURKIC LETTER ORKHON OT + +10C48 +OLD TURKIC LETTER ORKHON BASH + +10C80 +OLD HUNGARIAN CAPITAL LETTER A + +10C81 +OLD HUNGARIAN CAPITAL LETTER AA + +10C82 +OLD HUNGARIAN CAPITAL LETTER EB + +10C83 +OLD HUNGARIAN CAPITAL LETTER AMB + +10C84 +OLD HUNGARIAN CAPITAL LETTER EC + +10C85 +OLD HUNGARIAN CAPITAL LETTER ENC + +10C86 +OLD HUNGARIAN CAPITAL LETTER ECS + +10C87 +OLD HUNGARIAN CAPITAL LETTER ED + +10C88 +OLD HUNGARIAN CAPITAL LETTER AND + +10C89 +OLD HUNGARIAN CAPITAL LETTER E + +10C8A +OLD HUNGARIAN CAPITAL LETTER CLOSE E + +10C8B +OLD HUNGARIAN CAPITAL LETTER EE + +10C8C +OLD HUNGARIAN CAPITAL LETTER EF + +10C8D +OLD HUNGARIAN CAPITAL LETTER EG + +10C8E +OLD HUNGARIAN CAPITAL LETTER EGY + +10C8F +OLD HUNGARIAN CAPITAL LETTER EH + +10C90 +OLD HUNGARIAN CAPITAL LETTER I + +10C91 +OLD HUNGARIAN CAPITAL LETTER II + +10C92 +OLD HUNGARIAN CAPITAL LETTER EJ + +10C93 +OLD HUNGARIAN CAPITAL LETTER EK + +10C94 +OLD HUNGARIAN CAPITAL LETTER AK + +10C95 +OLD HUNGARIAN CAPITAL LETTER UNK + +10C96 +OLD HUNGARIAN CAPITAL LETTER EL + +10C97 +OLD HUNGARIAN CAPITAL LETTER ELY + +10C98 +OLD HUNGARIAN CAPITAL LETTER EM + +10C99 +OLD HUNGARIAN CAPITAL LETTER EN + +10C9A +OLD HUNGARIAN CAPITAL LETTER ENY + +10C9B +OLD HUNGARIAN CAPITAL LETTER O + +10C9C +OLD HUNGARIAN CAPITAL LETTER OO + +10C9D +OLD HUNGARIAN CAPITAL LETTER NIKOLSBURG OE + +10C9E +OLD HUNGARIAN CAPITAL LETTER RUDIMENTA OE + +10C9F +OLD HUNGARIAN CAPITAL LETTER OEE + +10CA0 +OLD HUNGARIAN CAPITAL LETTER EP + +10CA1 +OLD HUNGARIAN CAPITAL LETTER EMP + +10CA2 +OLD HUNGARIAN CAPITAL LETTER ER + +10CA3 +OLD HUNGARIAN CAPITAL LETTER SHORT ER + +10CA4 +OLD HUNGARIAN CAPITAL LETTER ES + +10CA5 +OLD HUNGARIAN CAPITAL LETTER ESZ + +10CA6 +OLD HUNGARIAN CAPITAL LETTER ET + +10CA7 +OLD HUNGARIAN CAPITAL LETTER ENT + +10CA8 +OLD HUNGARIAN CAPITAL LETTER ETY + +10CA9 +OLD HUNGARIAN CAPITAL LETTER ECH + +10CAA +OLD HUNGARIAN CAPITAL LETTER U + +10CAB +OLD HUNGARIAN CAPITAL LETTER UU + +10CAC +OLD HUNGARIAN CAPITAL LETTER NIKOLSBURG UE + +10CAD +OLD HUNGARIAN CAPITAL LETTER RUDIMENTA UE + +10CAE +OLD HUNGARIAN CAPITAL LETTER EV + +10CAF +OLD HUNGARIAN CAPITAL LETTER EZ + +10CB0 +OLD HUNGARIAN CAPITAL LETTER EZS + +10CB1 +OLD HUNGARIAN CAPITAL LETTER ENT-SHAPED SIGN + +10CB2 +OLD HUNGARIAN CAPITAL LETTER US + +10CC0 +OLD HUNGARIAN SMALL LETTER A + +10CC1 +OLD HUNGARIAN SMALL LETTER AA + +10CC2 +OLD HUNGARIAN SMALL LETTER EB + +10CC3 +OLD HUNGARIAN SMALL LETTER AMB + +10CC4 +OLD HUNGARIAN SMALL LETTER EC + +10CC5 +OLD HUNGARIAN SMALL LETTER ENC + +10CC6 +OLD HUNGARIAN SMALL LETTER ECS + +10CC7 +OLD HUNGARIAN SMALL LETTER ED + +10CC8 +OLD HUNGARIAN SMALL LETTER AND + +10CC9 +OLD HUNGARIAN SMALL LETTER E + +10CCA +OLD HUNGARIAN SMALL LETTER CLOSE E + +10CCB +OLD HUNGARIAN SMALL LETTER EE + +10CCC +OLD HUNGARIAN SMALL LETTER EF + +10CCD +OLD HUNGARIAN SMALL LETTER EG + +10CCE +OLD HUNGARIAN SMALL LETTER EGY + +10CCF +OLD HUNGARIAN SMALL LETTER EH + +10CD0 +OLD HUNGARIAN SMALL LETTER I + +10CD1 +OLD HUNGARIAN SMALL LETTER II + +10CD2 +OLD HUNGARIAN SMALL LETTER EJ + +10CD3 +OLD HUNGARIAN SMALL LETTER EK + +10CD4 +OLD HUNGARIAN SMALL LETTER AK + +10CD5 +OLD HUNGARIAN SMALL LETTER UNK + +10CD6 +OLD HUNGARIAN SMALL LETTER EL + +10CD7 +OLD HUNGARIAN SMALL LETTER ELY + +10CD8 +OLD HUNGARIAN SMALL LETTER EM + +10CD9 +OLD HUNGARIAN SMALL LETTER EN + +10CDA +OLD HUNGARIAN SMALL LETTER ENY + +10CDB +OLD HUNGARIAN SMALL LETTER O + +10CDC +OLD HUNGARIAN SMALL LETTER OO + +10CDD +OLD HUNGARIAN SMALL LETTER NIKOLSBURG OE + +10CDE +OLD HUNGARIAN SMALL LETTER RUDIMENTA OE + +10CDF +OLD HUNGARIAN SMALL LETTER OEE + +10CE0 +OLD HUNGARIAN SMALL LETTER EP + +10CE1 +OLD HUNGARIAN SMALL LETTER EMP + +10CE2 +OLD HUNGARIAN SMALL LETTER ER + +10CE3 +OLD HUNGARIAN SMALL LETTER SHORT ER + +10CE4 +OLD HUNGARIAN SMALL LETTER ES + +10CE5 +OLD HUNGARIAN SMALL LETTER ESZ + +10CE6 +OLD HUNGARIAN SMALL LETTER ET + +10CE7 +OLD HUNGARIAN SMALL LETTER ENT + +10CE8 +OLD HUNGARIAN SMALL LETTER ETY + +10CE9 +OLD HUNGARIAN SMALL LETTER ECH + +10CEA +OLD HUNGARIAN SMALL LETTER U + +10CEB +OLD HUNGARIAN SMALL LETTER UU + +10CEC +OLD HUNGARIAN SMALL LETTER NIKOLSBURG UE + +10CED +OLD HUNGARIAN SMALL LETTER RUDIMENTA UE + +10CEE +OLD HUNGARIAN SMALL LETTER EV + +10CEF +OLD HUNGARIAN SMALL LETTER EZ + +10CF0 +OLD HUNGARIAN SMALL LETTER EZS + +10CF1 +OLD HUNGARIAN SMALL LETTER ENT-SHAPED SIGN + +10CF2 +OLD HUNGARIAN SMALL LETTER US + +10CFA +OLD HUNGARIAN NUMBER ONE + +10CFB +OLD HUNGARIAN NUMBER FIVE + +10CFC +OLD HUNGARIAN NUMBER TEN + +10CFD +OLD HUNGARIAN NUMBER FIFTY + +10CFE +OLD HUNGARIAN NUMBER ONE HUNDRED + +10CFF +OLD HUNGARIAN NUMBER ONE THOUSAND + +10D00 +HANIFI ROHINGYA LETTER A + +10D01 +HANIFI ROHINGYA LETTER BA + +10D02 +HANIFI ROHINGYA LETTER PA + +10D03 +HANIFI ROHINGYA LETTER TA + +10D04 +HANIFI ROHINGYA LETTER TTA + +10D05 +HANIFI ROHINGYA LETTER JA + +10D06 +HANIFI ROHINGYA LETTER CA + +10D07 +HANIFI ROHINGYA LETTER HA + +10D08 +HANIFI ROHINGYA LETTER KHA + +10D09 +HANIFI ROHINGYA LETTER FA + +10D0A +HANIFI ROHINGYA LETTER DA + +10D0B +HANIFI ROHINGYA LETTER DDA + +10D0C +HANIFI ROHINGYA LETTER RA + +10D0D +HANIFI ROHINGYA LETTER RRA + +10D0E +HANIFI ROHINGYA LETTER ZA + +10D0F +HANIFI ROHINGYA LETTER SA + +10D10 +HANIFI ROHINGYA LETTER SHA + +10D11 +HANIFI ROHINGYA LETTER KA + +10D12 +HANIFI ROHINGYA LETTER GA + +10D13 +HANIFI ROHINGYA LETTER LA + +10D14 +HANIFI ROHINGYA LETTER MA + +10D15 +HANIFI ROHINGYA LETTER NA + +10D16 +HANIFI ROHINGYA LETTER WA + +10D17 +HANIFI ROHINGYA LETTER KINNA WA + +10D18 +HANIFI ROHINGYA LETTER YA + +10D19 +HANIFI ROHINGYA LETTER KINNA YA + +10D1A +HANIFI ROHINGYA LETTER NGA + +10D1B +HANIFI ROHINGYA LETTER NYA + +10D1C +HANIFI ROHINGYA LETTER VA + +10D1D +HANIFI ROHINGYA VOWEL A + +10D1E +HANIFI ROHINGYA VOWEL I + +10D1F +HANIFI ROHINGYA VOWEL U + +10D20 +HANIFI ROHINGYA VOWEL E + +10D21 +HANIFI ROHINGYA VOWEL O + +10D22 +HANIFI ROHINGYA MARK SAKIN + +10D23 +HANIFI ROHINGYA MARK NA KHONNA + +10D24 +HANIFI ROHINGYA SIGN HARBAHAY + +10D25 +HANIFI ROHINGYA SIGN TAHALA + +10D26 +HANIFI ROHINGYA SIGN TANA + +10D27 +HANIFI ROHINGYA SIGN TASSI + +10D30 +HANIFI ROHINGYA DIGIT ZERO + +10D31 +HANIFI ROHINGYA DIGIT ONE + +10D32 +HANIFI ROHINGYA DIGIT TWO + +10D33 +HANIFI ROHINGYA DIGIT THREE + +10D34 +HANIFI ROHINGYA DIGIT FOUR + +10D35 +HANIFI ROHINGYA DIGIT FIVE + +10D36 +HANIFI ROHINGYA DIGIT SIX + +10D37 +HANIFI ROHINGYA DIGIT SEVEN + +10D38 +HANIFI ROHINGYA DIGIT EIGHT + +10D39 +HANIFI ROHINGYA DIGIT NINE + +10D40 +GARAY DIGIT ZERO + +10D41 +GARAY DIGIT ONE + +10D42 +GARAY DIGIT TWO + +10D43 +GARAY DIGIT THREE + +10D44 +GARAY DIGIT FOUR + +10D45 +GARAY DIGIT FIVE + +10D46 +GARAY DIGIT SIX + +10D47 +GARAY DIGIT SEVEN + +10D48 +GARAY DIGIT EIGHT + +10D49 +GARAY DIGIT NINE + +10D4A +GARAY VOWEL SIGN A + +10D4B +GARAY VOWEL SIGN I + +10D4C +GARAY VOWEL SIGN O + +10D4D +GARAY VOWEL SIGN EE + +10D4E +GARAY VOWEL LENGTH MARK + +10D4F +GARAY SUKUN + +10D50 +GARAY CAPITAL LETTER A + +10D51 +GARAY CAPITAL LETTER CA + +10D52 +GARAY CAPITAL LETTER MA + +10D53 +GARAY CAPITAL LETTER KA + +10D54 +GARAY CAPITAL LETTER BA + +10D55 +GARAY CAPITAL LETTER JA + +10D56 +GARAY CAPITAL LETTER SA + +10D57 +GARAY CAPITAL LETTER WA + +10D58 +GARAY CAPITAL LETTER LA + +10D59 +GARAY CAPITAL LETTER GA + +10D5A +GARAY CAPITAL LETTER DA + +10D5B +GARAY CAPITAL LETTER XA + +10D5C +GARAY CAPITAL LETTER YA + +10D5D +GARAY CAPITAL LETTER TA + +10D5E +GARAY CAPITAL LETTER RA + +10D5F +GARAY CAPITAL LETTER NYA + +10D60 +GARAY CAPITAL LETTER FA + +10D61 +GARAY CAPITAL LETTER NA + +10D62 +GARAY CAPITAL LETTER PA + +10D63 +GARAY CAPITAL LETTER HA + +10D64 +GARAY CAPITAL LETTER OLD KA + +10D65 +GARAY CAPITAL LETTER OLD NA + +10D69 +GARAY VOWEL SIGN E + +10D6A +GARAY CONSONANT GEMINATION MARK + +10D6B +GARAY COMBINING DOT ABOVE + +10D6C +GARAY COMBINING DOUBLE DOT ABOVE + +10D6D +GARAY CONSONANT NASALIZATION MARK + +10D6E +GARAY HYPHEN + +10D6F +GARAY REDUPLICATION MARK + +10D70 +GARAY SMALL LETTER A + +10D71 +GARAY SMALL LETTER CA + +10D72 +GARAY SMALL LETTER MA + +10D73 +GARAY SMALL LETTER KA + +10D74 +GARAY SMALL LETTER BA + +10D75 +GARAY SMALL LETTER JA + +10D76 +GARAY SMALL LETTER SA + +10D77 +GARAY SMALL LETTER WA + +10D78 +GARAY SMALL LETTER LA + +10D79 +GARAY SMALL LETTER GA + +10D7A +GARAY SMALL LETTER DA + +10D7B +GARAY SMALL LETTER XA + +10D7C +GARAY SMALL LETTER YA + +10D7D +GARAY SMALL LETTER TA + +10D7E +GARAY SMALL LETTER RA + +10D7F +GARAY SMALL LETTER NYA + +10D80 +GARAY SMALL LETTER FA + +10D81 +GARAY SMALL LETTER NA + +10D82 +GARAY SMALL LETTER PA + +10D83 +GARAY SMALL LETTER HA + +10D84 +GARAY SMALL LETTER OLD KA + +10D85 +GARAY SMALL LETTER OLD NA + +10D8E +GARAY PLUS SIGN + +10D8F +GARAY MINUS SIGN + +10E60 +RUMI DIGIT ONE + +10E61 +RUMI DIGIT TWO + +10E62 +RUMI DIGIT THREE + +10E63 +RUMI DIGIT FOUR + +10E64 +RUMI DIGIT FIVE + +10E65 +RUMI DIGIT SIX + +10E66 +RUMI DIGIT SEVEN + +10E67 +RUMI DIGIT EIGHT + +10E68 +RUMI DIGIT NINE + +10E69 +RUMI NUMBER TEN + +10E6A +RUMI NUMBER TWENTY + +10E6B +RUMI NUMBER THIRTY + +10E6C +RUMI NUMBER FORTY + +10E6D +RUMI NUMBER FIFTY + +10E6E +RUMI NUMBER SIXTY + +10E6F +RUMI NUMBER SEVENTY + +10E70 +RUMI NUMBER EIGHTY + +10E71 +RUMI NUMBER NINETY + +10E72 +RUMI NUMBER ONE HUNDRED + +10E73 +RUMI NUMBER TWO HUNDRED + +10E74 +RUMI NUMBER THREE HUNDRED + +10E75 +RUMI NUMBER FOUR HUNDRED + +10E76 +RUMI NUMBER FIVE HUNDRED + +10E77 +RUMI NUMBER SIX HUNDRED + +10E78 +RUMI NUMBER SEVEN HUNDRED + +10E79 +RUMI NUMBER EIGHT HUNDRED + +10E7A +RUMI NUMBER NINE HUNDRED + +10E7B +RUMI FRACTION ONE HALF + +10E7C +RUMI FRACTION ONE QUARTER + +10E7D +RUMI FRACTION ONE THIRD + +10E7E +RUMI FRACTION TWO THIRDS + +10E80 +YEZIDI LETTER ELIF + +10E81 +YEZIDI LETTER BE + +10E82 +YEZIDI LETTER PE + +10E83 +YEZIDI LETTER PHE + +10E84 +YEZIDI LETTER THE + +10E85 +YEZIDI LETTER SE + +10E86 +YEZIDI LETTER CIM + +10E87 +YEZIDI LETTER CHIM + +10E88 +YEZIDI LETTER CHHIM + +10E89 +YEZIDI LETTER HHA + +10E8A +YEZIDI LETTER XA + +10E8B +YEZIDI LETTER DAL + +10E8C +YEZIDI LETTER ZAL + +10E8D +YEZIDI LETTER RA + +10E8E +YEZIDI LETTER RHA + +10E8F +YEZIDI LETTER ZA + +10E90 +YEZIDI LETTER JA + +10E91 +YEZIDI LETTER SIN + +10E92 +YEZIDI LETTER SHIN + +10E93 +YEZIDI LETTER SAD + +10E94 +YEZIDI LETTER DAD + +10E95 +YEZIDI LETTER TA + +10E96 +YEZIDI LETTER ZE + +10E97 +YEZIDI LETTER EYN + +10E98 +YEZIDI LETTER XHEYN + +10E99 +YEZIDI LETTER FA + +10E9A +YEZIDI LETTER VA + +10E9B +YEZIDI LETTER VA ALTERNATE FORM + +10E9C +YEZIDI LETTER QAF + +10E9D +YEZIDI LETTER KAF + +10E9E +YEZIDI LETTER KHAF + +10E9F +YEZIDI LETTER GAF + +10EA0 +YEZIDI LETTER LAM + +10EA1 +YEZIDI LETTER MIM + +10EA2 +YEZIDI LETTER NUN + +10EA3 +YEZIDI LETTER UM + +10EA4 +YEZIDI LETTER WAW + +10EA5 +YEZIDI LETTER OW + +10EA6 +YEZIDI LETTER EW + +10EA7 +YEZIDI LETTER HAY + +10EA8 +YEZIDI LETTER YOT + +10EA9 +YEZIDI LETTER ET + +10EAB +YEZIDI COMBINING HAMZA MARK + +10EAC +YEZIDI COMBINING MADDA MARK + +10EAD +YEZIDI HYPHENATION MARK + +10EB0 +YEZIDI LETTER LAM WITH DOT ABOVE + +10EB1 +YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE + +10EC2 +ARABIC LETTER DAL WITH TWO DOTS VERTICALLY BELOW + +10EC3 +ARABIC LETTER TAH WITH TWO DOTS VERTICALLY BELOW + +10EC4 +ARABIC LETTER KAF WITH TWO DOTS VERTICALLY BELOW + +10EC5 +ARABIC SMALL YEH BARREE WITH TWO DOTS BELOW + +10EC6 +ARABIC LETTER THIN NOON + +10EC7 +ARABIC LETTER YEH WITH FOUR DOTS BELOW + +10ED0 +ARABIC BIBLICAL END OF VERSE + +10ED1 +ARABIC LIGATURE ALAYHAA AS-SALAATU WAS-SALAAM + +10ED2 +ARABIC LIGATURE ALAYHIM AS-SALAATU WAS-SALAAM + +10ED3 +ARABIC LIGATURE ALAYHIMAA AS-SALAATU WAS-SALAAM + +10ED4 +ARABIC LIGATURE QADDASA ALLAAHU SIRRAH + +10ED5 +ARABIC LIGATURE QUDDISA SIRRUHUM + +10ED6 +ARABIC LIGATURE QUDDISA SIRRUHUMAA + +10ED7 +ARABIC LIGATURE QUDDISAT ASRAARUHUM + +10ED8 +ARABIC LIGATURE NAWWARA ALLAAHU MARQADAH + +10EFA +ARABIC DOUBLE VERTICAL BAR BELOW + +10EFB +ARABIC SMALL LOW NOON + +10EFC +ARABIC COMBINING ALEF OVERLAY + +10EFD +ARABIC SMALL LOW WORD SAKTA + +10EFE +ARABIC SMALL LOW WORD QASR + +10EFF +ARABIC SMALL LOW WORD MADDA + +10F00 +OLD SOGDIAN LETTER ALEPH + +10F01 +OLD SOGDIAN LETTER FINAL ALEPH + +10F02 +OLD SOGDIAN LETTER BETH + +10F03 +OLD SOGDIAN LETTER FINAL BETH + +10F04 +OLD SOGDIAN LETTER GIMEL + +10F05 +OLD SOGDIAN LETTER HE + +10F06 +OLD SOGDIAN LETTER FINAL HE + +10F07 +OLD SOGDIAN LETTER WAW + +10F08 +OLD SOGDIAN LETTER ZAYIN + +10F09 +OLD SOGDIAN LETTER HETH + +10F0A +OLD SOGDIAN LETTER YODH + +10F0B +OLD SOGDIAN LETTER KAPH + +10F0C +OLD SOGDIAN LETTER LAMEDH + +10F0D +OLD SOGDIAN LETTER MEM + +10F0E +OLD SOGDIAN LETTER NUN + +10F0F +OLD SOGDIAN LETTER FINAL NUN + +10F10 +OLD SOGDIAN LETTER FINAL NUN WITH VERTICAL TAIL + +10F11 +OLD SOGDIAN LETTER SAMEKH + +10F12 +OLD SOGDIAN LETTER AYIN + +10F13 +OLD SOGDIAN LETTER ALTERNATE AYIN + +10F14 +OLD SOGDIAN LETTER PE + +10F15 +OLD SOGDIAN LETTER SADHE + +10F16 +OLD SOGDIAN LETTER FINAL SADHE + +10F17 +OLD SOGDIAN LETTER FINAL SADHE WITH VERTICAL TAIL + +10F18 +OLD SOGDIAN LETTER RESH-AYIN-DALETH + +10F19 +OLD SOGDIAN LETTER SHIN + +10F1A +OLD SOGDIAN LETTER TAW + +10F1B +OLD SOGDIAN LETTER FINAL TAW + +10F1C +OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL + +10F1D +OLD SOGDIAN NUMBER ONE + +10F1E +OLD SOGDIAN NUMBER TWO + +10F1F +OLD SOGDIAN NUMBER THREE + +10F20 +OLD SOGDIAN NUMBER FOUR + +10F21 +OLD SOGDIAN NUMBER FIVE + +10F22 +OLD SOGDIAN NUMBER TEN + +10F23 +OLD SOGDIAN NUMBER TWENTY + +10F24 +OLD SOGDIAN NUMBER THIRTY + +10F25 +OLD SOGDIAN NUMBER ONE HUNDRED + +10F26 +OLD SOGDIAN FRACTION ONE HALF + +10F27 +OLD SOGDIAN LIGATURE AYIN-DALETH + +10F30 +SOGDIAN LETTER ALEPH + +10F31 +SOGDIAN LETTER BETH + +10F32 +SOGDIAN LETTER GIMEL + +10F33 +SOGDIAN LETTER HE + +10F34 +SOGDIAN LETTER WAW + +10F35 +SOGDIAN LETTER ZAYIN + +10F36 +SOGDIAN LETTER HETH + +10F37 +SOGDIAN LETTER YODH + +10F38 +SOGDIAN LETTER KAPH + +10F39 +SOGDIAN LETTER LAMEDH + +10F3A +SOGDIAN LETTER MEM + +10F3B +SOGDIAN LETTER NUN + +10F3C +SOGDIAN LETTER SAMEKH + +10F3D +SOGDIAN LETTER AYIN + +10F3E +SOGDIAN LETTER PE + +10F3F +SOGDIAN LETTER SADHE + +10F40 +SOGDIAN LETTER RESH-AYIN + +10F41 +SOGDIAN LETTER SHIN + +10F42 +SOGDIAN LETTER TAW + +10F43 +SOGDIAN LETTER FETH + +10F44 +SOGDIAN LETTER LESH + +10F45 +SOGDIAN INDEPENDENT SHIN + +10F46 +SOGDIAN COMBINING DOT BELOW + +10F47 +SOGDIAN COMBINING TWO DOTS BELOW + +10F48 +SOGDIAN COMBINING DOT ABOVE + +10F49 +SOGDIAN COMBINING TWO DOTS ABOVE + +10F4A +SOGDIAN COMBINING CURVE ABOVE + +10F4B +SOGDIAN COMBINING CURVE BELOW + +10F4C +SOGDIAN COMBINING HOOK ABOVE + +10F4D +SOGDIAN COMBINING HOOK BELOW + +10F4E +SOGDIAN COMBINING LONG HOOK BELOW + +10F4F +SOGDIAN COMBINING RESH BELOW + +10F50 +SOGDIAN COMBINING STROKE BELOW + +10F51 +SOGDIAN NUMBER ONE + +10F52 +SOGDIAN NUMBER TEN + +10F53 +SOGDIAN NUMBER TWENTY + +10F54 +SOGDIAN NUMBER ONE HUNDRED + +10F55 +SOGDIAN PUNCTUATION TWO VERTICAL BARS + +10F56 +SOGDIAN PUNCTUATION TWO VERTICAL BARS WITH DOTS + +10F57 +SOGDIAN PUNCTUATION CIRCLE WITH DOT + +10F58 +SOGDIAN PUNCTUATION TWO CIRCLES WITH DOTS + +10F59 +SOGDIAN PUNCTUATION HALF CIRCLE WITH DOT + +10F70 +OLD UYGHUR LETTER ALEPH + +10F71 +OLD UYGHUR LETTER BETH + +10F72 +OLD UYGHUR LETTER GIMEL-HETH + +10F73 +OLD UYGHUR LETTER WAW + +10F74 +OLD UYGHUR LETTER ZAYIN + +10F75 +OLD UYGHUR LETTER FINAL HETH + +10F76 +OLD UYGHUR LETTER YODH + +10F77 +OLD UYGHUR LETTER KAPH + +10F78 +OLD UYGHUR LETTER LAMEDH + +10F79 +OLD UYGHUR LETTER MEM + +10F7A +OLD UYGHUR LETTER NUN + +10F7B +OLD UYGHUR LETTER SAMEKH + +10F7C +OLD UYGHUR LETTER PE + +10F7D +OLD UYGHUR LETTER SADHE + +10F7E +OLD UYGHUR LETTER RESH + +10F7F +OLD UYGHUR LETTER SHIN + +10F80 +OLD UYGHUR LETTER TAW + +10F81 +OLD UYGHUR LETTER LESH + +10F82 +OLD UYGHUR COMBINING DOT ABOVE + +10F83 +OLD UYGHUR COMBINING DOT BELOW + +10F84 +OLD UYGHUR COMBINING TWO DOTS ABOVE + +10F85 +OLD UYGHUR COMBINING TWO DOTS BELOW + +10F86 +OLD UYGHUR PUNCTUATION BAR + +10F87 +OLD UYGHUR PUNCTUATION TWO BARS + +10F88 +OLD UYGHUR PUNCTUATION TWO DOTS + +10F89 +OLD UYGHUR PUNCTUATION FOUR DOTS + +10FB0 +CHORASMIAN LETTER ALEPH + +10FB1 +CHORASMIAN LETTER SMALL ALEPH + +10FB2 +CHORASMIAN LETTER BETH + +10FB3 +CHORASMIAN LETTER GIMEL + +10FB4 +CHORASMIAN LETTER DALETH + +10FB5 +CHORASMIAN LETTER HE + +10FB6 +CHORASMIAN LETTER WAW + +10FB7 +CHORASMIAN LETTER CURLED WAW + +10FB8 +CHORASMIAN LETTER ZAYIN + +10FB9 +CHORASMIAN LETTER HETH + +10FBA +CHORASMIAN LETTER YODH + +10FBB +CHORASMIAN LETTER KAPH + +10FBC +CHORASMIAN LETTER LAMEDH + +10FBD +CHORASMIAN LETTER MEM + +10FBE +CHORASMIAN LETTER NUN + +10FBF +CHORASMIAN LETTER SAMEKH + +10FC0 +CHORASMIAN LETTER AYIN + +10FC1 +CHORASMIAN LETTER PE + +10FC2 +CHORASMIAN LETTER RESH + +10FC3 +CHORASMIAN LETTER SHIN + +10FC4 +CHORASMIAN LETTER TAW + +10FC5 +CHORASMIAN NUMBER ONE + +10FC6 +CHORASMIAN NUMBER TWO + +10FC7 +CHORASMIAN NUMBER THREE + +10FC8 +CHORASMIAN NUMBER FOUR + +10FC9 +CHORASMIAN NUMBER TEN + +10FCA +CHORASMIAN NUMBER TWENTY + +10FCB +CHORASMIAN NUMBER ONE HUNDRED + +10FE0 +ELYMAIC LETTER ALEPH + +10FE1 +ELYMAIC LETTER BETH + +10FE2 +ELYMAIC LETTER GIMEL + +10FE3 +ELYMAIC LETTER DALETH + +10FE4 +ELYMAIC LETTER HE + +10FE5 +ELYMAIC LETTER WAW + +10FE6 +ELYMAIC LETTER ZAYIN + +10FE7 +ELYMAIC LETTER HETH + +10FE8 +ELYMAIC LETTER TETH + +10FE9 +ELYMAIC LETTER YODH + +10FEA +ELYMAIC LETTER KAPH + +10FEB +ELYMAIC LETTER LAMEDH + +10FEC +ELYMAIC LETTER MEM + +10FED +ELYMAIC LETTER NUN + +10FEE +ELYMAIC LETTER SAMEKH + +10FEF +ELYMAIC LETTER AYIN + +10FF0 +ELYMAIC LETTER PE + +10FF1 +ELYMAIC LETTER SADHE + +10FF2 +ELYMAIC LETTER QOPH + +10FF3 +ELYMAIC LETTER RESH + +10FF4 +ELYMAIC LETTER SHIN + +10FF5 +ELYMAIC LETTER TAW + +10FF6 +ELYMAIC LIGATURE ZAYIN-YODH + +11000 +BRAHMI SIGN CANDRABINDU + +11001 +BRAHMI SIGN ANUSVARA + +11002 +BRAHMI SIGN VISARGA + +11003 +BRAHMI SIGN JIHVAMULIYA + +11004 +BRAHMI SIGN UPADHMANIYA + +11005 +BRAHMI LETTER A + +11006 +BRAHMI LETTER AA + +11007 +BRAHMI LETTER I + +11008 +BRAHMI LETTER II + +11009 +BRAHMI LETTER U + +1100A +BRAHMI LETTER UU + +1100B +BRAHMI LETTER VOCALIC R + +1100C +BRAHMI LETTER VOCALIC RR + +1100D +BRAHMI LETTER VOCALIC L + +1100E +BRAHMI LETTER VOCALIC LL + +1100F +BRAHMI LETTER E + +11010 +BRAHMI LETTER AI + +11011 +BRAHMI LETTER O + +11012 +BRAHMI LETTER AU + +11013 +BRAHMI LETTER KA + +11014 +BRAHMI LETTER KHA + +11015 +BRAHMI LETTER GA + +11016 +BRAHMI LETTER GHA + +11017 +BRAHMI LETTER NGA + +11018 +BRAHMI LETTER CA + +11019 +BRAHMI LETTER CHA + +1101A +BRAHMI LETTER JA + +1101B +BRAHMI LETTER JHA + +1101C +BRAHMI LETTER NYA + +1101D +BRAHMI LETTER TTA + +1101E +BRAHMI LETTER TTHA + +1101F +BRAHMI LETTER DDA + +11020 +BRAHMI LETTER DDHA + +11021 +BRAHMI LETTER NNA + +11022 +BRAHMI LETTER TA + +11023 +BRAHMI LETTER THA + +11024 +BRAHMI LETTER DA + +11025 +BRAHMI LETTER DHA + +11026 +BRAHMI LETTER NA + +11027 +BRAHMI LETTER PA + +11028 +BRAHMI LETTER PHA + +11029 +BRAHMI LETTER BA + +1102A +BRAHMI LETTER BHA + +1102B +BRAHMI LETTER MA + +1102C +BRAHMI LETTER YA + +1102D +BRAHMI LETTER RA + +1102E +BRAHMI LETTER LA + +1102F +BRAHMI LETTER VA + +11030 +BRAHMI LETTER SHA + +11031 +BRAHMI LETTER SSA + +11032 +BRAHMI LETTER SA + +11033 +BRAHMI LETTER HA + +11034 +BRAHMI LETTER LLA + +11035 +BRAHMI LETTER OLD TAMIL LLLA + +11036 +BRAHMI LETTER OLD TAMIL RRA + +11037 +BRAHMI LETTER OLD TAMIL NNNA + +11038 +BRAHMI VOWEL SIGN AA + +11039 +BRAHMI VOWEL SIGN BHATTIPROLU AA + +1103A +BRAHMI VOWEL SIGN I + +1103B +BRAHMI VOWEL SIGN II + +1103C +BRAHMI VOWEL SIGN U + +1103D +BRAHMI VOWEL SIGN UU + +1103E +BRAHMI VOWEL SIGN VOCALIC R + +1103F +BRAHMI VOWEL SIGN VOCALIC RR + +11040 +BRAHMI VOWEL SIGN VOCALIC L + +11041 +BRAHMI VOWEL SIGN VOCALIC LL + +11042 +BRAHMI VOWEL SIGN E + +11043 +BRAHMI VOWEL SIGN AI + +11044 +BRAHMI VOWEL SIGN O + +11045 +BRAHMI VOWEL SIGN AU + +11046 +BRAHMI VIRAMA + +11047 +BRAHMI DANDA + +11048 +BRAHMI DOUBLE DANDA + +11049 +BRAHMI PUNCTUATION DOT + +1104A +BRAHMI PUNCTUATION DOUBLE DOT + +1104B +BRAHMI PUNCTUATION LINE + +1104C +BRAHMI PUNCTUATION CRESCENT BAR + +1104D +BRAHMI PUNCTUATION LOTUS + +11052 +BRAHMI NUMBER ONE + +11053 +BRAHMI NUMBER TWO + +11054 +BRAHMI NUMBER THREE + +11055 +BRAHMI NUMBER FOUR + +11056 +BRAHMI NUMBER FIVE + +11057 +BRAHMI NUMBER SIX + +11058 +BRAHMI NUMBER SEVEN + +11059 +BRAHMI NUMBER EIGHT + +1105A +BRAHMI NUMBER NINE + +1105B +BRAHMI NUMBER TEN + +1105C +BRAHMI NUMBER TWENTY + +1105D +BRAHMI NUMBER THIRTY + +1105E +BRAHMI NUMBER FORTY + +1105F +BRAHMI NUMBER FIFTY + +11060 +BRAHMI NUMBER SIXTY + +11061 +BRAHMI NUMBER SEVENTY + +11062 +BRAHMI NUMBER EIGHTY + +11063 +BRAHMI NUMBER NINETY + +11064 +BRAHMI NUMBER ONE HUNDRED + +11065 +BRAHMI NUMBER ONE THOUSAND + +11066 +BRAHMI DIGIT ZERO + +11067 +BRAHMI DIGIT ONE + +11068 +BRAHMI DIGIT TWO + +11069 +BRAHMI DIGIT THREE + +1106A +BRAHMI DIGIT FOUR + +1106B +BRAHMI DIGIT FIVE + +1106C +BRAHMI DIGIT SIX + +1106D +BRAHMI DIGIT SEVEN + +1106E +BRAHMI DIGIT EIGHT + +1106F +BRAHMI DIGIT NINE + +11070 +BRAHMI SIGN OLD TAMIL VIRAMA + +11071 +BRAHMI LETTER OLD TAMIL SHORT E + +11072 +BRAHMI LETTER OLD TAMIL SHORT O + +11073 +BRAHMI VOWEL SIGN OLD TAMIL SHORT E + +11074 +BRAHMI VOWEL SIGN OLD TAMIL SHORT O + +11075 +BRAHMI LETTER OLD TAMIL LLA + +1107F +BRAHMI NUMBER JOINER + +11080 +KAITHI SIGN CANDRABINDU + +11081 +KAITHI SIGN ANUSVARA + +11082 +KAITHI SIGN VISARGA + +11083 +KAITHI LETTER A + +11084 +KAITHI LETTER AA + +11085 +KAITHI LETTER I + +11086 +KAITHI LETTER II + +11087 +KAITHI LETTER U + +11088 +KAITHI LETTER UU + +11089 +KAITHI LETTER E + +1108A +KAITHI LETTER AI + +1108B +KAITHI LETTER O + +1108C +KAITHI LETTER AU + +1108D +KAITHI LETTER KA + +1108E +KAITHI LETTER KHA + +1108F +KAITHI LETTER GA + +11090 +KAITHI LETTER GHA + +11091 +KAITHI LETTER NGA + +11092 +KAITHI LETTER CA + +11093 +KAITHI LETTER CHA + +11094 +KAITHI LETTER JA + +11095 +KAITHI LETTER JHA + +11096 +KAITHI LETTER NYA + +11097 +KAITHI LETTER TTA + +11098 +KAITHI LETTER TTHA + +11099 +KAITHI LETTER DDA + +1109A +KAITHI LETTER DDDHA + +1109B +KAITHI LETTER DDHA + +1109C +KAITHI LETTER RHA + +1109D +KAITHI LETTER NNA + +1109E +KAITHI LETTER TA + +1109F +KAITHI LETTER THA + +110A0 +KAITHI LETTER DA + +110A1 +KAITHI LETTER DHA + +110A2 +KAITHI LETTER NA + +110A3 +KAITHI LETTER PA + +110A4 +KAITHI LETTER PHA + +110A5 +KAITHI LETTER BA + +110A6 +KAITHI LETTER BHA + +110A7 +KAITHI LETTER MA + +110A8 +KAITHI LETTER YA + +110A9 +KAITHI LETTER RA + +110AA +KAITHI LETTER LA + +110AB +KAITHI LETTER VA + +110AC +KAITHI LETTER SHA + +110AD +KAITHI LETTER SSA + +110AE +KAITHI LETTER SA + +110AF +KAITHI LETTER HA + +110B0 +KAITHI VOWEL SIGN AA + +110B1 +KAITHI VOWEL SIGN I + +110B2 +KAITHI VOWEL SIGN II + +110B3 +KAITHI VOWEL SIGN U + +110B4 +KAITHI VOWEL SIGN UU + +110B5 +KAITHI VOWEL SIGN E + +110B6 +KAITHI VOWEL SIGN AI + +110B7 +KAITHI VOWEL SIGN O + +110B8 +KAITHI VOWEL SIGN AU + +110B9 +KAITHI SIGN VIRAMA + +110BA +KAITHI SIGN NUKTA + +110BB +KAITHI ABBREVIATION SIGN + +110BC +KAITHI ENUMERATION SIGN + +110BD +KAITHI NUMBER SIGN + +110BE +KAITHI SECTION MARK + +110BF +KAITHI DOUBLE SECTION MARK + +110C0 +KAITHI DANDA + +110C1 +KAITHI DOUBLE DANDA + +110C2 +KAITHI VOWEL SIGN VOCALIC R + +110CD +KAITHI NUMBER SIGN ABOVE + +110D0 +SORA SOMPENG LETTER SAH + +110D1 +SORA SOMPENG LETTER TAH + +110D2 +SORA SOMPENG LETTER BAH + +110D3 +SORA SOMPENG LETTER CAH + +110D4 +SORA SOMPENG LETTER DAH + +110D5 +SORA SOMPENG LETTER GAH + +110D6 +SORA SOMPENG LETTER MAH + +110D7 +SORA SOMPENG LETTER NGAH + +110D8 +SORA SOMPENG LETTER LAH + +110D9 +SORA SOMPENG LETTER NAH + +110DA +SORA SOMPENG LETTER VAH + +110DB +SORA SOMPENG LETTER PAH + +110DC +SORA SOMPENG LETTER YAH + +110DD +SORA SOMPENG LETTER RAH + +110DE +SORA SOMPENG LETTER HAH + +110DF +SORA SOMPENG LETTER KAH + +110E0 +SORA SOMPENG LETTER JAH + +110E1 +SORA SOMPENG LETTER NYAH + +110E2 +SORA SOMPENG LETTER AH + +110E3 +SORA SOMPENG LETTER EEH + +110E4 +SORA SOMPENG LETTER IH + +110E5 +SORA SOMPENG LETTER UH + +110E6 +SORA SOMPENG LETTER OH + +110E7 +SORA SOMPENG LETTER EH + +110E8 +SORA SOMPENG LETTER MAE + +110F0 +SORA SOMPENG DIGIT ZERO + +110F1 +SORA SOMPENG DIGIT ONE + +110F2 +SORA SOMPENG DIGIT TWO + +110F3 +SORA SOMPENG DIGIT THREE + +110F4 +SORA SOMPENG DIGIT FOUR + +110F5 +SORA SOMPENG DIGIT FIVE + +110F6 +SORA SOMPENG DIGIT SIX + +110F7 +SORA SOMPENG DIGIT SEVEN + +110F8 +SORA SOMPENG DIGIT EIGHT + +110F9 +SORA SOMPENG DIGIT NINE + +11100 +CHAKMA SIGN CANDRABINDU + +11101 +CHAKMA SIGN ANUSVARA + +11102 +CHAKMA SIGN VISARGA + +11103 +CHAKMA LETTER AA + +11104 +CHAKMA LETTER I + +11105 +CHAKMA LETTER U + +11106 +CHAKMA LETTER E + +11107 +CHAKMA LETTER KAA + +11108 +CHAKMA LETTER KHAA + +11109 +CHAKMA LETTER GAA + +1110A +CHAKMA LETTER GHAA + +1110B +CHAKMA LETTER NGAA + +1110C +CHAKMA LETTER CAA + +1110D +CHAKMA LETTER CHAA + +1110E +CHAKMA LETTER JAA + +1110F +CHAKMA LETTER JHAA + +11110 +CHAKMA LETTER NYAA + +11111 +CHAKMA LETTER TTAA + +11112 +CHAKMA LETTER TTHAA + +11113 +CHAKMA LETTER DDAA + +11114 +CHAKMA LETTER DDHAA + +11115 +CHAKMA LETTER NNAA + +11116 +CHAKMA LETTER TAA + +11117 +CHAKMA LETTER THAA + +11118 +CHAKMA LETTER DAA + +11119 +CHAKMA LETTER DHAA + +1111A +CHAKMA LETTER NAA + +1111B +CHAKMA LETTER PAA + +1111C +CHAKMA LETTER PHAA + +1111D +CHAKMA LETTER BAA + +1111E +CHAKMA LETTER BHAA + +1111F +CHAKMA LETTER MAA + +11120 +CHAKMA LETTER YYAA + +11121 +CHAKMA LETTER YAA + +11122 +CHAKMA LETTER RAA + +11123 +CHAKMA LETTER LAA + +11124 +CHAKMA LETTER WAA + +11125 +CHAKMA LETTER SAA + +11126 +CHAKMA LETTER HAA + +11127 +CHAKMA VOWEL SIGN A + +11128 +CHAKMA VOWEL SIGN I + +11129 +CHAKMA VOWEL SIGN II + +1112A +CHAKMA VOWEL SIGN U + +1112B +CHAKMA VOWEL SIGN UU + +1112C +CHAKMA VOWEL SIGN E + +1112D +CHAKMA VOWEL SIGN AI + +1112E +CHAKMA VOWEL SIGN O + +1112F +CHAKMA VOWEL SIGN AU + +11130 +CHAKMA VOWEL SIGN OI + +11131 +CHAKMA O MARK + +11132 +CHAKMA AU MARK + +11133 +CHAKMA VIRAMA + +11134 +CHAKMA MAAYYAA + +11136 +CHAKMA DIGIT ZERO + +11137 +CHAKMA DIGIT ONE + +11138 +CHAKMA DIGIT TWO + +11139 +CHAKMA DIGIT THREE + +1113A +CHAKMA DIGIT FOUR + +1113B +CHAKMA DIGIT FIVE + +1113C +CHAKMA DIGIT SIX + +1113D +CHAKMA DIGIT SEVEN + +1113E +CHAKMA DIGIT EIGHT + +1113F +CHAKMA DIGIT NINE + +11140 +CHAKMA SECTION MARK + +11141 +CHAKMA DANDA + +11142 +CHAKMA DOUBLE DANDA + +11143 +CHAKMA QUESTION MARK + +11144 +CHAKMA LETTER LHAA + +11145 +CHAKMA VOWEL SIGN AA + +11146 +CHAKMA VOWEL SIGN EI + +11147 +CHAKMA LETTER VAA + +11150 +MAHAJANI LETTER A + +11151 +MAHAJANI LETTER I + +11152 +MAHAJANI LETTER U + +11153 +MAHAJANI LETTER E + +11154 +MAHAJANI LETTER O + +11155 +MAHAJANI LETTER KA + +11156 +MAHAJANI LETTER KHA + +11157 +MAHAJANI LETTER GA + +11158 +MAHAJANI LETTER GHA + +11159 +MAHAJANI LETTER CA + +1115A +MAHAJANI LETTER CHA + +1115B +MAHAJANI LETTER JA + +1115C +MAHAJANI LETTER JHA + +1115D +MAHAJANI LETTER NYA + +1115E +MAHAJANI LETTER TTA + +1115F +MAHAJANI LETTER TTHA + +11160 +MAHAJANI LETTER DDA + +11161 +MAHAJANI LETTER DDHA + +11162 +MAHAJANI LETTER NNA + +11163 +MAHAJANI LETTER TA + +11164 +MAHAJANI LETTER THA + +11165 +MAHAJANI LETTER DA + +11166 +MAHAJANI LETTER DHA + +11167 +MAHAJANI LETTER NA + +11168 +MAHAJANI LETTER PA + +11169 +MAHAJANI LETTER PHA + +1116A +MAHAJANI LETTER BA + +1116B +MAHAJANI LETTER BHA + +1116C +MAHAJANI LETTER MA + +1116D +MAHAJANI LETTER RA + +1116E +MAHAJANI LETTER LA + +1116F +MAHAJANI LETTER VA + +11170 +MAHAJANI LETTER SA + +11171 +MAHAJANI LETTER HA + +11172 +MAHAJANI LETTER RRA + +11173 +MAHAJANI SIGN NUKTA + +11174 +MAHAJANI ABBREVIATION SIGN + +11175 +MAHAJANI SECTION MARK + +11176 +MAHAJANI LIGATURE SHRI + +11180 +SHARADA SIGN CANDRABINDU + +11181 +SHARADA SIGN ANUSVARA + +11182 +SHARADA SIGN VISARGA + +11183 +SHARADA LETTER A + +11184 +SHARADA LETTER AA + +11185 +SHARADA LETTER I + +11186 +SHARADA LETTER II + +11187 +SHARADA LETTER U + +11188 +SHARADA LETTER UU + +11189 +SHARADA LETTER VOCALIC R + +1118A +SHARADA LETTER VOCALIC RR + +1118B +SHARADA LETTER VOCALIC L + +1118C +SHARADA LETTER VOCALIC LL + +1118D +SHARADA LETTER E + +1118E +SHARADA LETTER AI + +1118F +SHARADA LETTER O + +11190 +SHARADA LETTER AU + +11191 +SHARADA LETTER KA + +11192 +SHARADA LETTER KHA + +11193 +SHARADA LETTER GA + +11194 +SHARADA LETTER GHA + +11195 +SHARADA LETTER NGA + +11196 +SHARADA LETTER CA + +11197 +SHARADA LETTER CHA + +11198 +SHARADA LETTER JA + +11199 +SHARADA LETTER JHA + +1119A +SHARADA LETTER NYA + +1119B +SHARADA LETTER TTA + +1119C +SHARADA LETTER TTHA + +1119D +SHARADA LETTER DDA + +1119E +SHARADA LETTER DDHA + +1119F +SHARADA LETTER NNA + +111A0 +SHARADA LETTER TA + +111A1 +SHARADA LETTER THA + +111A2 +SHARADA LETTER DA + +111A3 +SHARADA LETTER DHA + +111A4 +SHARADA LETTER NA + +111A5 +SHARADA LETTER PA + +111A6 +SHARADA LETTER PHA + +111A7 +SHARADA LETTER BA + +111A8 +SHARADA LETTER BHA + +111A9 +SHARADA LETTER MA + +111AA +SHARADA LETTER YA + +111AB +SHARADA LETTER RA + +111AC +SHARADA LETTER LA + +111AD +SHARADA LETTER LLA + +111AE +SHARADA LETTER VA + +111AF +SHARADA LETTER SHA + +111B0 +SHARADA LETTER SSA + +111B1 +SHARADA LETTER SA + +111B2 +SHARADA LETTER HA + +111B3 +SHARADA VOWEL SIGN AA + +111B4 +SHARADA VOWEL SIGN I + +111B5 +SHARADA VOWEL SIGN II + +111B6 +SHARADA VOWEL SIGN U + +111B7 +SHARADA VOWEL SIGN UU + +111B8 +SHARADA VOWEL SIGN VOCALIC R + +111B9 +SHARADA VOWEL SIGN VOCALIC RR + +111BA +SHARADA VOWEL SIGN VOCALIC L + +111BB +SHARADA VOWEL SIGN VOCALIC LL + +111BC +SHARADA VOWEL SIGN E + +111BD +SHARADA VOWEL SIGN AI + +111BE +SHARADA VOWEL SIGN O + +111BF +SHARADA VOWEL SIGN AU + +111C0 +SHARADA SIGN VIRAMA + +111C1 +SHARADA SIGN AVAGRAHA + +111C2 +SHARADA SIGN JIHVAMULIYA + +111C3 +SHARADA SIGN UPADHMANIYA + +111C4 +SHARADA OM + +111C5 +SHARADA DANDA + +111C6 +SHARADA DOUBLE DANDA + +111C7 +SHARADA ABBREVIATION SIGN + +111C8 +SHARADA SEPARATOR + +111C9 +SHARADA SANDHI MARK + +111CA +SHARADA SIGN NUKTA + +111CB +SHARADA VOWEL MODIFIER MARK + +111CC +SHARADA EXTRA SHORT VOWEL MARK + +111CD +SHARADA SUTRA MARK + +111CE +SHARADA VOWEL SIGN PRISHTHAMATRA E + +111CF +SHARADA SIGN INVERTED CANDRABINDU + +111D0 +SHARADA DIGIT ZERO + +111D1 +SHARADA DIGIT ONE + +111D2 +SHARADA DIGIT TWO + +111D3 +SHARADA DIGIT THREE + +111D4 +SHARADA DIGIT FOUR + +111D5 +SHARADA DIGIT FIVE + +111D6 +SHARADA DIGIT SIX + +111D7 +SHARADA DIGIT SEVEN + +111D8 +SHARADA DIGIT EIGHT + +111D9 +SHARADA DIGIT NINE + +111DA +SHARADA EKAM + +111DB +SHARADA SIGN SIDDHAM + +111DC +SHARADA HEADSTROKE + +111DD +SHARADA CONTINUATION SIGN + +111DE +SHARADA SECTION MARK-1 + +111DF +SHARADA SECTION MARK-2 + +111E1 +SINHALA ARCHAIC DIGIT ONE + +111E2 +SINHALA ARCHAIC DIGIT TWO + +111E3 +SINHALA ARCHAIC DIGIT THREE + +111E4 +SINHALA ARCHAIC DIGIT FOUR + +111E5 +SINHALA ARCHAIC DIGIT FIVE + +111E6 +SINHALA ARCHAIC DIGIT SIX + +111E7 +SINHALA ARCHAIC DIGIT SEVEN + +111E8 +SINHALA ARCHAIC DIGIT EIGHT + +111E9 +SINHALA ARCHAIC DIGIT NINE + +111EA +SINHALA ARCHAIC NUMBER TEN + +111EB +SINHALA ARCHAIC NUMBER TWENTY + +111EC +SINHALA ARCHAIC NUMBER THIRTY + +111ED +SINHALA ARCHAIC NUMBER FORTY + +111EE +SINHALA ARCHAIC NUMBER FIFTY + +111EF +SINHALA ARCHAIC NUMBER SIXTY + +111F0 +SINHALA ARCHAIC NUMBER SEVENTY + +111F1 +SINHALA ARCHAIC NUMBER EIGHTY + +111F2 +SINHALA ARCHAIC NUMBER NINETY + +111F3 +SINHALA ARCHAIC NUMBER ONE HUNDRED + +111F4 +SINHALA ARCHAIC NUMBER ONE THOUSAND + +11200 +KHOJKI LETTER A + +11201 +KHOJKI LETTER AA + +11202 +KHOJKI LETTER I + +11203 +KHOJKI LETTER U + +11204 +KHOJKI LETTER E + +11205 +KHOJKI LETTER AI + +11206 +KHOJKI LETTER O + +11207 +KHOJKI LETTER AU + +11208 +KHOJKI LETTER KA + +11209 +KHOJKI LETTER KHA + +1120A +KHOJKI LETTER GA + +1120B +KHOJKI LETTER GGA + +1120C +KHOJKI LETTER GHA + +1120D +KHOJKI LETTER NGA + +1120E +KHOJKI LETTER CA + +1120F +KHOJKI LETTER CHA + +11210 +KHOJKI LETTER JA + +11211 +KHOJKI LETTER JJA + +11213 +KHOJKI LETTER NYA + +11214 +KHOJKI LETTER TTA + +11215 +KHOJKI LETTER TTHA + +11216 +KHOJKI LETTER DDA + +11217 +KHOJKI LETTER DDHA + +11218 +KHOJKI LETTER NNA + +11219 +KHOJKI LETTER TA + +1121A +KHOJKI LETTER THA + +1121B +KHOJKI LETTER DA + +1121C +KHOJKI LETTER DDDA + +1121D +KHOJKI LETTER DHA + +1121E +KHOJKI LETTER NA + +1121F +KHOJKI LETTER PA + +11220 +KHOJKI LETTER PHA + +11221 +KHOJKI LETTER BA + +11222 +KHOJKI LETTER BBA + +11223 +KHOJKI LETTER BHA + +11224 +KHOJKI LETTER MA + +11225 +KHOJKI LETTER YA + +11226 +KHOJKI LETTER RA + +11227 +KHOJKI LETTER LA + +11228 +KHOJKI LETTER VA + +11229 +KHOJKI LETTER SA + +1122A +KHOJKI LETTER HA + +1122B +KHOJKI LETTER LLA + +1122C +KHOJKI VOWEL SIGN AA + +1122D +KHOJKI VOWEL SIGN I + +1122E +KHOJKI VOWEL SIGN II + +1122F +KHOJKI VOWEL SIGN U + +11230 +KHOJKI VOWEL SIGN E + +11231 +KHOJKI VOWEL SIGN AI + +11232 +KHOJKI VOWEL SIGN O + +11233 +KHOJKI VOWEL SIGN AU + +11234 +KHOJKI SIGN ANUSVARA + +11235 +KHOJKI SIGN VIRAMA + +11236 +KHOJKI SIGN NUKTA + +11237 +KHOJKI SIGN SHADDA + +11238 +KHOJKI DANDA + +11239 +KHOJKI DOUBLE DANDA + +1123A +KHOJKI WORD SEPARATOR + +1123B +KHOJKI SECTION MARK + +1123C +KHOJKI DOUBLE SECTION MARK + +1123D +KHOJKI ABBREVIATION SIGN + +1123E +KHOJKI SIGN SUKUN + +1123F +KHOJKI LETTER QA + +11240 +KHOJKI LETTER SHORT I + +11241 +KHOJKI VOWEL SIGN VOCALIC R + +11280 +MULTANI LETTER A + +11281 +MULTANI LETTER I + +11282 +MULTANI LETTER U + +11283 +MULTANI LETTER E + +11284 +MULTANI LETTER KA + +11285 +MULTANI LETTER KHA + +11286 +MULTANI LETTER GA + +11288 +MULTANI LETTER GHA + +1128A +MULTANI LETTER CA + +1128B +MULTANI LETTER CHA + +1128C +MULTANI LETTER JA + +1128D +MULTANI LETTER JJA + +1128F +MULTANI LETTER NYA + +11290 +MULTANI LETTER TTA + +11291 +MULTANI LETTER TTHA + +11292 +MULTANI LETTER DDA + +11293 +MULTANI LETTER DDDA + +11294 +MULTANI LETTER DDHA + +11295 +MULTANI LETTER NNA + +11296 +MULTANI LETTER TA + +11297 +MULTANI LETTER THA + +11298 +MULTANI LETTER DA + +11299 +MULTANI LETTER DHA + +1129A +MULTANI LETTER NA + +1129B +MULTANI LETTER PA + +1129C +MULTANI LETTER PHA + +1129D +MULTANI LETTER BA + +1129F +MULTANI LETTER BHA + +112A0 +MULTANI LETTER MA + +112A1 +MULTANI LETTER YA + +112A2 +MULTANI LETTER RA + +112A3 +MULTANI LETTER LA + +112A4 +MULTANI LETTER VA + +112A5 +MULTANI LETTER SA + +112A6 +MULTANI LETTER HA + +112A7 +MULTANI LETTER RRA + +112A8 +MULTANI LETTER RHA + +112A9 +MULTANI SECTION MARK + +112B0 +KHUDAWADI LETTER A + +112B1 +KHUDAWADI LETTER AA + +112B2 +KHUDAWADI LETTER I + +112B3 +KHUDAWADI LETTER II + +112B4 +KHUDAWADI LETTER U + +112B5 +KHUDAWADI LETTER UU + +112B6 +KHUDAWADI LETTER E + +112B7 +KHUDAWADI LETTER AI + +112B8 +KHUDAWADI LETTER O + +112B9 +KHUDAWADI LETTER AU + +112BA +KHUDAWADI LETTER KA + +112BB +KHUDAWADI LETTER KHA + +112BC +KHUDAWADI LETTER GA + +112BD +KHUDAWADI LETTER GGA + +112BE +KHUDAWADI LETTER GHA + +112BF +KHUDAWADI LETTER NGA + +112C0 +KHUDAWADI LETTER CA + +112C1 +KHUDAWADI LETTER CHA + +112C2 +KHUDAWADI LETTER JA + +112C3 +KHUDAWADI LETTER JJA + +112C4 +KHUDAWADI LETTER JHA + +112C5 +KHUDAWADI LETTER NYA + +112C6 +KHUDAWADI LETTER TTA + +112C7 +KHUDAWADI LETTER TTHA + +112C8 +KHUDAWADI LETTER DDA + +112C9 +KHUDAWADI LETTER DDDA + +112CA +KHUDAWADI LETTER RRA + +112CB +KHUDAWADI LETTER DDHA + +112CC +KHUDAWADI LETTER NNA + +112CD +KHUDAWADI LETTER TA + +112CE +KHUDAWADI LETTER THA + +112CF +KHUDAWADI LETTER DA + +112D0 +KHUDAWADI LETTER DHA + +112D1 +KHUDAWADI LETTER NA + +112D2 +KHUDAWADI LETTER PA + +112D3 +KHUDAWADI LETTER PHA + +112D4 +KHUDAWADI LETTER BA + +112D5 +KHUDAWADI LETTER BBA + +112D6 +KHUDAWADI LETTER BHA + +112D7 +KHUDAWADI LETTER MA + +112D8 +KHUDAWADI LETTER YA + +112D9 +KHUDAWADI LETTER RA + +112DA +KHUDAWADI LETTER LA + +112DB +KHUDAWADI LETTER VA + +112DC +KHUDAWADI LETTER SHA + +112DD +KHUDAWADI LETTER SA + +112DE +KHUDAWADI LETTER HA + +112DF +KHUDAWADI SIGN ANUSVARA + +112E0 +KHUDAWADI VOWEL SIGN AA + +112E1 +KHUDAWADI VOWEL SIGN I + +112E2 +KHUDAWADI VOWEL SIGN II + +112E3 +KHUDAWADI VOWEL SIGN U + +112E4 +KHUDAWADI VOWEL SIGN UU + +112E5 +KHUDAWADI VOWEL SIGN E + +112E6 +KHUDAWADI VOWEL SIGN AI + +112E7 +KHUDAWADI VOWEL SIGN O + +112E8 +KHUDAWADI VOWEL SIGN AU + +112E9 +KHUDAWADI SIGN NUKTA + +112EA +KHUDAWADI SIGN VIRAMA + +112F0 +KHUDAWADI DIGIT ZERO + +112F1 +KHUDAWADI DIGIT ONE + +112F2 +KHUDAWADI DIGIT TWO + +112F3 +KHUDAWADI DIGIT THREE + +112F4 +KHUDAWADI DIGIT FOUR + +112F5 +KHUDAWADI DIGIT FIVE + +112F6 +KHUDAWADI DIGIT SIX + +112F7 +KHUDAWADI DIGIT SEVEN + +112F8 +KHUDAWADI DIGIT EIGHT + +112F9 +KHUDAWADI DIGIT NINE + +11300 +GRANTHA SIGN COMBINING ANUSVARA ABOVE + +11301 +GRANTHA SIGN CANDRABINDU + +11302 +GRANTHA SIGN ANUSVARA + +11303 +GRANTHA SIGN VISARGA + +11305 +GRANTHA LETTER A + +11306 +GRANTHA LETTER AA + +11307 +GRANTHA LETTER I + +11308 +GRANTHA LETTER II + +11309 +GRANTHA LETTER U + +1130A +GRANTHA LETTER UU + +1130B +GRANTHA LETTER VOCALIC R + +1130C +GRANTHA LETTER VOCALIC L + +1130F +GRANTHA LETTER EE + +11310 +GRANTHA LETTER AI + +11313 +GRANTHA LETTER OO + +11314 +GRANTHA LETTER AU + +11315 +GRANTHA LETTER KA + +11316 +GRANTHA LETTER KHA + +11317 +GRANTHA LETTER GA + +11318 +GRANTHA LETTER GHA + +11319 +GRANTHA LETTER NGA + +1131A +GRANTHA LETTER CA + +1131B +GRANTHA LETTER CHA + +1131C +GRANTHA LETTER JA + +1131D +GRANTHA LETTER JHA + +1131E +GRANTHA LETTER NYA + +1131F +GRANTHA LETTER TTA + +11320 +GRANTHA LETTER TTHA + +11321 +GRANTHA LETTER DDA + +11322 +GRANTHA LETTER DDHA + +11323 +GRANTHA LETTER NNA + +11324 +GRANTHA LETTER TA + +11325 +GRANTHA LETTER THA + +11326 +GRANTHA LETTER DA + +11327 +GRANTHA LETTER DHA + +11328 +GRANTHA LETTER NA + +1132A +GRANTHA LETTER PA + +1132B +GRANTHA LETTER PHA + +1132C +GRANTHA LETTER BA + +1132D +GRANTHA LETTER BHA + +1132E +GRANTHA LETTER MA + +1132F +GRANTHA LETTER YA + +11330 +GRANTHA LETTER RA + +11332 +GRANTHA LETTER LA + +11333 +GRANTHA LETTER LLA + +11335 +GRANTHA LETTER VA + +11336 +GRANTHA LETTER SHA + +11337 +GRANTHA LETTER SSA + +11338 +GRANTHA LETTER SA + +11339 +GRANTHA LETTER HA + +1133B +COMBINING BINDU BELOW + +1133C +GRANTHA SIGN NUKTA + +1133D +GRANTHA SIGN AVAGRAHA + +1133E +GRANTHA VOWEL SIGN AA + +1133F +GRANTHA VOWEL SIGN I + +11340 +GRANTHA VOWEL SIGN II + +11341 +GRANTHA VOWEL SIGN U + +11342 +GRANTHA VOWEL SIGN UU + +11343 +GRANTHA VOWEL SIGN VOCALIC R + +11344 +GRANTHA VOWEL SIGN VOCALIC RR + +11347 +GRANTHA VOWEL SIGN EE + +11348 +GRANTHA VOWEL SIGN AI + +1134B +GRANTHA VOWEL SIGN OO + +1134C +GRANTHA VOWEL SIGN AU + +1134D +GRANTHA SIGN VIRAMA + +11350 +GRANTHA OM + +11357 +GRANTHA AU LENGTH MARK + +1135D +GRANTHA SIGN PLUTA + +1135E +GRANTHA LETTER VEDIC ANUSVARA + +1135F +GRANTHA LETTER VEDIC DOUBLE ANUSVARA + +11360 +GRANTHA LETTER VOCALIC RR + +11361 +GRANTHA LETTER VOCALIC LL + +11362 +GRANTHA VOWEL SIGN VOCALIC L + +11363 +GRANTHA VOWEL SIGN VOCALIC LL + +11366 +COMBINING GRANTHA DIGIT ZERO + +11367 +COMBINING GRANTHA DIGIT ONE + +11368 +COMBINING GRANTHA DIGIT TWO + +11369 +COMBINING GRANTHA DIGIT THREE + +1136A +COMBINING GRANTHA DIGIT FOUR + +1136B +COMBINING GRANTHA DIGIT FIVE + +1136C +COMBINING GRANTHA DIGIT SIX + +11370 +COMBINING GRANTHA LETTER A + +11371 +COMBINING GRANTHA LETTER KA + +11372 +COMBINING GRANTHA LETTER NA + +11373 +COMBINING GRANTHA LETTER VI + +11374 +COMBINING GRANTHA LETTER PA + +11380 +TULU-TIGALARI LETTER A + +11381 +TULU-TIGALARI LETTER AA + +11382 +TULU-TIGALARI LETTER I + +11383 +TULU-TIGALARI LETTER II + +11384 +TULU-TIGALARI LETTER U + +11385 +TULU-TIGALARI LETTER UU + +11386 +TULU-TIGALARI LETTER VOCALIC R + +11387 +TULU-TIGALARI LETTER VOCALIC RR + +11388 +TULU-TIGALARI LETTER VOCALIC L + +11389 +TULU-TIGALARI LETTER VOCALIC LL + +1138B +TULU-TIGALARI LETTER EE + +1138E +TULU-TIGALARI LETTER AI + +11390 +TULU-TIGALARI LETTER OO + +11391 +TULU-TIGALARI LETTER AU + +11392 +TULU-TIGALARI LETTER KA + +11393 +TULU-TIGALARI LETTER KHA + +11394 +TULU-TIGALARI LETTER GA + +11395 +TULU-TIGALARI LETTER GHA + +11396 +TULU-TIGALARI LETTER NGA + +11397 +TULU-TIGALARI LETTER CA + +11398 +TULU-TIGALARI LETTER CHA + +11399 +TULU-TIGALARI LETTER JA + +1139A +TULU-TIGALARI LETTER JHA + +1139B +TULU-TIGALARI LETTER NYA + +1139C +TULU-TIGALARI LETTER TTA + +1139D +TULU-TIGALARI LETTER TTHA + +1139E +TULU-TIGALARI LETTER DDA + +1139F +TULU-TIGALARI LETTER DDHA + +113A0 +TULU-TIGALARI LETTER NNA + +113A1 +TULU-TIGALARI LETTER TA + +113A2 +TULU-TIGALARI LETTER THA + +113A3 +TULU-TIGALARI LETTER DA + +113A4 +TULU-TIGALARI LETTER DHA + +113A5 +TULU-TIGALARI LETTER NA + +113A6 +TULU-TIGALARI LETTER PA + +113A7 +TULU-TIGALARI LETTER PHA + +113A8 +TULU-TIGALARI LETTER BA + +113A9 +TULU-TIGALARI LETTER BHA + +113AA +TULU-TIGALARI LETTER MA + +113AB +TULU-TIGALARI LETTER YA + +113AC +TULU-TIGALARI LETTER RA + +113AD +TULU-TIGALARI LETTER LA + +113AE +TULU-TIGALARI LETTER VA + +113AF +TULU-TIGALARI LETTER SHA + +113B0 +TULU-TIGALARI LETTER SSA + +113B1 +TULU-TIGALARI LETTER SA + +113B2 +TULU-TIGALARI LETTER HA + +113B3 +TULU-TIGALARI LETTER LLA + +113B4 +TULU-TIGALARI LETTER RRA + +113B5 +TULU-TIGALARI LETTER LLLA + +113B7 +TULU-TIGALARI SIGN AVAGRAHA + +113B8 +TULU-TIGALARI VOWEL SIGN AA + +113B9 +TULU-TIGALARI VOWEL SIGN I + +113BA +TULU-TIGALARI VOWEL SIGN II + +113BB +TULU-TIGALARI VOWEL SIGN U + +113BC +TULU-TIGALARI VOWEL SIGN UU + +113BD +TULU-TIGALARI VOWEL SIGN VOCALIC R + +113BE +TULU-TIGALARI VOWEL SIGN VOCALIC RR + +113BF +TULU-TIGALARI VOWEL SIGN VOCALIC L + +113C0 +TULU-TIGALARI VOWEL SIGN VOCALIC LL + +113C2 +TULU-TIGALARI VOWEL SIGN EE + +113C5 +TULU-TIGALARI VOWEL SIGN AI + +113C7 +TULU-TIGALARI VOWEL SIGN OO + +113C8 +TULU-TIGALARI VOWEL SIGN AU + +113C9 +TULU-TIGALARI AU LENGTH MARK + +113CA +TULU-TIGALARI SIGN CANDRA ANUNASIKA + +113CC +TULU-TIGALARI SIGN ANUSVARA + +113CD +TULU-TIGALARI SIGN VISARGA + +113CE +TULU-TIGALARI SIGN VIRAMA + +113CF +TULU-TIGALARI SIGN LOOPED VIRAMA + +113D0 +TULU-TIGALARI CONJOINER + +113D1 +TULU-TIGALARI REPHA + +113D2 +TULU-TIGALARI GEMINATION MARK + +113D3 +TULU-TIGALARI SIGN PLUTA + +113D4 +TULU-TIGALARI DANDA + +113D5 +TULU-TIGALARI DOUBLE DANDA + +113D7 +TULU-TIGALARI SIGN OM PUSHPIKA + +113D8 +TULU-TIGALARI SIGN SHRII PUSHPIKA + +113E1 +TULU-TIGALARI VEDIC TONE SVARITA + +113E2 +TULU-TIGALARI VEDIC TONE ANUDATTA + +11400 +NEWA LETTER A + +11401 +NEWA LETTER AA + +11402 +NEWA LETTER I + +11403 +NEWA LETTER II + +11404 +NEWA LETTER U + +11405 +NEWA LETTER UU + +11406 +NEWA LETTER VOCALIC R + +11407 +NEWA LETTER VOCALIC RR + +11408 +NEWA LETTER VOCALIC L + +11409 +NEWA LETTER VOCALIC LL + +1140A +NEWA LETTER E + +1140B +NEWA LETTER AI + +1140C +NEWA LETTER O + +1140D +NEWA LETTER AU + +1140E +NEWA LETTER KA + +1140F +NEWA LETTER KHA + +11410 +NEWA LETTER GA + +11411 +NEWA LETTER GHA + +11412 +NEWA LETTER NGA + +11413 +NEWA LETTER NGHA + +11414 +NEWA LETTER CA + +11415 +NEWA LETTER CHA + +11416 +NEWA LETTER JA + +11417 +NEWA LETTER JHA + +11418 +NEWA LETTER NYA + +11419 +NEWA LETTER NYHA + +1141A +NEWA LETTER TTA + +1141B +NEWA LETTER TTHA + +1141C +NEWA LETTER DDA + +1141D +NEWA LETTER DDHA + +1141E +NEWA LETTER NNA + +1141F +NEWA LETTER TA + +11420 +NEWA LETTER THA + +11421 +NEWA LETTER DA + +11422 +NEWA LETTER DHA + +11423 +NEWA LETTER NA + +11424 +NEWA LETTER NHA + +11425 +NEWA LETTER PA + +11426 +NEWA LETTER PHA + +11427 +NEWA LETTER BA + +11428 +NEWA LETTER BHA + +11429 +NEWA LETTER MA + +1142A +NEWA LETTER MHA + +1142B +NEWA LETTER YA + +1142C +NEWA LETTER RA + +1142D +NEWA LETTER RHA + +1142E +NEWA LETTER LA + +1142F +NEWA LETTER LHA + +11430 +NEWA LETTER WA + +11431 +NEWA LETTER SHA + +11432 +NEWA LETTER SSA + +11433 +NEWA LETTER SA + +11434 +NEWA LETTER HA + +11435 +NEWA VOWEL SIGN AA + +11436 +NEWA VOWEL SIGN I + +11437 +NEWA VOWEL SIGN II + +11438 +NEWA VOWEL SIGN U + +11439 +NEWA VOWEL SIGN UU + +1143A +NEWA VOWEL SIGN VOCALIC R + +1143B +NEWA VOWEL SIGN VOCALIC RR + +1143C +NEWA VOWEL SIGN VOCALIC L + +1143D +NEWA VOWEL SIGN VOCALIC LL + +1143E +NEWA VOWEL SIGN E + +1143F +NEWA VOWEL SIGN AI + +11440 +NEWA VOWEL SIGN O + +11441 +NEWA VOWEL SIGN AU + +11442 +NEWA SIGN VIRAMA + +11443 +NEWA SIGN CANDRABINDU + +11444 +NEWA SIGN ANUSVARA + +11445 +NEWA SIGN VISARGA + +11446 +NEWA SIGN NUKTA + +11447 +NEWA SIGN AVAGRAHA + +11448 +NEWA SIGN FINAL ANUSVARA + +11449 +NEWA OM + +1144A +NEWA SIDDHI + +1144B +NEWA DANDA + +1144C +NEWA DOUBLE DANDA + +1144D +NEWA COMMA + +1144E +NEWA GAP FILLER + +1144F +NEWA ABBREVIATION SIGN + +11450 +NEWA DIGIT ZERO + +11451 +NEWA DIGIT ONE + +11452 +NEWA DIGIT TWO + +11453 +NEWA DIGIT THREE + +11454 +NEWA DIGIT FOUR + +11455 +NEWA DIGIT FIVE + +11456 +NEWA DIGIT SIX + +11457 +NEWA DIGIT SEVEN + +11458 +NEWA DIGIT EIGHT + +11459 +NEWA DIGIT NINE + +1145A +NEWA DOUBLE COMMA + +1145B +NEWA PLACEHOLDER MARK + +1145D +NEWA INSERTION SIGN + +1145E +NEWA SANDHI MARK + +1145F +NEWA LETTER VEDIC ANUSVARA + +11460 +NEWA SIGN JIHVAMULIYA + +11461 +NEWA SIGN UPADHMANIYA + +11480 +TIRHUTA ANJI + +11481 +TIRHUTA LETTER A + +11482 +TIRHUTA LETTER AA + +11483 +TIRHUTA LETTER I + +11484 +TIRHUTA LETTER II + +11485 +TIRHUTA LETTER U + +11486 +TIRHUTA LETTER UU + +11487 +TIRHUTA LETTER VOCALIC R + +11488 +TIRHUTA LETTER VOCALIC RR + +11489 +TIRHUTA LETTER VOCALIC L + +1148A +TIRHUTA LETTER VOCALIC LL + +1148B +TIRHUTA LETTER E + +1148C +TIRHUTA LETTER AI + +1148D +TIRHUTA LETTER O + +1148E +TIRHUTA LETTER AU + +1148F +TIRHUTA LETTER KA + +11490 +TIRHUTA LETTER KHA + +11491 +TIRHUTA LETTER GA + +11492 +TIRHUTA LETTER GHA + +11493 +TIRHUTA LETTER NGA + +11494 +TIRHUTA LETTER CA + +11495 +TIRHUTA LETTER CHA + +11496 +TIRHUTA LETTER JA + +11497 +TIRHUTA LETTER JHA + +11498 +TIRHUTA LETTER NYA + +11499 +TIRHUTA LETTER TTA + +1149A +TIRHUTA LETTER TTHA + +1149B +TIRHUTA LETTER DDA + +1149C +TIRHUTA LETTER DDHA + +1149D +TIRHUTA LETTER NNA + +1149E +TIRHUTA LETTER TA + +1149F +TIRHUTA LETTER THA + +114A0 +TIRHUTA LETTER DA + +114A1 +TIRHUTA LETTER DHA + +114A2 +TIRHUTA LETTER NA + +114A3 +TIRHUTA LETTER PA + +114A4 +TIRHUTA LETTER PHA + +114A5 +TIRHUTA LETTER BA + +114A6 +TIRHUTA LETTER BHA + +114A7 +TIRHUTA LETTER MA + +114A8 +TIRHUTA LETTER YA + +114A9 +TIRHUTA LETTER RA + +114AA +TIRHUTA LETTER LA + +114AB +TIRHUTA LETTER VA + +114AC +TIRHUTA LETTER SHA + +114AD +TIRHUTA LETTER SSA + +114AE +TIRHUTA LETTER SA + +114AF +TIRHUTA LETTER HA + +114B0 +TIRHUTA VOWEL SIGN AA + +114B1 +TIRHUTA VOWEL SIGN I + +114B2 +TIRHUTA VOWEL SIGN II + +114B3 +TIRHUTA VOWEL SIGN U + +114B4 +TIRHUTA VOWEL SIGN UU + +114B5 +TIRHUTA VOWEL SIGN VOCALIC R + +114B6 +TIRHUTA VOWEL SIGN VOCALIC RR + +114B7 +TIRHUTA VOWEL SIGN VOCALIC L + +114B8 +TIRHUTA VOWEL SIGN VOCALIC LL + +114B9 +TIRHUTA VOWEL SIGN E + +114BA +TIRHUTA VOWEL SIGN SHORT E + +114BB +TIRHUTA VOWEL SIGN AI + +114BC +TIRHUTA VOWEL SIGN O + +114BD +TIRHUTA VOWEL SIGN SHORT O + +114BE +TIRHUTA VOWEL SIGN AU + +114BF +TIRHUTA SIGN CANDRABINDU + +114C0 +TIRHUTA SIGN ANUSVARA + +114C1 +TIRHUTA SIGN VISARGA + +114C2 +TIRHUTA SIGN VIRAMA + +114C3 +TIRHUTA SIGN NUKTA + +114C4 +TIRHUTA SIGN AVAGRAHA + +114C5 +TIRHUTA GVANG + +114C6 +TIRHUTA ABBREVIATION SIGN + +114C7 +TIRHUTA OM + +114D0 +TIRHUTA DIGIT ZERO + +114D1 +TIRHUTA DIGIT ONE + +114D2 +TIRHUTA DIGIT TWO + +114D3 +TIRHUTA DIGIT THREE + +114D4 +TIRHUTA DIGIT FOUR + +114D5 +TIRHUTA DIGIT FIVE + +114D6 +TIRHUTA DIGIT SIX + +114D7 +TIRHUTA DIGIT SEVEN + +114D8 +TIRHUTA DIGIT EIGHT + +114D9 +TIRHUTA DIGIT NINE + +11580 +SIDDHAM LETTER A + +11581 +SIDDHAM LETTER AA + +11582 +SIDDHAM LETTER I + +11583 +SIDDHAM LETTER II + +11584 +SIDDHAM LETTER U + +11585 +SIDDHAM LETTER UU + +11586 +SIDDHAM LETTER VOCALIC R + +11587 +SIDDHAM LETTER VOCALIC RR + +11588 +SIDDHAM LETTER VOCALIC L + +11589 +SIDDHAM LETTER VOCALIC LL + +1158A +SIDDHAM LETTER E + +1158B +SIDDHAM LETTER AI + +1158C +SIDDHAM LETTER O + +1158D +SIDDHAM LETTER AU + +1158E +SIDDHAM LETTER KA + +1158F +SIDDHAM LETTER KHA + +11590 +SIDDHAM LETTER GA + +11591 +SIDDHAM LETTER GHA + +11592 +SIDDHAM LETTER NGA + +11593 +SIDDHAM LETTER CA + +11594 +SIDDHAM LETTER CHA + +11595 +SIDDHAM LETTER JA + +11596 +SIDDHAM LETTER JHA + +11597 +SIDDHAM LETTER NYA + +11598 +SIDDHAM LETTER TTA + +11599 +SIDDHAM LETTER TTHA + +1159A +SIDDHAM LETTER DDA + +1159B +SIDDHAM LETTER DDHA + +1159C +SIDDHAM LETTER NNA + +1159D +SIDDHAM LETTER TA + +1159E +SIDDHAM LETTER THA + +1159F +SIDDHAM LETTER DA + +115A0 +SIDDHAM LETTER DHA + +115A1 +SIDDHAM LETTER NA + +115A2 +SIDDHAM LETTER PA + +115A3 +SIDDHAM LETTER PHA + +115A4 +SIDDHAM LETTER BA + +115A5 +SIDDHAM LETTER BHA + +115A6 +SIDDHAM LETTER MA + +115A7 +SIDDHAM LETTER YA + +115A8 +SIDDHAM LETTER RA + +115A9 +SIDDHAM LETTER LA + +115AA +SIDDHAM LETTER VA + +115AB +SIDDHAM LETTER SHA + +115AC +SIDDHAM LETTER SSA + +115AD +SIDDHAM LETTER SA + +115AE +SIDDHAM LETTER HA + +115AF +SIDDHAM VOWEL SIGN AA + +115B0 +SIDDHAM VOWEL SIGN I + +115B1 +SIDDHAM VOWEL SIGN II + +115B2 +SIDDHAM VOWEL SIGN U + +115B3 +SIDDHAM VOWEL SIGN UU + +115B4 +SIDDHAM VOWEL SIGN VOCALIC R + +115B5 +SIDDHAM VOWEL SIGN VOCALIC RR + +115B8 +SIDDHAM VOWEL SIGN E + +115B9 +SIDDHAM VOWEL SIGN AI + +115BA +SIDDHAM VOWEL SIGN O + +115BB +SIDDHAM VOWEL SIGN AU + +115BC +SIDDHAM SIGN CANDRABINDU + +115BD +SIDDHAM SIGN ANUSVARA + +115BE +SIDDHAM SIGN VISARGA + +115BF +SIDDHAM SIGN VIRAMA + +115C0 +SIDDHAM SIGN NUKTA + +115C1 +SIDDHAM SIGN SIDDHAM + +115C2 +SIDDHAM DANDA + +115C3 +SIDDHAM DOUBLE DANDA + +115C4 +SIDDHAM SEPARATOR DOT + +115C5 +SIDDHAM SEPARATOR BAR + +115C6 +SIDDHAM REPETITION MARK-1 + +115C7 +SIDDHAM REPETITION MARK-2 + +115C8 +SIDDHAM REPETITION MARK-3 + +115C9 +SIDDHAM END OF TEXT MARK + +115CA +SIDDHAM SECTION MARK WITH TRIDENT AND U-SHAPED ORNAMENTS + +115CB +SIDDHAM SECTION MARK WITH TRIDENT AND DOTTED CRESCENTS + +115CC +SIDDHAM SECTION MARK WITH RAYS AND DOTTED CRESCENTS + +115CD +SIDDHAM SECTION MARK WITH RAYS AND DOTTED DOUBLE CRESCENTS + +115CE +SIDDHAM SECTION MARK WITH RAYS AND DOTTED TRIPLE CRESCENTS + +115CF +SIDDHAM SECTION MARK DOUBLE RING + +115D0 +SIDDHAM SECTION MARK DOUBLE RING WITH RAYS + +115D1 +SIDDHAM SECTION MARK WITH DOUBLE CRESCENTS + +115D2 +SIDDHAM SECTION MARK WITH TRIPLE CRESCENTS + +115D3 +SIDDHAM SECTION MARK WITH QUADRUPLE CRESCENTS + +115D4 +SIDDHAM SECTION MARK WITH SEPTUPLE CRESCENTS + +115D5 +SIDDHAM SECTION MARK WITH CIRCLES AND RAYS + +115D6 +SIDDHAM SECTION MARK WITH CIRCLES AND TWO ENCLOSURES + +115D7 +SIDDHAM SECTION MARK WITH CIRCLES AND FOUR ENCLOSURES + +115D8 +SIDDHAM LETTER THREE-CIRCLE ALTERNATE I + +115D9 +SIDDHAM LETTER TWO-CIRCLE ALTERNATE I + +115DA +SIDDHAM LETTER TWO-CIRCLE ALTERNATE II + +115DB +SIDDHAM LETTER ALTERNATE U + +115DC +SIDDHAM VOWEL SIGN ALTERNATE U + +115DD +SIDDHAM VOWEL SIGN ALTERNATE UU + +11600 +MODI LETTER A + +11601 +MODI LETTER AA + +11602 +MODI LETTER I + +11603 +MODI LETTER II + +11604 +MODI LETTER U + +11605 +MODI LETTER UU + +11606 +MODI LETTER VOCALIC R + +11607 +MODI LETTER VOCALIC RR + +11608 +MODI LETTER VOCALIC L + +11609 +MODI LETTER VOCALIC LL + +1160A +MODI LETTER E + +1160B +MODI LETTER AI + +1160C +MODI LETTER O + +1160D +MODI LETTER AU + +1160E +MODI LETTER KA + +1160F +MODI LETTER KHA + +11610 +MODI LETTER GA + +11611 +MODI LETTER GHA + +11612 +MODI LETTER NGA + +11613 +MODI LETTER CA + +11614 +MODI LETTER CHA + +11615 +MODI LETTER JA + +11616 +MODI LETTER JHA + +11617 +MODI LETTER NYA + +11618 +MODI LETTER TTA + +11619 +MODI LETTER TTHA + +1161A +MODI LETTER DDA + +1161B +MODI LETTER DDHA + +1161C +MODI LETTER NNA + +1161D +MODI LETTER TA + +1161E +MODI LETTER THA + +1161F +MODI LETTER DA + +11620 +MODI LETTER DHA + +11621 +MODI LETTER NA + +11622 +MODI LETTER PA + +11623 +MODI LETTER PHA + +11624 +MODI LETTER BA + +11625 +MODI LETTER BHA + +11626 +MODI LETTER MA + +11627 +MODI LETTER YA + +11628 +MODI LETTER RA + +11629 +MODI LETTER LA + +1162A +MODI LETTER VA + +1162B +MODI LETTER SHA + +1162C +MODI LETTER SSA + +1162D +MODI LETTER SA + +1162E +MODI LETTER HA + +1162F +MODI LETTER LLA + +11630 +MODI VOWEL SIGN AA + +11631 +MODI VOWEL SIGN I + +11632 +MODI VOWEL SIGN II + +11633 +MODI VOWEL SIGN U + +11634 +MODI VOWEL SIGN UU + +11635 +MODI VOWEL SIGN VOCALIC R + +11636 +MODI VOWEL SIGN VOCALIC RR + +11637 +MODI VOWEL SIGN VOCALIC L + +11638 +MODI VOWEL SIGN VOCALIC LL + +11639 +MODI VOWEL SIGN E + +1163A +MODI VOWEL SIGN AI + +1163B +MODI VOWEL SIGN O + +1163C +MODI VOWEL SIGN AU + +1163D +MODI SIGN ANUSVARA + +1163E +MODI SIGN VISARGA + +1163F +MODI SIGN VIRAMA + +11640 +MODI SIGN ARDHACANDRA + +11641 +MODI DANDA + +11642 +MODI DOUBLE DANDA + +11643 +MODI ABBREVIATION SIGN + +11644 +MODI SIGN HUVA + +11650 +MODI DIGIT ZERO + +11651 +MODI DIGIT ONE + +11652 +MODI DIGIT TWO + +11653 +MODI DIGIT THREE + +11654 +MODI DIGIT FOUR + +11655 +MODI DIGIT FIVE + +11656 +MODI DIGIT SIX + +11657 +MODI DIGIT SEVEN + +11658 +MODI DIGIT EIGHT + +11659 +MODI DIGIT NINE + +11660 +MONGOLIAN BIRGA WITH ORNAMENT + +11661 +MONGOLIAN ROTATED BIRGA + +11662 +MONGOLIAN DOUBLE BIRGA WITH ORNAMENT + +11663 +MONGOLIAN TRIPLE BIRGA WITH ORNAMENT + +11664 +MONGOLIAN BIRGA WITH DOUBLE ORNAMENT + +11665 +MONGOLIAN ROTATED BIRGA WITH ORNAMENT + +11666 +MONGOLIAN ROTATED BIRGA WITH DOUBLE ORNAMENT + +11667 +MONGOLIAN INVERTED BIRGA + +11668 +MONGOLIAN INVERTED BIRGA WITH DOUBLE ORNAMENT + +11669 +MONGOLIAN SWIRL BIRGA + +1166A +MONGOLIAN SWIRL BIRGA WITH ORNAMENT + +1166B +MONGOLIAN SWIRL BIRGA WITH DOUBLE ORNAMENT + +1166C +MONGOLIAN TURNED SWIRL BIRGA WITH DOUBLE ORNAMENT + +11680 +TAKRI LETTER A + +11681 +TAKRI LETTER AA + +11682 +TAKRI LETTER I + +11683 +TAKRI LETTER II + +11684 +TAKRI LETTER U + +11685 +TAKRI LETTER UU + +11686 +TAKRI LETTER E + +11687 +TAKRI LETTER AI + +11688 +TAKRI LETTER O + +11689 +TAKRI LETTER AU + +1168A +TAKRI LETTER KA + +1168B +TAKRI LETTER KHA + +1168C +TAKRI LETTER GA + +1168D +TAKRI LETTER GHA + +1168E +TAKRI LETTER NGA + +1168F +TAKRI LETTER CA + +11690 +TAKRI LETTER CHA + +11691 +TAKRI LETTER JA + +11692 +TAKRI LETTER JHA + +11693 +TAKRI LETTER NYA + +11694 +TAKRI LETTER TTA + +11695 +TAKRI LETTER TTHA + +11696 +TAKRI LETTER DDA + +11697 +TAKRI LETTER DDHA + +11698 +TAKRI LETTER NNA + +11699 +TAKRI LETTER TA + +1169A +TAKRI LETTER THA + +1169B +TAKRI LETTER DA + +1169C +TAKRI LETTER DHA + +1169D +TAKRI LETTER NA + +1169E +TAKRI LETTER PA + +1169F +TAKRI LETTER PHA + +116A0 +TAKRI LETTER BA + +116A1 +TAKRI LETTER BHA + +116A2 +TAKRI LETTER MA + +116A3 +TAKRI LETTER YA + +116A4 +TAKRI LETTER RA + +116A5 +TAKRI LETTER LA + +116A6 +TAKRI LETTER VA + +116A7 +TAKRI LETTER SHA + +116A8 +TAKRI LETTER SA + +116A9 +TAKRI LETTER HA + +116AA +TAKRI LETTER RRA + +116AB +TAKRI SIGN ANUSVARA + +116AC +TAKRI SIGN VISARGA + +116AD +TAKRI VOWEL SIGN AA + +116AE +TAKRI VOWEL SIGN I + +116AF +TAKRI VOWEL SIGN II + +116B0 +TAKRI VOWEL SIGN U + +116B1 +TAKRI VOWEL SIGN UU + +116B2 +TAKRI VOWEL SIGN E + +116B3 +TAKRI VOWEL SIGN AI + +116B4 +TAKRI VOWEL SIGN O + +116B5 +TAKRI VOWEL SIGN AU + +116B6 +TAKRI SIGN VIRAMA + +116B7 +TAKRI SIGN NUKTA + +116B8 +TAKRI LETTER ARCHAIC KHA + +116B9 +TAKRI ABBREVIATION SIGN + +116C0 +TAKRI DIGIT ZERO + +116C1 +TAKRI DIGIT ONE + +116C2 +TAKRI DIGIT TWO + +116C3 +TAKRI DIGIT THREE + +116C4 +TAKRI DIGIT FOUR + +116C5 +TAKRI DIGIT FIVE + +116C6 +TAKRI DIGIT SIX + +116C7 +TAKRI DIGIT SEVEN + +116C8 +TAKRI DIGIT EIGHT + +116C9 +TAKRI DIGIT NINE + +116D0 +MYANMAR PAO DIGIT ZERO + +116D1 +MYANMAR PAO DIGIT ONE + +116D2 +MYANMAR PAO DIGIT TWO + +116D3 +MYANMAR PAO DIGIT THREE + +116D4 +MYANMAR PAO DIGIT FOUR + +116D5 +MYANMAR PAO DIGIT FIVE + +116D6 +MYANMAR PAO DIGIT SIX + +116D7 +MYANMAR PAO DIGIT SEVEN + +116D8 +MYANMAR PAO DIGIT EIGHT + +116D9 +MYANMAR PAO DIGIT NINE + +116DA +MYANMAR EASTERN PWO KAREN DIGIT ZERO + +116DB +MYANMAR EASTERN PWO KAREN DIGIT ONE + +116DC +MYANMAR EASTERN PWO KAREN DIGIT TWO + +116DD +MYANMAR EASTERN PWO KAREN DIGIT THREE + +116DE +MYANMAR EASTERN PWO KAREN DIGIT FOUR + +116DF +MYANMAR EASTERN PWO KAREN DIGIT FIVE + +116E0 +MYANMAR EASTERN PWO KAREN DIGIT SIX + +116E1 +MYANMAR EASTERN PWO KAREN DIGIT SEVEN + +116E2 +MYANMAR EASTERN PWO KAREN DIGIT EIGHT + +116E3 +MYANMAR EASTERN PWO KAREN DIGIT NINE + +11700 +AHOM LETTER KA + +11701 +AHOM LETTER KHA + +11702 +AHOM LETTER NGA + +11703 +AHOM LETTER NA + +11704 +AHOM LETTER TA + +11705 +AHOM LETTER ALTERNATE TA + +11706 +AHOM LETTER PA + +11707 +AHOM LETTER PHA + +11708 +AHOM LETTER BA + +11709 +AHOM LETTER MA + +1170A +AHOM LETTER JA + +1170B +AHOM LETTER CHA + +1170C +AHOM LETTER THA + +1170D +AHOM LETTER RA + +1170E +AHOM LETTER LA + +1170F +AHOM LETTER SA + +11710 +AHOM LETTER NYA + +11711 +AHOM LETTER HA + +11712 +AHOM LETTER A + +11713 +AHOM LETTER DA + +11714 +AHOM LETTER DHA + +11715 +AHOM LETTER GA + +11716 +AHOM LETTER ALTERNATE GA + +11717 +AHOM LETTER GHA + +11718 +AHOM LETTER BHA + +11719 +AHOM LETTER JHA + +1171A +AHOM LETTER ALTERNATE BA + +1171D +AHOM CONSONANT SIGN MEDIAL LA + +1171E +AHOM CONSONANT SIGN MEDIAL RA + +1171F +AHOM CONSONANT SIGN MEDIAL LIGATING RA + +11720 +AHOM VOWEL SIGN A + +11721 +AHOM VOWEL SIGN AA + +11722 +AHOM VOWEL SIGN I + +11723 +AHOM VOWEL SIGN II + +11724 +AHOM VOWEL SIGN U + +11725 +AHOM VOWEL SIGN UU + +11726 +AHOM VOWEL SIGN E + +11727 +AHOM VOWEL SIGN AW + +11728 +AHOM VOWEL SIGN O + +11729 +AHOM VOWEL SIGN AI + +1172A +AHOM VOWEL SIGN AM + +1172B +AHOM SIGN KILLER + +11730 +AHOM DIGIT ZERO + +11731 +AHOM DIGIT ONE + +11732 +AHOM DIGIT TWO + +11733 +AHOM DIGIT THREE + +11734 +AHOM DIGIT FOUR + +11735 +AHOM DIGIT FIVE + +11736 +AHOM DIGIT SIX + +11737 +AHOM DIGIT SEVEN + +11738 +AHOM DIGIT EIGHT + +11739 +AHOM DIGIT NINE + +1173A +AHOM NUMBER TEN + +1173B +AHOM NUMBER TWENTY + +1173C +AHOM SIGN SMALL SECTION + +1173D +AHOM SIGN SECTION + +1173E +AHOM SIGN RULAI + +1173F +AHOM SYMBOL VI + +11740 +AHOM LETTER CA + +11741 +AHOM LETTER TTA + +11742 +AHOM LETTER TTHA + +11743 +AHOM LETTER DDA + +11744 +AHOM LETTER DDHA + +11745 +AHOM LETTER NNA + +11746 +AHOM LETTER LLA + +11800 +DOGRA LETTER A + +11801 +DOGRA LETTER AA + +11802 +DOGRA LETTER I + +11803 +DOGRA LETTER II + +11804 +DOGRA LETTER U + +11805 +DOGRA LETTER UU + +11806 +DOGRA LETTER E + +11807 +DOGRA LETTER AI + +11808 +DOGRA LETTER O + +11809 +DOGRA LETTER AU + +1180A +DOGRA LETTER KA + +1180B +DOGRA LETTER KHA + +1180C +DOGRA LETTER GA + +1180D +DOGRA LETTER GHA + +1180E +DOGRA LETTER NGA + +1180F +DOGRA LETTER CA + +11810 +DOGRA LETTER CHA + +11811 +DOGRA LETTER JA + +11812 +DOGRA LETTER JHA + +11813 +DOGRA LETTER NYA + +11814 +DOGRA LETTER TTA + +11815 +DOGRA LETTER TTHA + +11816 +DOGRA LETTER DDA + +11817 +DOGRA LETTER DDHA + +11818 +DOGRA LETTER NNA + +11819 +DOGRA LETTER TA + +1181A +DOGRA LETTER THA + +1181B +DOGRA LETTER DA + +1181C +DOGRA LETTER DHA + +1181D +DOGRA LETTER NA + +1181E +DOGRA LETTER PA + +1181F +DOGRA LETTER PHA + +11820 +DOGRA LETTER BA + +11821 +DOGRA LETTER BHA + +11822 +DOGRA LETTER MA + +11823 +DOGRA LETTER YA + +11824 +DOGRA LETTER RA + +11825 +DOGRA LETTER LA + +11826 +DOGRA LETTER VA + +11827 +DOGRA LETTER SHA + +11828 +DOGRA LETTER SSA + +11829 +DOGRA LETTER SA + +1182A +DOGRA LETTER HA + +1182B +DOGRA LETTER RRA + +1182C +DOGRA VOWEL SIGN AA + +1182D +DOGRA VOWEL SIGN I + +1182E +DOGRA VOWEL SIGN II + +1182F +DOGRA VOWEL SIGN U + +11830 +DOGRA VOWEL SIGN UU + +11831 +DOGRA VOWEL SIGN VOCALIC R + +11832 +DOGRA VOWEL SIGN VOCALIC RR + +11833 +DOGRA VOWEL SIGN E + +11834 +DOGRA VOWEL SIGN AI + +11835 +DOGRA VOWEL SIGN O + +11836 +DOGRA VOWEL SIGN AU + +11837 +DOGRA SIGN ANUSVARA + +11838 +DOGRA SIGN VISARGA + +11839 +DOGRA SIGN VIRAMA + +1183A +DOGRA SIGN NUKTA + +1183B +DOGRA ABBREVIATION SIGN + +118A0 +WARANG CITI CAPITAL LETTER NGAA + +118A1 +WARANG CITI CAPITAL LETTER A + +118A2 +WARANG CITI CAPITAL LETTER WI + +118A3 +WARANG CITI CAPITAL LETTER YU + +118A4 +WARANG CITI CAPITAL LETTER YA + +118A5 +WARANG CITI CAPITAL LETTER YO + +118A6 +WARANG CITI CAPITAL LETTER II + +118A7 +WARANG CITI CAPITAL LETTER UU + +118A8 +WARANG CITI CAPITAL LETTER E + +118A9 +WARANG CITI CAPITAL LETTER O + +118AA +WARANG CITI CAPITAL LETTER ANG + +118AB +WARANG CITI CAPITAL LETTER GA + +118AC +WARANG CITI CAPITAL LETTER KO + +118AD +WARANG CITI CAPITAL LETTER ENY + +118AE +WARANG CITI CAPITAL LETTER YUJ + +118AF +WARANG CITI CAPITAL LETTER UC + +118B0 +WARANG CITI CAPITAL LETTER ENN + +118B1 +WARANG CITI CAPITAL LETTER ODD + +118B2 +WARANG CITI CAPITAL LETTER TTE + +118B3 +WARANG CITI CAPITAL LETTER NUNG + +118B4 +WARANG CITI CAPITAL LETTER DA + +118B5 +WARANG CITI CAPITAL LETTER AT + +118B6 +WARANG CITI CAPITAL LETTER AM + +118B7 +WARANG CITI CAPITAL LETTER BU + +118B8 +WARANG CITI CAPITAL LETTER PU + +118B9 +WARANG CITI CAPITAL LETTER HIYO + +118BA +WARANG CITI CAPITAL LETTER HOLO + +118BB +WARANG CITI CAPITAL LETTER HORR + +118BC +WARANG CITI CAPITAL LETTER HAR + +118BD +WARANG CITI CAPITAL LETTER SSUU + +118BE +WARANG CITI CAPITAL LETTER SII + +118BF +WARANG CITI CAPITAL LETTER VIYO + +118C0 +WARANG CITI SMALL LETTER NGAA + +118C1 +WARANG CITI SMALL LETTER A + +118C2 +WARANG CITI SMALL LETTER WI + +118C3 +WARANG CITI SMALL LETTER YU + +118C4 +WARANG CITI SMALL LETTER YA + +118C5 +WARANG CITI SMALL LETTER YO + +118C6 +WARANG CITI SMALL LETTER II + +118C7 +WARANG CITI SMALL LETTER UU + +118C8 +WARANG CITI SMALL LETTER E + +118C9 +WARANG CITI SMALL LETTER O + +118CA +WARANG CITI SMALL LETTER ANG + +118CB +WARANG CITI SMALL LETTER GA + +118CC +WARANG CITI SMALL LETTER KO + +118CD +WARANG CITI SMALL LETTER ENY + +118CE +WARANG CITI SMALL LETTER YUJ + +118CF +WARANG CITI SMALL LETTER UC + +118D0 +WARANG CITI SMALL LETTER ENN + +118D1 +WARANG CITI SMALL LETTER ODD + +118D2 +WARANG CITI SMALL LETTER TTE + +118D3 +WARANG CITI SMALL LETTER NUNG + +118D4 +WARANG CITI SMALL LETTER DA + +118D5 +WARANG CITI SMALL LETTER AT + +118D6 +WARANG CITI SMALL LETTER AM + +118D7 +WARANG CITI SMALL LETTER BU + +118D8 +WARANG CITI SMALL LETTER PU + +118D9 +WARANG CITI SMALL LETTER HIYO + +118DA +WARANG CITI SMALL LETTER HOLO + +118DB +WARANG CITI SMALL LETTER HORR + +118DC +WARANG CITI SMALL LETTER HAR + +118DD +WARANG CITI SMALL LETTER SSUU + +118DE +WARANG CITI SMALL LETTER SII + +118DF +WARANG CITI SMALL LETTER VIYO + +118E0 +WARANG CITI DIGIT ZERO + +118E1 +WARANG CITI DIGIT ONE + +118E2 +WARANG CITI DIGIT TWO + +118E3 +WARANG CITI DIGIT THREE + +118E4 +WARANG CITI DIGIT FOUR + +118E5 +WARANG CITI DIGIT FIVE + +118E6 +WARANG CITI DIGIT SIX + +118E7 +WARANG CITI DIGIT SEVEN + +118E8 +WARANG CITI DIGIT EIGHT + +118E9 +WARANG CITI DIGIT NINE + +118EA +WARANG CITI NUMBER TEN + +118EB +WARANG CITI NUMBER TWENTY + +118EC +WARANG CITI NUMBER THIRTY + +118ED +WARANG CITI NUMBER FORTY + +118EE +WARANG CITI NUMBER FIFTY + +118EF +WARANG CITI NUMBER SIXTY + +118F0 +WARANG CITI NUMBER SEVENTY + +118F1 +WARANG CITI NUMBER EIGHTY + +118F2 +WARANG CITI NUMBER NINETY + +118FF +WARANG CITI OM + +11900 +DIVES AKURU LETTER A + +11901 +DIVES AKURU LETTER AA + +11902 +DIVES AKURU LETTER I + +11903 +DIVES AKURU LETTER II + +11904 +DIVES AKURU LETTER U + +11905 +DIVES AKURU LETTER UU + +11906 +DIVES AKURU LETTER E + +11909 +DIVES AKURU LETTER O + +1190C +DIVES AKURU LETTER KA + +1190D +DIVES AKURU LETTER KHA + +1190E +DIVES AKURU LETTER GA + +1190F +DIVES AKURU LETTER GHA + +11910 +DIVES AKURU LETTER NGA + +11911 +DIVES AKURU LETTER CA + +11912 +DIVES AKURU LETTER CHA + +11913 +DIVES AKURU LETTER JA + +11915 +DIVES AKURU LETTER NYA + +11916 +DIVES AKURU LETTER TTA + +11918 +DIVES AKURU LETTER DDA + +11919 +DIVES AKURU LETTER DDHA + +1191A +DIVES AKURU LETTER NNA + +1191B +DIVES AKURU LETTER TA + +1191C +DIVES AKURU LETTER THA + +1191D +DIVES AKURU LETTER DA + +1191E +DIVES AKURU LETTER DHA + +1191F +DIVES AKURU LETTER NA + +11920 +DIVES AKURU LETTER PA + +11921 +DIVES AKURU LETTER PHA + +11922 +DIVES AKURU LETTER BA + +11923 +DIVES AKURU LETTER BHA + +11924 +DIVES AKURU LETTER MA + +11925 +DIVES AKURU LETTER YA + +11926 +DIVES AKURU LETTER YYA + +11927 +DIVES AKURU LETTER RA + +11928 +DIVES AKURU LETTER LA + +11929 +DIVES AKURU LETTER VA + +1192A +DIVES AKURU LETTER SHA + +1192B +DIVES AKURU LETTER SSA + +1192C +DIVES AKURU LETTER SA + +1192D +DIVES AKURU LETTER HA + +1192E +DIVES AKURU LETTER LLA + +1192F +DIVES AKURU LETTER ZA + +11930 +DIVES AKURU VOWEL SIGN AA + +11931 +DIVES AKURU VOWEL SIGN I + +11932 +DIVES AKURU VOWEL SIGN II + +11933 +DIVES AKURU VOWEL SIGN U + +11934 +DIVES AKURU VOWEL SIGN UU + +11935 +DIVES AKURU VOWEL SIGN E + +11937 +DIVES AKURU VOWEL SIGN AI + +11938 +DIVES AKURU VOWEL SIGN O + +1193B +DIVES AKURU SIGN ANUSVARA + +1193C +DIVES AKURU SIGN CANDRABINDU + +1193D +DIVES AKURU SIGN HALANTA + +1193E +DIVES AKURU VIRAMA + +1193F +DIVES AKURU PREFIXED NASAL SIGN + +11940 +DIVES AKURU MEDIAL YA + +11941 +DIVES AKURU INITIAL RA + +11942 +DIVES AKURU MEDIAL RA + +11943 +DIVES AKURU SIGN NUKTA + +11944 +DIVES AKURU DOUBLE DANDA + +11945 +DIVES AKURU GAP FILLER + +11946 +DIVES AKURU END OF TEXT MARK + +11950 +DIVES AKURU DIGIT ZERO + +11951 +DIVES AKURU DIGIT ONE + +11952 +DIVES AKURU DIGIT TWO + +11953 +DIVES AKURU DIGIT THREE + +11954 +DIVES AKURU DIGIT FOUR + +11955 +DIVES AKURU DIGIT FIVE + +11956 +DIVES AKURU DIGIT SIX + +11957 +DIVES AKURU DIGIT SEVEN + +11958 +DIVES AKURU DIGIT EIGHT + +11959 +DIVES AKURU DIGIT NINE + +119A0 +NANDINAGARI LETTER A + +119A1 +NANDINAGARI LETTER AA + +119A2 +NANDINAGARI LETTER I + +119A3 +NANDINAGARI LETTER II + +119A4 +NANDINAGARI LETTER U + +119A5 +NANDINAGARI LETTER UU + +119A6 +NANDINAGARI LETTER VOCALIC R + +119A7 +NANDINAGARI LETTER VOCALIC RR + +119AA +NANDINAGARI LETTER E + +119AB +NANDINAGARI LETTER AI + +119AC +NANDINAGARI LETTER O + +119AD +NANDINAGARI LETTER AU + +119AE +NANDINAGARI LETTER KA + +119AF +NANDINAGARI LETTER KHA + +119B0 +NANDINAGARI LETTER GA + +119B1 +NANDINAGARI LETTER GHA + +119B2 +NANDINAGARI LETTER NGA + +119B3 +NANDINAGARI LETTER CA + +119B4 +NANDINAGARI LETTER CHA + +119B5 +NANDINAGARI LETTER JA + +119B6 +NANDINAGARI LETTER JHA + +119B7 +NANDINAGARI LETTER NYA + +119B8 +NANDINAGARI LETTER TTA + +119B9 +NANDINAGARI LETTER TTHA + +119BA +NANDINAGARI LETTER DDA + +119BB +NANDINAGARI LETTER DDHA + +119BC +NANDINAGARI LETTER NNA + +119BD +NANDINAGARI LETTER TA + +119BE +NANDINAGARI LETTER THA + +119BF +NANDINAGARI LETTER DA + +119C0 +NANDINAGARI LETTER DHA + +119C1 +NANDINAGARI LETTER NA + +119C2 +NANDINAGARI LETTER PA + +119C3 +NANDINAGARI LETTER PHA + +119C4 +NANDINAGARI LETTER BA + +119C5 +NANDINAGARI LETTER BHA + +119C6 +NANDINAGARI LETTER MA + +119C7 +NANDINAGARI LETTER YA + +119C8 +NANDINAGARI LETTER RA + +119C9 +NANDINAGARI LETTER LA + +119CA +NANDINAGARI LETTER VA + +119CB +NANDINAGARI LETTER SHA + +119CC +NANDINAGARI LETTER SSA + +119CD +NANDINAGARI LETTER SA + +119CE +NANDINAGARI LETTER HA + +119CF +NANDINAGARI LETTER LLA + +119D0 +NANDINAGARI LETTER RRA + +119D1 +NANDINAGARI VOWEL SIGN AA + +119D2 +NANDINAGARI VOWEL SIGN I + +119D3 +NANDINAGARI VOWEL SIGN II + +119D4 +NANDINAGARI VOWEL SIGN U + +119D5 +NANDINAGARI VOWEL SIGN UU + +119D6 +NANDINAGARI VOWEL SIGN VOCALIC R + +119D7 +NANDINAGARI VOWEL SIGN VOCALIC RR + +119DA +NANDINAGARI VOWEL SIGN E + +119DB +NANDINAGARI VOWEL SIGN AI + +119DC +NANDINAGARI VOWEL SIGN O + +119DD +NANDINAGARI VOWEL SIGN AU + +119DE +NANDINAGARI SIGN ANUSVARA + +119DF +NANDINAGARI SIGN VISARGA + +119E0 +NANDINAGARI SIGN VIRAMA + +119E1 +NANDINAGARI SIGN AVAGRAHA + +119E2 +NANDINAGARI SIGN SIDDHAM + +119E3 +NANDINAGARI HEADSTROKE + +119E4 +NANDINAGARI VOWEL SIGN PRISHTHAMATRA E + +11A00 +ZANABAZAR SQUARE LETTER A + +11A01 +ZANABAZAR SQUARE VOWEL SIGN I + +11A02 +ZANABAZAR SQUARE VOWEL SIGN UE + +11A03 +ZANABAZAR SQUARE VOWEL SIGN U + +11A04 +ZANABAZAR SQUARE VOWEL SIGN E + +11A05 +ZANABAZAR SQUARE VOWEL SIGN OE + +11A06 +ZANABAZAR SQUARE VOWEL SIGN O + +11A07 +ZANABAZAR SQUARE VOWEL SIGN AI + +11A08 +ZANABAZAR SQUARE VOWEL SIGN AU + +11A09 +ZANABAZAR SQUARE VOWEL SIGN REVERSED I + +11A0A +ZANABAZAR SQUARE VOWEL LENGTH MARK + +11A0B +ZANABAZAR SQUARE LETTER KA + +11A0C +ZANABAZAR SQUARE LETTER KHA + +11A0D +ZANABAZAR SQUARE LETTER GA + +11A0E +ZANABAZAR SQUARE LETTER GHA + +11A0F +ZANABAZAR SQUARE LETTER NGA + +11A10 +ZANABAZAR SQUARE LETTER CA + +11A11 +ZANABAZAR SQUARE LETTER CHA + +11A12 +ZANABAZAR SQUARE LETTER JA + +11A13 +ZANABAZAR SQUARE LETTER NYA + +11A14 +ZANABAZAR SQUARE LETTER TTA + +11A15 +ZANABAZAR SQUARE LETTER TTHA + +11A16 +ZANABAZAR SQUARE LETTER DDA + +11A17 +ZANABAZAR SQUARE LETTER DDHA + +11A18 +ZANABAZAR SQUARE LETTER NNA + +11A19 +ZANABAZAR SQUARE LETTER TA + +11A1A +ZANABAZAR SQUARE LETTER THA + +11A1B +ZANABAZAR SQUARE LETTER DA + +11A1C +ZANABAZAR SQUARE LETTER DHA + +11A1D +ZANABAZAR SQUARE LETTER NA + +11A1E +ZANABAZAR SQUARE LETTER PA + +11A1F +ZANABAZAR SQUARE LETTER PHA + +11A20 +ZANABAZAR SQUARE LETTER BA + +11A21 +ZANABAZAR SQUARE LETTER BHA + +11A22 +ZANABAZAR SQUARE LETTER MA + +11A23 +ZANABAZAR SQUARE LETTER TSA + +11A24 +ZANABAZAR SQUARE LETTER TSHA + +11A25 +ZANABAZAR SQUARE LETTER DZA + +11A26 +ZANABAZAR SQUARE LETTER DZHA + +11A27 +ZANABAZAR SQUARE LETTER ZHA + +11A28 +ZANABAZAR SQUARE LETTER ZA + +11A29 +ZANABAZAR SQUARE LETTER -A + +11A2A +ZANABAZAR SQUARE LETTER YA + +11A2B +ZANABAZAR SQUARE LETTER RA + +11A2C +ZANABAZAR SQUARE LETTER LA + +11A2D +ZANABAZAR SQUARE LETTER VA + +11A2E +ZANABAZAR SQUARE LETTER SHA + +11A2F +ZANABAZAR SQUARE LETTER SSA + +11A30 +ZANABAZAR SQUARE LETTER SA + +11A31 +ZANABAZAR SQUARE LETTER HA + +11A32 +ZANABAZAR SQUARE LETTER KSSA + +11A33 +ZANABAZAR SQUARE FINAL CONSONANT MARK + +11A34 +ZANABAZAR SQUARE SIGN VIRAMA + +11A35 +ZANABAZAR SQUARE SIGN CANDRABINDU + +11A36 +ZANABAZAR SQUARE SIGN CANDRABINDU WITH ORNAMENT + +11A37 +ZANABAZAR SQUARE SIGN CANDRA WITH ORNAMENT + +11A38 +ZANABAZAR SQUARE SIGN ANUSVARA + +11A39 +ZANABAZAR SQUARE SIGN VISARGA + +11A3A +ZANABAZAR SQUARE CLUSTER-INITIAL LETTER RA + +11A3B +ZANABAZAR SQUARE CLUSTER-FINAL LETTER YA + +11A3C +ZANABAZAR SQUARE CLUSTER-FINAL LETTER RA + +11A3D +ZANABAZAR SQUARE CLUSTER-FINAL LETTER LA + +11A3E +ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA + +11A3F +ZANABAZAR SQUARE INITIAL HEAD MARK + +11A40 +ZANABAZAR SQUARE CLOSING HEAD MARK + +11A41 +ZANABAZAR SQUARE MARK TSHEG + +11A42 +ZANABAZAR SQUARE MARK SHAD + +11A43 +ZANABAZAR SQUARE MARK DOUBLE SHAD + +11A44 +ZANABAZAR SQUARE MARK LONG TSHEG + +11A45 +ZANABAZAR SQUARE INITIAL DOUBLE-LINED HEAD MARK + +11A46 +ZANABAZAR SQUARE CLOSING DOUBLE-LINED HEAD MARK + +11A47 +ZANABAZAR SQUARE SUBJOINER + +11A50 +SOYOMBO LETTER A + +11A51 +SOYOMBO VOWEL SIGN I + +11A52 +SOYOMBO VOWEL SIGN UE + +11A53 +SOYOMBO VOWEL SIGN U + +11A54 +SOYOMBO VOWEL SIGN E + +11A55 +SOYOMBO VOWEL SIGN O + +11A56 +SOYOMBO VOWEL SIGN OE + +11A57 +SOYOMBO VOWEL SIGN AI + +11A58 +SOYOMBO VOWEL SIGN AU + +11A59 +SOYOMBO VOWEL SIGN VOCALIC R + +11A5A +SOYOMBO VOWEL SIGN VOCALIC L + +11A5B +SOYOMBO VOWEL LENGTH MARK + +11A5C +SOYOMBO LETTER KA + +11A5D +SOYOMBO LETTER KHA + +11A5E +SOYOMBO LETTER GA + +11A5F +SOYOMBO LETTER GHA + +11A60 +SOYOMBO LETTER NGA + +11A61 +SOYOMBO LETTER CA + +11A62 +SOYOMBO LETTER CHA + +11A63 +SOYOMBO LETTER JA + +11A64 +SOYOMBO LETTER JHA + +11A65 +SOYOMBO LETTER NYA + +11A66 +SOYOMBO LETTER TTA + +11A67 +SOYOMBO LETTER TTHA + +11A68 +SOYOMBO LETTER DDA + +11A69 +SOYOMBO LETTER DDHA + +11A6A +SOYOMBO LETTER NNA + +11A6B +SOYOMBO LETTER TA + +11A6C +SOYOMBO LETTER THA + +11A6D +SOYOMBO LETTER DA + +11A6E +SOYOMBO LETTER DHA + +11A6F +SOYOMBO LETTER NA + +11A70 +SOYOMBO LETTER PA + +11A71 +SOYOMBO LETTER PHA + +11A72 +SOYOMBO LETTER BA + +11A73 +SOYOMBO LETTER BHA + +11A74 +SOYOMBO LETTER MA + +11A75 +SOYOMBO LETTER TSA + +11A76 +SOYOMBO LETTER TSHA + +11A77 +SOYOMBO LETTER DZA + +11A78 +SOYOMBO LETTER ZHA + +11A79 +SOYOMBO LETTER ZA + +11A7A +SOYOMBO LETTER -A + +11A7B +SOYOMBO LETTER YA + +11A7C +SOYOMBO LETTER RA + +11A7D +SOYOMBO LETTER LA + +11A7E +SOYOMBO LETTER VA + +11A7F +SOYOMBO LETTER SHA + +11A80 +SOYOMBO LETTER SSA + +11A81 +SOYOMBO LETTER SA + +11A82 +SOYOMBO LETTER HA + +11A83 +SOYOMBO LETTER KSSA + +11A84 +SOYOMBO SIGN JIHVAMULIYA + +11A85 +SOYOMBO SIGN UPADHMANIYA + +11A86 +SOYOMBO CLUSTER-INITIAL LETTER RA + +11A87 +SOYOMBO CLUSTER-INITIAL LETTER LA + +11A88 +SOYOMBO CLUSTER-INITIAL LETTER SHA + +11A89 +SOYOMBO CLUSTER-INITIAL LETTER SA + +11A8A +SOYOMBO FINAL CONSONANT SIGN G + +11A8B +SOYOMBO FINAL CONSONANT SIGN K + +11A8C +SOYOMBO FINAL CONSONANT SIGN NG + +11A8D +SOYOMBO FINAL CONSONANT SIGN D + +11A8E +SOYOMBO FINAL CONSONANT SIGN N + +11A8F +SOYOMBO FINAL CONSONANT SIGN B + +11A90 +SOYOMBO FINAL CONSONANT SIGN M + +11A91 +SOYOMBO FINAL CONSONANT SIGN R + +11A92 +SOYOMBO FINAL CONSONANT SIGN L + +11A93 +SOYOMBO FINAL CONSONANT SIGN SH + +11A94 +SOYOMBO FINAL CONSONANT SIGN S + +11A95 +SOYOMBO FINAL CONSONANT SIGN -A + +11A96 +SOYOMBO SIGN ANUSVARA + +11A97 +SOYOMBO SIGN VISARGA + +11A98 +SOYOMBO GEMINATION MARK + +11A99 +SOYOMBO SUBJOINER + +11A9A +SOYOMBO MARK TSHEG + +11A9B +SOYOMBO MARK SHAD + +11A9C +SOYOMBO MARK DOUBLE SHAD + +11A9D +SOYOMBO MARK PLUTA + +11A9E +SOYOMBO HEAD MARK WITH MOON AND SUN AND TRIPLE FLAME + +11A9F +SOYOMBO HEAD MARK WITH MOON AND SUN AND FLAME + +11AA0 +SOYOMBO HEAD MARK WITH MOON AND SUN + +11AA1 +SOYOMBO TERMINAL MARK-1 + +11AA2 +SOYOMBO TERMINAL MARK-2 + +11AB0 +CANADIAN SYLLABICS NATTILIK HI + +11AB1 +CANADIAN SYLLABICS NATTILIK HII + +11AB2 +CANADIAN SYLLABICS NATTILIK HO + +11AB3 +CANADIAN SYLLABICS NATTILIK HOO + +11AB4 +CANADIAN SYLLABICS NATTILIK HA + +11AB5 +CANADIAN SYLLABICS NATTILIK HAA + +11AB6 +CANADIAN SYLLABICS NATTILIK SHRI + +11AB7 +CANADIAN SYLLABICS NATTILIK SHRII + +11AB8 +CANADIAN SYLLABICS NATTILIK SHRO + +11AB9 +CANADIAN SYLLABICS NATTILIK SHROO + +11ABA +CANADIAN SYLLABICS NATTILIK SHRA + +11ABB +CANADIAN SYLLABICS NATTILIK SHRAA + +11ABC +CANADIAN SYLLABICS SPE + +11ABD +CANADIAN SYLLABICS SPI + +11ABE +CANADIAN SYLLABICS SPO + +11ABF +CANADIAN SYLLABICS SPA + +11AC0 +PAU CIN HAU LETTER PA + +11AC1 +PAU CIN HAU LETTER KA + +11AC2 +PAU CIN HAU LETTER LA + +11AC3 +PAU CIN HAU LETTER MA + +11AC4 +PAU CIN HAU LETTER DA + +11AC5 +PAU CIN HAU LETTER ZA + +11AC6 +PAU CIN HAU LETTER VA + +11AC7 +PAU CIN HAU LETTER NGA + +11AC8 +PAU CIN HAU LETTER HA + +11AC9 +PAU CIN HAU LETTER GA + +11ACA +PAU CIN HAU LETTER KHA + +11ACB +PAU CIN HAU LETTER SA + +11ACC +PAU CIN HAU LETTER BA + +11ACD +PAU CIN HAU LETTER CA + +11ACE +PAU CIN HAU LETTER TA + +11ACF +PAU CIN HAU LETTER THA + +11AD0 +PAU CIN HAU LETTER NA + +11AD1 +PAU CIN HAU LETTER PHA + +11AD2 +PAU CIN HAU LETTER RA + +11AD3 +PAU CIN HAU LETTER FA + +11AD4 +PAU CIN HAU LETTER CHA + +11AD5 +PAU CIN HAU LETTER A + +11AD6 +PAU CIN HAU LETTER E + +11AD7 +PAU CIN HAU LETTER I + +11AD8 +PAU CIN HAU LETTER O + +11AD9 +PAU CIN HAU LETTER U + +11ADA +PAU CIN HAU LETTER UA + +11ADB +PAU CIN HAU LETTER IA + +11ADC +PAU CIN HAU LETTER FINAL P + +11ADD +PAU CIN HAU LETTER FINAL K + +11ADE +PAU CIN HAU LETTER FINAL T + +11ADF +PAU CIN HAU LETTER FINAL M + +11AE0 +PAU CIN HAU LETTER FINAL N + +11AE1 +PAU CIN HAU LETTER FINAL L + +11AE2 +PAU CIN HAU LETTER FINAL W + +11AE3 +PAU CIN HAU LETTER FINAL NG + +11AE4 +PAU CIN HAU LETTER FINAL Y + +11AE5 +PAU CIN HAU RISING TONE LONG + +11AE6 +PAU CIN HAU RISING TONE + +11AE7 +PAU CIN HAU SANDHI GLOTTAL STOP + +11AE8 +PAU CIN HAU RISING TONE LONG FINAL + +11AE9 +PAU CIN HAU RISING TONE FINAL + +11AEA +PAU CIN HAU SANDHI GLOTTAL STOP FINAL + +11AEB +PAU CIN HAU SANDHI TONE LONG + +11AEC +PAU CIN HAU SANDHI TONE + +11AED +PAU CIN HAU SANDHI TONE LONG FINAL + +11AEE +PAU CIN HAU SANDHI TONE FINAL + +11AEF +PAU CIN HAU MID-LEVEL TONE + +11AF0 +PAU CIN HAU GLOTTAL STOP VARIANT + +11AF1 +PAU CIN HAU MID-LEVEL TONE LONG FINAL + +11AF2 +PAU CIN HAU MID-LEVEL TONE FINAL + +11AF3 +PAU CIN HAU LOW-FALLING TONE LONG + +11AF4 +PAU CIN HAU LOW-FALLING TONE + +11AF5 +PAU CIN HAU GLOTTAL STOP + +11AF6 +PAU CIN HAU LOW-FALLING TONE LONG FINAL + +11AF7 +PAU CIN HAU LOW-FALLING TONE FINAL + +11AF8 +PAU CIN HAU GLOTTAL STOP FINAL + +11B00 +DEVANAGARI HEAD MARK + +11B01 +DEVANAGARI HEAD MARK WITH HEADSTROKE + +11B02 +DEVANAGARI SIGN BHALE + +11B03 +DEVANAGARI SIGN BHALE WITH HOOK + +11B04 +DEVANAGARI SIGN EXTENDED BHALE + +11B05 +DEVANAGARI SIGN EXTENDED BHALE WITH HOOK + +11B06 +DEVANAGARI SIGN WESTERN FIVE-LIKE BHALE + +11B07 +DEVANAGARI SIGN WESTERN NINE-LIKE BHALE + +11B08 +DEVANAGARI SIGN REVERSED NINE-LIKE BHALE + +11B09 +DEVANAGARI SIGN MINDU + +11B60 +SHARADA VOWEL SIGN OE + +11B61 +SHARADA VOWEL SIGN OOE + +11B62 +SHARADA VOWEL SIGN UE + +11B63 +SHARADA VOWEL SIGN UUE + +11B64 +SHARADA VOWEL SIGN SHORT E + +11B65 +SHARADA VOWEL SIGN SHORT O + +11B66 +SHARADA VOWEL SIGN CANDRA E + +11B67 +SHARADA VOWEL SIGN CANDRA O + +11BC0 +SUNUWAR LETTER DEVI + +11BC1 +SUNUWAR LETTER TASLA + +11BC2 +SUNUWAR LETTER EKO + +11BC3 +SUNUWAR LETTER IMAR + +11BC4 +SUNUWAR LETTER REU + +11BC5 +SUNUWAR LETTER UTTHI + +11BC6 +SUNUWAR LETTER KIK + +11BC7 +SUNUWAR LETTER MA + +11BC8 +SUNUWAR LETTER APPHO + +11BC9 +SUNUWAR LETTER PIP + +11BCA +SUNUWAR LETTER GIL + +11BCB +SUNUWAR LETTER HAMSO + +11BCC +SUNUWAR LETTER CARMI + +11BCD +SUNUWAR LETTER NAH + +11BCE +SUNUWAR LETTER BUR + +11BCF +SUNUWAR LETTER JYAH + +11BD0 +SUNUWAR LETTER LOACHA + +11BD1 +SUNUWAR LETTER OTTHI + +11BD2 +SUNUWAR LETTER SHYELE + +11BD3 +SUNUWAR LETTER VARCA + +11BD4 +SUNUWAR LETTER YAT + +11BD5 +SUNUWAR LETTER AVA + +11BD6 +SUNUWAR LETTER AAL + +11BD7 +SUNUWAR LETTER DONGA + +11BD8 +SUNUWAR LETTER THARI + +11BD9 +SUNUWAR LETTER PHAR + +11BDA +SUNUWAR LETTER NGAR + +11BDB +SUNUWAR LETTER KHA + +11BDC +SUNUWAR LETTER SHYER + +11BDD +SUNUWAR LETTER CHELAP + +11BDE +SUNUWAR LETTER TENTU + +11BDF +SUNUWAR LETTER THELE + +11BE0 +SUNUWAR LETTER KLOKO + +11BE1 +SUNUWAR SIGN PVO + +11BF0 +SUNUWAR DIGIT ZERO + +11BF1 +SUNUWAR DIGIT ONE + +11BF2 +SUNUWAR DIGIT TWO + +11BF3 +SUNUWAR DIGIT THREE + +11BF4 +SUNUWAR DIGIT FOUR + +11BF5 +SUNUWAR DIGIT FIVE + +11BF6 +SUNUWAR DIGIT SIX + +11BF7 +SUNUWAR DIGIT SEVEN + +11BF8 +SUNUWAR DIGIT EIGHT + +11BF9 +SUNUWAR DIGIT NINE + +11C00 +BHAIKSUKI LETTER A + +11C01 +BHAIKSUKI LETTER AA + +11C02 +BHAIKSUKI LETTER I + +11C03 +BHAIKSUKI LETTER II + +11C04 +BHAIKSUKI LETTER U + +11C05 +BHAIKSUKI LETTER UU + +11C06 +BHAIKSUKI LETTER VOCALIC R + +11C07 +BHAIKSUKI LETTER VOCALIC RR + +11C08 +BHAIKSUKI LETTER VOCALIC L + +11C0A +BHAIKSUKI LETTER E + +11C0B +BHAIKSUKI LETTER AI + +11C0C +BHAIKSUKI LETTER O + +11C0D +BHAIKSUKI LETTER AU + +11C0E +BHAIKSUKI LETTER KA + +11C0F +BHAIKSUKI LETTER KHA + +11C10 +BHAIKSUKI LETTER GA + +11C11 +BHAIKSUKI LETTER GHA + +11C12 +BHAIKSUKI LETTER NGA + +11C13 +BHAIKSUKI LETTER CA + +11C14 +BHAIKSUKI LETTER CHA + +11C15 +BHAIKSUKI LETTER JA + +11C16 +BHAIKSUKI LETTER JHA + +11C17 +BHAIKSUKI LETTER NYA + +11C18 +BHAIKSUKI LETTER TTA + +11C19 +BHAIKSUKI LETTER TTHA + +11C1A +BHAIKSUKI LETTER DDA + +11C1B +BHAIKSUKI LETTER DDHA + +11C1C +BHAIKSUKI LETTER NNA + +11C1D +BHAIKSUKI LETTER TA + +11C1E +BHAIKSUKI LETTER THA + +11C1F +BHAIKSUKI LETTER DA + +11C20 +BHAIKSUKI LETTER DHA + +11C21 +BHAIKSUKI LETTER NA + +11C22 +BHAIKSUKI LETTER PA + +11C23 +BHAIKSUKI LETTER PHA + +11C24 +BHAIKSUKI LETTER BA + +11C25 +BHAIKSUKI LETTER BHA + +11C26 +BHAIKSUKI LETTER MA + +11C27 +BHAIKSUKI LETTER YA + +11C28 +BHAIKSUKI LETTER RA + +11C29 +BHAIKSUKI LETTER LA + +11C2A +BHAIKSUKI LETTER VA + +11C2B +BHAIKSUKI LETTER SHA + +11C2C +BHAIKSUKI LETTER SSA + +11C2D +BHAIKSUKI LETTER SA + +11C2E +BHAIKSUKI LETTER HA + +11C2F +BHAIKSUKI VOWEL SIGN AA + +11C30 +BHAIKSUKI VOWEL SIGN I + +11C31 +BHAIKSUKI VOWEL SIGN II + +11C32 +BHAIKSUKI VOWEL SIGN U + +11C33 +BHAIKSUKI VOWEL SIGN UU + +11C34 +BHAIKSUKI VOWEL SIGN VOCALIC R + +11C35 +BHAIKSUKI VOWEL SIGN VOCALIC RR + +11C36 +BHAIKSUKI VOWEL SIGN VOCALIC L + +11C38 +BHAIKSUKI VOWEL SIGN E + +11C39 +BHAIKSUKI VOWEL SIGN AI + +11C3A +BHAIKSUKI VOWEL SIGN O + +11C3B +BHAIKSUKI VOWEL SIGN AU + +11C3C +BHAIKSUKI SIGN CANDRABINDU + +11C3D +BHAIKSUKI SIGN ANUSVARA + +11C3E +BHAIKSUKI SIGN VISARGA + +11C3F +BHAIKSUKI SIGN VIRAMA + +11C40 +BHAIKSUKI SIGN AVAGRAHA + +11C41 +BHAIKSUKI DANDA + +11C42 +BHAIKSUKI DOUBLE DANDA + +11C43 +BHAIKSUKI WORD SEPARATOR + +11C44 +BHAIKSUKI GAP FILLER-1 + +11C45 +BHAIKSUKI GAP FILLER-2 + +11C50 +BHAIKSUKI DIGIT ZERO + +11C51 +BHAIKSUKI DIGIT ONE + +11C52 +BHAIKSUKI DIGIT TWO + +11C53 +BHAIKSUKI DIGIT THREE + +11C54 +BHAIKSUKI DIGIT FOUR + +11C55 +BHAIKSUKI DIGIT FIVE + +11C56 +BHAIKSUKI DIGIT SIX + +11C57 +BHAIKSUKI DIGIT SEVEN + +11C58 +BHAIKSUKI DIGIT EIGHT + +11C59 +BHAIKSUKI DIGIT NINE + +11C5A +BHAIKSUKI NUMBER ONE + +11C5B +BHAIKSUKI NUMBER TWO + +11C5C +BHAIKSUKI NUMBER THREE + +11C5D +BHAIKSUKI NUMBER FOUR + +11C5E +BHAIKSUKI NUMBER FIVE + +11C5F +BHAIKSUKI NUMBER SIX + +11C60 +BHAIKSUKI NUMBER SEVEN + +11C61 +BHAIKSUKI NUMBER EIGHT + +11C62 +BHAIKSUKI NUMBER NINE + +11C63 +BHAIKSUKI NUMBER TEN + +11C64 +BHAIKSUKI NUMBER TWENTY + +11C65 +BHAIKSUKI NUMBER THIRTY + +11C66 +BHAIKSUKI NUMBER FORTY + +11C67 +BHAIKSUKI NUMBER FIFTY + +11C68 +BHAIKSUKI NUMBER SIXTY + +11C69 +BHAIKSUKI NUMBER SEVENTY + +11C6A +BHAIKSUKI NUMBER EIGHTY + +11C6B +BHAIKSUKI NUMBER NINETY + +11C6C +BHAIKSUKI HUNDREDS UNIT MARK + +11C70 +MARCHEN HEAD MARK + +11C71 +MARCHEN MARK SHAD + +11C72 +MARCHEN LETTER KA + +11C73 +MARCHEN LETTER KHA + +11C74 +MARCHEN LETTER GA + +11C75 +MARCHEN LETTER NGA + +11C76 +MARCHEN LETTER CA + +11C77 +MARCHEN LETTER CHA + +11C78 +MARCHEN LETTER JA + +11C79 +MARCHEN LETTER NYA + +11C7A +MARCHEN LETTER TA + +11C7B +MARCHEN LETTER THA + +11C7C +MARCHEN LETTER DA + +11C7D +MARCHEN LETTER NA + +11C7E +MARCHEN LETTER PA + +11C7F +MARCHEN LETTER PHA + +11C80 +MARCHEN LETTER BA + +11C81 +MARCHEN LETTER MA + +11C82 +MARCHEN LETTER TSA + +11C83 +MARCHEN LETTER TSHA + +11C84 +MARCHEN LETTER DZA + +11C85 +MARCHEN LETTER WA + +11C86 +MARCHEN LETTER ZHA + +11C87 +MARCHEN LETTER ZA + +11C88 +MARCHEN LETTER -A + +11C89 +MARCHEN LETTER YA + +11C8A +MARCHEN LETTER RA + +11C8B +MARCHEN LETTER LA + +11C8C +MARCHEN LETTER SHA + +11C8D +MARCHEN LETTER SA + +11C8E +MARCHEN LETTER HA + +11C8F +MARCHEN LETTER A + +11C92 +MARCHEN SUBJOINED LETTER KA + +11C93 +MARCHEN SUBJOINED LETTER KHA + +11C94 +MARCHEN SUBJOINED LETTER GA + +11C95 +MARCHEN SUBJOINED LETTER NGA + +11C96 +MARCHEN SUBJOINED LETTER CA + +11C97 +MARCHEN SUBJOINED LETTER CHA + +11C98 +MARCHEN SUBJOINED LETTER JA + +11C99 +MARCHEN SUBJOINED LETTER NYA + +11C9A +MARCHEN SUBJOINED LETTER TA + +11C9B +MARCHEN SUBJOINED LETTER THA + +11C9C +MARCHEN SUBJOINED LETTER DA + +11C9D +MARCHEN SUBJOINED LETTER NA + +11C9E +MARCHEN SUBJOINED LETTER PA + +11C9F +MARCHEN SUBJOINED LETTER PHA + +11CA0 +MARCHEN SUBJOINED LETTER BA + +11CA1 +MARCHEN SUBJOINED LETTER MA + +11CA2 +MARCHEN SUBJOINED LETTER TSA + +11CA3 +MARCHEN SUBJOINED LETTER TSHA + +11CA4 +MARCHEN SUBJOINED LETTER DZA + +11CA5 +MARCHEN SUBJOINED LETTER WA + +11CA6 +MARCHEN SUBJOINED LETTER ZHA + +11CA7 +MARCHEN SUBJOINED LETTER ZA + +11CA9 +MARCHEN SUBJOINED LETTER YA + +11CAA +MARCHEN SUBJOINED LETTER RA + +11CAB +MARCHEN SUBJOINED LETTER LA + +11CAC +MARCHEN SUBJOINED LETTER SHA + +11CAD +MARCHEN SUBJOINED LETTER SA + +11CAE +MARCHEN SUBJOINED LETTER HA + +11CAF +MARCHEN SUBJOINED LETTER A + +11CB0 +MARCHEN VOWEL SIGN AA + +11CB1 +MARCHEN VOWEL SIGN I + +11CB2 +MARCHEN VOWEL SIGN U + +11CB3 +MARCHEN VOWEL SIGN E + +11CB4 +MARCHEN VOWEL SIGN O + +11CB5 +MARCHEN SIGN ANUSVARA + +11CB6 +MARCHEN SIGN CANDRABINDU + +11D00 +MASARAM GONDI LETTER A + +11D01 +MASARAM GONDI LETTER AA + +11D02 +MASARAM GONDI LETTER I + +11D03 +MASARAM GONDI LETTER II + +11D04 +MASARAM GONDI LETTER U + +11D05 +MASARAM GONDI LETTER UU + +11D06 +MASARAM GONDI LETTER E + +11D08 +MASARAM GONDI LETTER AI + +11D09 +MASARAM GONDI LETTER O + +11D0B +MASARAM GONDI LETTER AU + +11D0C +MASARAM GONDI LETTER KA + +11D0D +MASARAM GONDI LETTER KHA + +11D0E +MASARAM GONDI LETTER GA + +11D0F +MASARAM GONDI LETTER GHA + +11D10 +MASARAM GONDI LETTER NGA + +11D11 +MASARAM GONDI LETTER CA + +11D12 +MASARAM GONDI LETTER CHA + +11D13 +MASARAM GONDI LETTER JA + +11D14 +MASARAM GONDI LETTER JHA + +11D15 +MASARAM GONDI LETTER NYA + +11D16 +MASARAM GONDI LETTER TTA + +11D17 +MASARAM GONDI LETTER TTHA + +11D18 +MASARAM GONDI LETTER DDA + +11D19 +MASARAM GONDI LETTER DDHA + +11D1A +MASARAM GONDI LETTER NNA + +11D1B +MASARAM GONDI LETTER TA + +11D1C +MASARAM GONDI LETTER THA + +11D1D +MASARAM GONDI LETTER DA + +11D1E +MASARAM GONDI LETTER DHA + +11D1F +MASARAM GONDI LETTER NA + +11D20 +MASARAM GONDI LETTER PA + +11D21 +MASARAM GONDI LETTER PHA + +11D22 +MASARAM GONDI LETTER BA + +11D23 +MASARAM GONDI LETTER BHA + +11D24 +MASARAM GONDI LETTER MA + +11D25 +MASARAM GONDI LETTER YA + +11D26 +MASARAM GONDI LETTER RA + +11D27 +MASARAM GONDI LETTER LA + +11D28 +MASARAM GONDI LETTER VA + +11D29 +MASARAM GONDI LETTER SHA + +11D2A +MASARAM GONDI LETTER SSA + +11D2B +MASARAM GONDI LETTER SA + +11D2C +MASARAM GONDI LETTER HA + +11D2D +MASARAM GONDI LETTER LLA + +11D2E +MASARAM GONDI LETTER KSSA + +11D2F +MASARAM GONDI LETTER JNYA + +11D30 +MASARAM GONDI LETTER TRA + +11D31 +MASARAM GONDI VOWEL SIGN AA + +11D32 +MASARAM GONDI VOWEL SIGN I + +11D33 +MASARAM GONDI VOWEL SIGN II + +11D34 +MASARAM GONDI VOWEL SIGN U + +11D35 +MASARAM GONDI VOWEL SIGN UU + +11D36 +MASARAM GONDI VOWEL SIGN VOCALIC R + +11D3A +MASARAM GONDI VOWEL SIGN E + +11D3C +MASARAM GONDI VOWEL SIGN AI + +11D3D +MASARAM GONDI VOWEL SIGN O + +11D3F +MASARAM GONDI VOWEL SIGN AU + +11D40 +MASARAM GONDI SIGN ANUSVARA + +11D41 +MASARAM GONDI SIGN VISARGA + +11D42 +MASARAM GONDI SIGN NUKTA + +11D43 +MASARAM GONDI SIGN CANDRA + +11D44 +MASARAM GONDI SIGN HALANTA + +11D45 +MASARAM GONDI VIRAMA + +11D46 +MASARAM GONDI REPHA + +11D47 +MASARAM GONDI RA-KARA + +11D50 +MASARAM GONDI DIGIT ZERO + +11D51 +MASARAM GONDI DIGIT ONE + +11D52 +MASARAM GONDI DIGIT TWO + +11D53 +MASARAM GONDI DIGIT THREE + +11D54 +MASARAM GONDI DIGIT FOUR + +11D55 +MASARAM GONDI DIGIT FIVE + +11D56 +MASARAM GONDI DIGIT SIX + +11D57 +MASARAM GONDI DIGIT SEVEN + +11D58 +MASARAM GONDI DIGIT EIGHT + +11D59 +MASARAM GONDI DIGIT NINE + +11D60 +GUNJALA GONDI LETTER A + +11D61 +GUNJALA GONDI LETTER AA + +11D62 +GUNJALA GONDI LETTER I + +11D63 +GUNJALA GONDI LETTER II + +11D64 +GUNJALA GONDI LETTER U + +11D65 +GUNJALA GONDI LETTER UU + +11D67 +GUNJALA GONDI LETTER EE + +11D68 +GUNJALA GONDI LETTER AI + +11D6A +GUNJALA GONDI LETTER OO + +11D6B +GUNJALA GONDI LETTER AU + +11D6C +GUNJALA GONDI LETTER YA + +11D6D +GUNJALA GONDI LETTER VA + +11D6E +GUNJALA GONDI LETTER BA + +11D6F +GUNJALA GONDI LETTER BHA + +11D70 +GUNJALA GONDI LETTER MA + +11D71 +GUNJALA GONDI LETTER KA + +11D72 +GUNJALA GONDI LETTER KHA + +11D73 +GUNJALA GONDI LETTER TA + +11D74 +GUNJALA GONDI LETTER THA + +11D75 +GUNJALA GONDI LETTER LA + +11D76 +GUNJALA GONDI LETTER GA + +11D77 +GUNJALA GONDI LETTER GHA + +11D78 +GUNJALA GONDI LETTER DA + +11D79 +GUNJALA GONDI LETTER DHA + +11D7A +GUNJALA GONDI LETTER NA + +11D7B +GUNJALA GONDI LETTER CA + +11D7C +GUNJALA GONDI LETTER CHA + +11D7D +GUNJALA GONDI LETTER TTA + +11D7E +GUNJALA GONDI LETTER TTHA + +11D7F +GUNJALA GONDI LETTER LLA + +11D80 +GUNJALA GONDI LETTER JA + +11D81 +GUNJALA GONDI LETTER JHA + +11D82 +GUNJALA GONDI LETTER DDA + +11D83 +GUNJALA GONDI LETTER DDHA + +11D84 +GUNJALA GONDI LETTER NGA + +11D85 +GUNJALA GONDI LETTER PA + +11D86 +GUNJALA GONDI LETTER PHA + +11D87 +GUNJALA GONDI LETTER HA + +11D88 +GUNJALA GONDI LETTER RA + +11D89 +GUNJALA GONDI LETTER SA + +11D8A +GUNJALA GONDI VOWEL SIGN AA + +11D8B +GUNJALA GONDI VOWEL SIGN I + +11D8C +GUNJALA GONDI VOWEL SIGN II + +11D8D +GUNJALA GONDI VOWEL SIGN U + +11D8E +GUNJALA GONDI VOWEL SIGN UU + +11D90 +GUNJALA GONDI VOWEL SIGN EE + +11D91 +GUNJALA GONDI VOWEL SIGN AI + +11D93 +GUNJALA GONDI VOWEL SIGN OO + +11D94 +GUNJALA GONDI VOWEL SIGN AU + +11D95 +GUNJALA GONDI SIGN ANUSVARA + +11D96 +GUNJALA GONDI SIGN VISARGA + +11D97 +GUNJALA GONDI VIRAMA + +11D98 +GUNJALA GONDI OM + +11DA0 +GUNJALA GONDI DIGIT ZERO + +11DA1 +GUNJALA GONDI DIGIT ONE + +11DA2 +GUNJALA GONDI DIGIT TWO + +11DA3 +GUNJALA GONDI DIGIT THREE + +11DA4 +GUNJALA GONDI DIGIT FOUR + +11DA5 +GUNJALA GONDI DIGIT FIVE + +11DA6 +GUNJALA GONDI DIGIT SIX + +11DA7 +GUNJALA GONDI DIGIT SEVEN + +11DA8 +GUNJALA GONDI DIGIT EIGHT + +11DA9 +GUNJALA GONDI DIGIT NINE + +11DB0 +TOLONG SIKI LETTER I + +11DB1 +TOLONG SIKI LETTER E + +11DB2 +TOLONG SIKI LETTER U + +11DB3 +TOLONG SIKI LETTER O + +11DB4 +TOLONG SIKI LETTER A + +11DB5 +TOLONG SIKI LETTER AA + +11DB6 +TOLONG SIKI LETTER P + +11DB7 +TOLONG SIKI LETTER PH + +11DB8 +TOLONG SIKI LETTER B + +11DB9 +TOLONG SIKI LETTER BH + +11DBA +TOLONG SIKI LETTER M + +11DBB +TOLONG SIKI LETTER T + +11DBC +TOLONG SIKI LETTER TH + +11DBD +TOLONG SIKI LETTER D + +11DBE +TOLONG SIKI LETTER DH + +11DBF +TOLONG SIKI LETTER N + +11DC0 +TOLONG SIKI LETTER TT + +11DC1 +TOLONG SIKI LETTER TTH + +11DC2 +TOLONG SIKI LETTER DD + +11DC3 +TOLONG SIKI LETTER DDH + +11DC4 +TOLONG SIKI LETTER NN + +11DC5 +TOLONG SIKI LETTER C + +11DC6 +TOLONG SIKI LETTER CH + +11DC7 +TOLONG SIKI LETTER J + +11DC8 +TOLONG SIKI LETTER JH + +11DC9 +TOLONG SIKI LETTER NY + +11DCA +TOLONG SIKI LETTER K + +11DCB +TOLONG SIKI LETTER KH + +11DCC +TOLONG SIKI LETTER G + +11DCD +TOLONG SIKI LETTER GH + +11DCE +TOLONG SIKI LETTER NG + +11DCF +TOLONG SIKI LETTER Y + +11DD0 +TOLONG SIKI LETTER R + +11DD1 +TOLONG SIKI LETTER L + +11DD2 +TOLONG SIKI LETTER V + +11DD3 +TOLONG SIKI LETTER NNY + +11DD4 +TOLONG SIKI LETTER S + +11DD5 +TOLONG SIKI LETTER H + +11DD6 +TOLONG SIKI LETTER X + +11DD7 +TOLONG SIKI LETTER RR + +11DD8 +TOLONG SIKI LETTER RRH + +11DD9 +TOLONG SIKI SIGN SELA + +11DDA +TOLONG SIKI SIGN HECAKA + +11DDB +TOLONG SIKI UNGGA + +11DE0 +TOLONG SIKI DIGIT ZERO + +11DE1 +TOLONG SIKI DIGIT ONE + +11DE2 +TOLONG SIKI DIGIT TWO + +11DE3 +TOLONG SIKI DIGIT THREE + +11DE4 +TOLONG SIKI DIGIT FOUR + +11DE5 +TOLONG SIKI DIGIT FIVE + +11DE6 +TOLONG SIKI DIGIT SIX + +11DE7 +TOLONG SIKI DIGIT SEVEN + +11DE8 +TOLONG SIKI DIGIT EIGHT + +11DE9 +TOLONG SIKI DIGIT NINE + +11EE0 +MAKASAR LETTER KA + +11EE1 +MAKASAR LETTER GA + +11EE2 +MAKASAR LETTER NGA + +11EE3 +MAKASAR LETTER PA + +11EE4 +MAKASAR LETTER BA + +11EE5 +MAKASAR LETTER MA + +11EE6 +MAKASAR LETTER TA + +11EE7 +MAKASAR LETTER DA + +11EE8 +MAKASAR LETTER NA + +11EE9 +MAKASAR LETTER CA + +11EEA +MAKASAR LETTER JA + +11EEB +MAKASAR LETTER NYA + +11EEC +MAKASAR LETTER YA + +11EED +MAKASAR LETTER RA + +11EEE +MAKASAR LETTER LA + +11EEF +MAKASAR LETTER VA + +11EF0 +MAKASAR LETTER SA + +11EF1 +MAKASAR LETTER A + +11EF2 +MAKASAR ANGKA + +11EF3 +MAKASAR VOWEL SIGN I + +11EF4 +MAKASAR VOWEL SIGN U + +11EF5 +MAKASAR VOWEL SIGN E + +11EF6 +MAKASAR VOWEL SIGN O + +11EF7 +MAKASAR PASSIMBANG + +11EF8 +MAKASAR END OF SECTION + +11F00 +KAWI SIGN CANDRABINDU + +11F01 +KAWI SIGN ANUSVARA + +11F02 +KAWI SIGN REPHA + +11F03 +KAWI SIGN VISARGA + +11F04 +KAWI LETTER A + +11F05 +KAWI LETTER AA + +11F06 +KAWI LETTER I + +11F07 +KAWI LETTER II + +11F08 +KAWI LETTER U + +11F09 +KAWI LETTER UU + +11F0A +KAWI LETTER VOCALIC R + +11F0B +KAWI LETTER VOCALIC RR + +11F0C +KAWI LETTER VOCALIC L + +11F0D +KAWI LETTER VOCALIC LL + +11F0E +KAWI LETTER E + +11F0F +KAWI LETTER AI + +11F10 +KAWI LETTER O + +11F12 +KAWI LETTER KA + +11F13 +KAWI LETTER KHA + +11F14 +KAWI LETTER GA + +11F15 +KAWI LETTER GHA + +11F16 +KAWI LETTER NGA + +11F17 +KAWI LETTER CA + +11F18 +KAWI LETTER CHA + +11F19 +KAWI LETTER JA + +11F1A +KAWI LETTER JHA + +11F1B +KAWI LETTER NYA + +11F1C +KAWI LETTER TTA + +11F1D +KAWI LETTER TTHA + +11F1E +KAWI LETTER DDA + +11F1F +KAWI LETTER DDHA + +11F20 +KAWI LETTER NNA + +11F21 +KAWI LETTER TA + +11F22 +KAWI LETTER THA + +11F23 +KAWI LETTER DA + +11F24 +KAWI LETTER DHA + +11F25 +KAWI LETTER NA + +11F26 +KAWI LETTER PA + +11F27 +KAWI LETTER PHA + +11F28 +KAWI LETTER BA + +11F29 +KAWI LETTER BHA + +11F2A +KAWI LETTER MA + +11F2B +KAWI LETTER YA + +11F2C +KAWI LETTER RA + +11F2D +KAWI LETTER LA + +11F2E +KAWI LETTER WA + +11F2F +KAWI LETTER SHA + +11F30 +KAWI LETTER SSA + +11F31 +KAWI LETTER SA + +11F32 +KAWI LETTER HA + +11F33 +KAWI LETTER JNYA + +11F34 +KAWI VOWEL SIGN AA + +11F35 +KAWI VOWEL SIGN ALTERNATE AA + +11F36 +KAWI VOWEL SIGN I + +11F37 +KAWI VOWEL SIGN II + +11F38 +KAWI VOWEL SIGN U + +11F39 +KAWI VOWEL SIGN UU + +11F3A +KAWI VOWEL SIGN VOCALIC R + +11F3E +KAWI VOWEL SIGN E + +11F3F +KAWI VOWEL SIGN AI + +11F40 +KAWI VOWEL SIGN EU + +11F41 +KAWI SIGN KILLER + +11F42 +KAWI CONJOINER + +11F43 +KAWI DANDA + +11F44 +KAWI DOUBLE DANDA + +11F45 +KAWI PUNCTUATION SECTION MARKER + +11F46 +KAWI PUNCTUATION ALTERNATE SECTION MARKER + +11F47 +KAWI PUNCTUATION FLOWER + +11F48 +KAWI PUNCTUATION SPACE FILLER + +11F49 +KAWI PUNCTUATION DOT + +11F4A +KAWI PUNCTUATION DOUBLE DOT + +11F4B +KAWI PUNCTUATION TRIPLE DOT + +11F4C +KAWI PUNCTUATION CIRCLE + +11F4D +KAWI PUNCTUATION FILLED CIRCLE + +11F4E +KAWI PUNCTUATION SPIRAL + +11F4F +KAWI PUNCTUATION CLOSING SPIRAL + +11F50 +KAWI DIGIT ZERO + +11F51 +KAWI DIGIT ONE + +11F52 +KAWI DIGIT TWO + +11F53 +KAWI DIGIT THREE + +11F54 +KAWI DIGIT FOUR + +11F55 +KAWI DIGIT FIVE + +11F56 +KAWI DIGIT SIX + +11F57 +KAWI DIGIT SEVEN + +11F58 +KAWI DIGIT EIGHT + +11F59 +KAWI DIGIT NINE + +11F5A +KAWI SIGN NUKTA + +11FB0 +LISU LETTER YHA + +11FC0 +TAMIL FRACTION ONE THREE-HUNDRED-AND-TWENTIETH + +11FC1 +TAMIL FRACTION ONE ONE-HUNDRED-AND-SIXTIETH + +11FC2 +TAMIL FRACTION ONE EIGHTIETH + +11FC3 +TAMIL FRACTION ONE SIXTY-FOURTH + +11FC4 +TAMIL FRACTION ONE FORTIETH + +11FC5 +TAMIL FRACTION ONE THIRTY-SECOND + +11FC6 +TAMIL FRACTION THREE EIGHTIETHS + +11FC7 +TAMIL FRACTION THREE SIXTY-FOURTHS + +11FC8 +TAMIL FRACTION ONE TWENTIETH + +11FC9 +TAMIL FRACTION ONE SIXTEENTH-1 + +11FCA +TAMIL FRACTION ONE SIXTEENTH-2 + +11FCB +TAMIL FRACTION ONE TENTH + +11FCC +TAMIL FRACTION ONE EIGHTH + +11FCD +TAMIL FRACTION THREE TWENTIETHS + +11FCE +TAMIL FRACTION THREE SIXTEENTHS + +11FCF +TAMIL FRACTION ONE FIFTH + +11FD0 +TAMIL FRACTION ONE QUARTER + +11FD1 +TAMIL FRACTION ONE HALF-1 + +11FD2 +TAMIL FRACTION ONE HALF-2 + +11FD3 +TAMIL FRACTION THREE QUARTERS + +11FD4 +TAMIL FRACTION DOWNSCALING FACTOR KIIZH + +11FD5 +TAMIL SIGN NEL + +11FD6 +TAMIL SIGN CEVITU + +11FD7 +TAMIL SIGN AAZHAAKKU + +11FD8 +TAMIL SIGN UZHAKKU + +11FD9 +TAMIL SIGN MUUVUZHAKKU + +11FDA +TAMIL SIGN KURUNI + +11FDB +TAMIL SIGN PATHAKKU + +11FDC +TAMIL SIGN MUKKURUNI + +11FDD +TAMIL SIGN KAACU + +11FDE +TAMIL SIGN PANAM + +11FDF +TAMIL SIGN PON + +11FE0 +TAMIL SIGN VARAAKAN + +11FE1 +TAMIL SIGN PAARAM + +11FE2 +TAMIL SIGN KUZHI + +11FE3 +TAMIL SIGN VELI + +11FE4 +TAMIL WET CULTIVATION SIGN + +11FE5 +TAMIL DRY CULTIVATION SIGN + +11FE6 +TAMIL LAND SIGN + +11FE7 +TAMIL SALT PAN SIGN + +11FE8 +TAMIL TRADITIONAL CREDIT SIGN + +11FE9 +TAMIL TRADITIONAL NUMBER SIGN + +11FEA +TAMIL CURRENT SIGN + +11FEB +TAMIL AND ODD SIGN + +11FEC +TAMIL SPENT SIGN + +11FED +TAMIL TOTAL SIGN + +11FEE +TAMIL IN POSSESSION SIGN + +11FEF +TAMIL STARTING FROM SIGN + +11FF0 +TAMIL SIGN MUTHALIYA + +11FF1 +TAMIL SIGN VAKAIYARAA + +11FFF +TAMIL PUNCTUATION END OF TEXT + +12000 +CUNEIFORM SIGN A + +12001 +CUNEIFORM SIGN A TIMES A + +12002 +CUNEIFORM SIGN A TIMES BAD + +12003 +CUNEIFORM SIGN A TIMES GAN2 TENU + +12004 +CUNEIFORM SIGN A TIMES HA + +12005 +CUNEIFORM SIGN A TIMES IGI + +12006 +CUNEIFORM SIGN A TIMES LAGAR GUNU + +12007 +CUNEIFORM SIGN A TIMES MUSH + +12008 +CUNEIFORM SIGN A TIMES SAG + +12009 +CUNEIFORM SIGN A2 + +1200A +CUNEIFORM SIGN AB + +1200B +CUNEIFORM SIGN AB TIMES ASH2 + +1200C +CUNEIFORM SIGN AB TIMES DUN3 GUNU + +1200D +CUNEIFORM SIGN AB TIMES GAL + +1200E +CUNEIFORM SIGN AB TIMES GAN2 TENU + +1200F +CUNEIFORM SIGN AB TIMES HA + +12010 +CUNEIFORM SIGN AB TIMES IGI GUNU + +12011 +CUNEIFORM SIGN AB TIMES IMIN + +12012 +CUNEIFORM SIGN AB TIMES LAGAB + +12013 +CUNEIFORM SIGN AB TIMES SHESH + +12014 +CUNEIFORM SIGN AB TIMES U PLUS U PLUS U + +12015 +CUNEIFORM SIGN AB GUNU + +12016 +CUNEIFORM SIGN AB2 + +12017 +CUNEIFORM SIGN AB2 TIMES BALAG + +12018 +CUNEIFORM SIGN AB2 TIMES GAN2 TENU + +12019 +CUNEIFORM SIGN AB2 TIMES ME PLUS EN + +1201A +CUNEIFORM SIGN AB2 TIMES SHA3 + +1201B +CUNEIFORM SIGN AB2 TIMES TAK4 + +1201C +CUNEIFORM SIGN AD + +1201D +CUNEIFORM SIGN AK + +1201E +CUNEIFORM SIGN AK TIMES ERIN2 + +1201F +CUNEIFORM SIGN AK TIMES SHITA PLUS GISH + +12020 +CUNEIFORM SIGN AL + +12021 +CUNEIFORM SIGN AL TIMES AL + +12022 +CUNEIFORM SIGN AL TIMES DIM2 + +12023 +CUNEIFORM SIGN AL TIMES GISH + +12024 +CUNEIFORM SIGN AL TIMES HA + +12025 +CUNEIFORM SIGN AL TIMES KAD3 + +12026 +CUNEIFORM SIGN AL TIMES KI + +12027 +CUNEIFORM SIGN AL TIMES SHE + +12028 +CUNEIFORM SIGN AL TIMES USH + +12029 +CUNEIFORM SIGN ALAN + +1202A +CUNEIFORM SIGN ALEPH + +1202B +CUNEIFORM SIGN AMAR + +1202C +CUNEIFORM SIGN AMAR TIMES SHE + +1202D +CUNEIFORM SIGN AN + +1202E +CUNEIFORM SIGN AN OVER AN + +1202F +CUNEIFORM SIGN AN THREE TIMES + +12030 +CUNEIFORM SIGN AN PLUS NAGA OPPOSING AN PLUS NAGA + +12031 +CUNEIFORM SIGN AN PLUS NAGA SQUARED + +12032 +CUNEIFORM SIGN ANSHE + +12033 +CUNEIFORM SIGN APIN + +12034 +CUNEIFORM SIGN ARAD + +12035 +CUNEIFORM SIGN ARAD TIMES KUR + +12036 +CUNEIFORM SIGN ARKAB + +12037 +CUNEIFORM SIGN ASAL2 + +12038 +CUNEIFORM SIGN ASH + +12039 +CUNEIFORM SIGN ASH ZIDA TENU + +1203A +CUNEIFORM SIGN ASH KABA TENU + +1203B +CUNEIFORM SIGN ASH OVER ASH TUG2 OVER TUG2 TUG2 OVER TUG2 PAP + +1203C +CUNEIFORM SIGN ASH OVER ASH OVER ASH + +1203D +CUNEIFORM SIGN ASH OVER ASH OVER ASH CROSSING ASH OVER ASH OVER ASH + +1203E +CUNEIFORM SIGN ASH2 + +1203F +CUNEIFORM SIGN ASHGAB + +12040 +CUNEIFORM SIGN BA + +12041 +CUNEIFORM SIGN BAD + +12042 +CUNEIFORM SIGN BAG3 + +12043 +CUNEIFORM SIGN BAHAR2 + +12044 +CUNEIFORM SIGN BAL + +12045 +CUNEIFORM SIGN BAL OVER BAL + +12046 +CUNEIFORM SIGN BALAG + +12047 +CUNEIFORM SIGN BAR + +12048 +CUNEIFORM SIGN BARA2 + +12049 +CUNEIFORM SIGN BI + +1204A +CUNEIFORM SIGN BI TIMES A + +1204B +CUNEIFORM SIGN BI TIMES GAR + +1204C +CUNEIFORM SIGN BI TIMES IGI GUNU + +1204D +CUNEIFORM SIGN BU + +1204E +CUNEIFORM SIGN BU OVER BU AB + +1204F +CUNEIFORM SIGN BU OVER BU UN + +12050 +CUNEIFORM SIGN BU CROSSING BU + +12051 +CUNEIFORM SIGN BULUG + +12052 +CUNEIFORM SIGN BULUG OVER BULUG + +12053 +CUNEIFORM SIGN BUR + +12054 +CUNEIFORM SIGN BUR2 + +12055 +CUNEIFORM SIGN DA + +12056 +CUNEIFORM SIGN DAG + +12057 +CUNEIFORM SIGN DAG KISIM5 TIMES A PLUS MASH + +12058 +CUNEIFORM SIGN DAG KISIM5 TIMES AMAR + +12059 +CUNEIFORM SIGN DAG KISIM5 TIMES BALAG + +1205A +CUNEIFORM SIGN DAG KISIM5 TIMES BI + +1205B +CUNEIFORM SIGN DAG KISIM5 TIMES GA + +1205C +CUNEIFORM SIGN DAG KISIM5 TIMES GA PLUS MASH + +1205D +CUNEIFORM SIGN DAG KISIM5 TIMES GI + +1205E +CUNEIFORM SIGN DAG KISIM5 TIMES GIR2 + +1205F +CUNEIFORM SIGN DAG KISIM5 TIMES GUD + +12060 +CUNEIFORM SIGN DAG KISIM5 TIMES HA + +12061 +CUNEIFORM SIGN DAG KISIM5 TIMES IR + +12062 +CUNEIFORM SIGN DAG KISIM5 TIMES IR PLUS LU + +12063 +CUNEIFORM SIGN DAG KISIM5 TIMES KAK + +12064 +CUNEIFORM SIGN DAG KISIM5 TIMES LA + +12065 +CUNEIFORM SIGN DAG KISIM5 TIMES LU + +12066 +CUNEIFORM SIGN DAG KISIM5 TIMES LU PLUS MASH2 + +12067 +CUNEIFORM SIGN DAG KISIM5 TIMES LUM + +12068 +CUNEIFORM SIGN DAG KISIM5 TIMES NE + +12069 +CUNEIFORM SIGN DAG KISIM5 TIMES PAP PLUS PAP + +1206A +CUNEIFORM SIGN DAG KISIM5 TIMES SI + +1206B +CUNEIFORM SIGN DAG KISIM5 TIMES TAK4 + +1206C +CUNEIFORM SIGN DAG KISIM5 TIMES U2 PLUS GIR2 + +1206D +CUNEIFORM SIGN DAG KISIM5 TIMES USH + +1206E +CUNEIFORM SIGN DAM + +1206F +CUNEIFORM SIGN DAR + +12070 +CUNEIFORM SIGN DARA3 + +12071 +CUNEIFORM SIGN DARA4 + +12072 +CUNEIFORM SIGN DI + +12073 +CUNEIFORM SIGN DIB + +12074 +CUNEIFORM SIGN DIM + +12075 +CUNEIFORM SIGN DIM TIMES SHE + +12076 +CUNEIFORM SIGN DIM2 + +12077 +CUNEIFORM SIGN DIN + +12078 +CUNEIFORM SIGN DIN KASKAL U GUNU DISH + +12079 +CUNEIFORM SIGN DISH + +1207A +CUNEIFORM SIGN DU + +1207B +CUNEIFORM SIGN DU OVER DU + +1207C +CUNEIFORM SIGN DU GUNU + +1207D +CUNEIFORM SIGN DU SHESHIG + +1207E +CUNEIFORM SIGN DUB + +1207F +CUNEIFORM SIGN DUB TIMES ESH2 + +12080 +CUNEIFORM SIGN DUB2 + +12081 +CUNEIFORM SIGN DUG + +12082 +CUNEIFORM SIGN DUGUD + +12083 +CUNEIFORM SIGN DUH + +12084 +CUNEIFORM SIGN DUN + +12085 +CUNEIFORM SIGN DUN3 + +12086 +CUNEIFORM SIGN DUN3 GUNU + +12087 +CUNEIFORM SIGN DUN3 GUNU GUNU + +12088 +CUNEIFORM SIGN DUN4 + +12089 +CUNEIFORM SIGN DUR2 + +1208A +CUNEIFORM SIGN E + +1208B +CUNEIFORM SIGN E TIMES PAP + +1208C +CUNEIFORM SIGN E OVER E NUN OVER NUN + +1208D +CUNEIFORM SIGN E2 + +1208E +CUNEIFORM SIGN E2 TIMES A PLUS HA PLUS DA + +1208F +CUNEIFORM SIGN E2 TIMES GAR + +12090 +CUNEIFORM SIGN E2 TIMES MI + +12091 +CUNEIFORM SIGN E2 TIMES SAL + +12092 +CUNEIFORM SIGN E2 TIMES SHE + +12093 +CUNEIFORM SIGN E2 TIMES U + +12094 +CUNEIFORM SIGN EDIN + +12095 +CUNEIFORM SIGN EGIR + +12096 +CUNEIFORM SIGN EL + +12097 +CUNEIFORM SIGN EN + +12098 +CUNEIFORM SIGN EN TIMES GAN2 + +12099 +CUNEIFORM SIGN EN TIMES GAN2 TENU + +1209A +CUNEIFORM SIGN EN TIMES ME + +1209B +CUNEIFORM SIGN EN CROSSING EN + +1209C +CUNEIFORM SIGN EN OPPOSING EN + +1209D +CUNEIFORM SIGN EN SQUARED + +1209E +CUNEIFORM SIGN EREN + +1209F +CUNEIFORM SIGN ERIN2 + +120A0 +CUNEIFORM SIGN ESH2 + +120A1 +CUNEIFORM SIGN EZEN + +120A2 +CUNEIFORM SIGN EZEN TIMES A + +120A3 +CUNEIFORM SIGN EZEN TIMES A PLUS LAL + +120A4 +CUNEIFORM SIGN EZEN TIMES A PLUS LAL TIMES LAL + +120A5 +CUNEIFORM SIGN EZEN TIMES AN + +120A6 +CUNEIFORM SIGN EZEN TIMES BAD + +120A7 +CUNEIFORM SIGN EZEN TIMES DUN3 GUNU + +120A8 +CUNEIFORM SIGN EZEN TIMES DUN3 GUNU GUNU + +120A9 +CUNEIFORM SIGN EZEN TIMES HA + +120AA +CUNEIFORM SIGN EZEN TIMES HA GUNU + +120AB +CUNEIFORM SIGN EZEN TIMES IGI GUNU + +120AC +CUNEIFORM SIGN EZEN TIMES KASKAL + +120AD +CUNEIFORM SIGN EZEN TIMES KASKAL SQUARED + +120AE +CUNEIFORM SIGN EZEN TIMES KU3 + +120AF +CUNEIFORM SIGN EZEN TIMES LA + +120B0 +CUNEIFORM SIGN EZEN TIMES LAL TIMES LAL + +120B1 +CUNEIFORM SIGN EZEN TIMES LI + +120B2 +CUNEIFORM SIGN EZEN TIMES LU + +120B3 +CUNEIFORM SIGN EZEN TIMES U2 + +120B4 +CUNEIFORM SIGN EZEN TIMES UD + +120B5 +CUNEIFORM SIGN GA + +120B6 +CUNEIFORM SIGN GA GUNU + +120B7 +CUNEIFORM SIGN GA2 + +120B8 +CUNEIFORM SIGN GA2 TIMES A PLUS DA PLUS HA + +120B9 +CUNEIFORM SIGN GA2 TIMES A PLUS HA + +120BA +CUNEIFORM SIGN GA2 TIMES A PLUS IGI + +120BB +CUNEIFORM SIGN GA2 TIMES AB2 TENU PLUS TAB + +120BC +CUNEIFORM SIGN GA2 TIMES AN + +120BD +CUNEIFORM SIGN GA2 TIMES ASH + +120BE +CUNEIFORM SIGN GA2 TIMES ASH2 PLUS GAL + +120BF +CUNEIFORM SIGN GA2 TIMES BAD + +120C0 +CUNEIFORM SIGN GA2 TIMES BAR PLUS RA + +120C1 +CUNEIFORM SIGN GA2 TIMES BUR + +120C2 +CUNEIFORM SIGN GA2 TIMES BUR PLUS RA + +120C3 +CUNEIFORM SIGN GA2 TIMES DA + +120C4 +CUNEIFORM SIGN GA2 TIMES DI + +120C5 +CUNEIFORM SIGN GA2 TIMES DIM TIMES SHE + +120C6 +CUNEIFORM SIGN GA2 TIMES DUB + +120C7 +CUNEIFORM SIGN GA2 TIMES EL + +120C8 +CUNEIFORM SIGN GA2 TIMES EL PLUS LA + +120C9 +CUNEIFORM SIGN GA2 TIMES EN + +120CA +CUNEIFORM SIGN GA2 TIMES EN TIMES GAN2 TENU + +120CB +CUNEIFORM SIGN GA2 TIMES GAN2 TENU + +120CC +CUNEIFORM SIGN GA2 TIMES GAR + +120CD +CUNEIFORM SIGN GA2 TIMES GI + +120CE +CUNEIFORM SIGN GA2 TIMES GI4 + +120CF +CUNEIFORM SIGN GA2 TIMES GI4 PLUS A + +120D0 +CUNEIFORM SIGN GA2 TIMES GIR2 PLUS SU + +120D1 +CUNEIFORM SIGN GA2 TIMES HA PLUS LU PLUS ESH2 + +120D2 +CUNEIFORM SIGN GA2 TIMES HAL + +120D3 +CUNEIFORM SIGN GA2 TIMES HAL PLUS LA + +120D4 +CUNEIFORM SIGN GA2 TIMES HI PLUS LI + +120D5 +CUNEIFORM SIGN GA2 TIMES HUB2 + +120D6 +CUNEIFORM SIGN GA2 TIMES IGI GUNU + +120D7 +CUNEIFORM SIGN GA2 TIMES ISH PLUS HU PLUS ASH + +120D8 +CUNEIFORM SIGN GA2 TIMES KAK + +120D9 +CUNEIFORM SIGN GA2 TIMES KASKAL + +120DA +CUNEIFORM SIGN GA2 TIMES KID + +120DB +CUNEIFORM SIGN GA2 TIMES KID PLUS LAL + +120DC +CUNEIFORM SIGN GA2 TIMES KU3 PLUS AN + +120DD +CUNEIFORM SIGN GA2 TIMES LA + +120DE +CUNEIFORM SIGN GA2 TIMES ME PLUS EN + +120DF +CUNEIFORM SIGN GA2 TIMES MI + +120E0 +CUNEIFORM SIGN GA2 TIMES NUN + +120E1 +CUNEIFORM SIGN GA2 TIMES NUN OVER NUN + +120E2 +CUNEIFORM SIGN GA2 TIMES PA + +120E3 +CUNEIFORM SIGN GA2 TIMES SAL + +120E4 +CUNEIFORM SIGN GA2 TIMES SAR + +120E5 +CUNEIFORM SIGN GA2 TIMES SHE + +120E6 +CUNEIFORM SIGN GA2 TIMES SHE PLUS TUR + +120E7 +CUNEIFORM SIGN GA2 TIMES SHID + +120E8 +CUNEIFORM SIGN GA2 TIMES SUM + +120E9 +CUNEIFORM SIGN GA2 TIMES TAK4 + +120EA +CUNEIFORM SIGN GA2 TIMES U + +120EB +CUNEIFORM SIGN GA2 TIMES UD + +120EC +CUNEIFORM SIGN GA2 TIMES UD PLUS DU + +120ED +CUNEIFORM SIGN GA2 OVER GA2 + +120EE +CUNEIFORM SIGN GABA + +120EF +CUNEIFORM SIGN GABA CROSSING GABA + +120F0 +CUNEIFORM SIGN GAD + +120F1 +CUNEIFORM SIGN GAD OVER GAD GAR OVER GAR + +120F2 +CUNEIFORM SIGN GAL + +120F3 +CUNEIFORM SIGN GAL GAD OVER GAD GAR OVER GAR + +120F4 +CUNEIFORM SIGN GALAM + +120F5 +CUNEIFORM SIGN GAM + +120F6 +CUNEIFORM SIGN GAN + +120F7 +CUNEIFORM SIGN GAN2 + +120F8 +CUNEIFORM SIGN GAN2 TENU + +120F9 +CUNEIFORM SIGN GAN2 OVER GAN2 + +120FA +CUNEIFORM SIGN GAN2 CROSSING GAN2 + +120FB +CUNEIFORM SIGN GAR + +120FC +CUNEIFORM SIGN GAR3 + +120FD +CUNEIFORM SIGN GASHAN + +120FE +CUNEIFORM SIGN GESHTIN + +120FF +CUNEIFORM SIGN GESHTIN TIMES KUR + +12100 +CUNEIFORM SIGN GI + +12101 +CUNEIFORM SIGN GI TIMES E + +12102 +CUNEIFORM SIGN GI TIMES U + +12103 +CUNEIFORM SIGN GI CROSSING GI + +12104 +CUNEIFORM SIGN GI4 + +12105 +CUNEIFORM SIGN GI4 OVER GI4 + +12106 +CUNEIFORM SIGN GI4 CROSSING GI4 + +12107 +CUNEIFORM SIGN GIDIM + +12108 +CUNEIFORM SIGN GIR2 + +12109 +CUNEIFORM SIGN GIR2 GUNU + +1210A +CUNEIFORM SIGN GIR3 + +1210B +CUNEIFORM SIGN GIR3 TIMES A PLUS IGI + +1210C +CUNEIFORM SIGN GIR3 TIMES GAN2 TENU + +1210D +CUNEIFORM SIGN GIR3 TIMES IGI + +1210E +CUNEIFORM SIGN GIR3 TIMES LU PLUS IGI + +1210F +CUNEIFORM SIGN GIR3 TIMES PA + +12110 +CUNEIFORM SIGN GISAL + +12111 +CUNEIFORM SIGN GISH + +12112 +CUNEIFORM SIGN GISH CROSSING GISH + +12113 +CUNEIFORM SIGN GISH TIMES BAD + +12114 +CUNEIFORM SIGN GISH TIMES TAK4 + +12115 +CUNEIFORM SIGN GISH TENU + +12116 +CUNEIFORM SIGN GU + +12117 +CUNEIFORM SIGN GU CROSSING GU + +12118 +CUNEIFORM SIGN GU2 + +12119 +CUNEIFORM SIGN GU2 TIMES KAK + +1211A +CUNEIFORM SIGN GU2 TIMES KAK TIMES IGI GUNU + +1211B +CUNEIFORM SIGN GU2 TIMES NUN + +1211C +CUNEIFORM SIGN GU2 TIMES SAL PLUS TUG2 + +1211D +CUNEIFORM SIGN GU2 GUNU + +1211E +CUNEIFORM SIGN GUD + +1211F +CUNEIFORM SIGN GUD TIMES A PLUS KUR + +12120 +CUNEIFORM SIGN GUD TIMES KUR + +12121 +CUNEIFORM SIGN GUD OVER GUD LUGAL + +12122 +CUNEIFORM SIGN GUL + +12123 +CUNEIFORM SIGN GUM + +12124 +CUNEIFORM SIGN GUM TIMES SHE + +12125 +CUNEIFORM SIGN GUR + +12126 +CUNEIFORM SIGN GUR7 + +12127 +CUNEIFORM SIGN GURUN + +12128 +CUNEIFORM SIGN GURUSH + +12129 +CUNEIFORM SIGN HA + +1212A +CUNEIFORM SIGN HA TENU + +1212B +CUNEIFORM SIGN HA GUNU + +1212C +CUNEIFORM SIGN HAL + +1212D +CUNEIFORM SIGN HI + +1212E +CUNEIFORM SIGN HI TIMES ASH + +1212F +CUNEIFORM SIGN HI TIMES ASH2 + +12130 +CUNEIFORM SIGN HI TIMES BAD + +12131 +CUNEIFORM SIGN HI TIMES DISH + +12132 +CUNEIFORM SIGN HI TIMES GAD + +12133 +CUNEIFORM SIGN HI TIMES KIN + +12134 +CUNEIFORM SIGN HI TIMES NUN + +12135 +CUNEIFORM SIGN HI TIMES SHE + +12136 +CUNEIFORM SIGN HI TIMES U + +12137 +CUNEIFORM SIGN HU + +12138 +CUNEIFORM SIGN HUB2 + +12139 +CUNEIFORM SIGN HUB2 TIMES AN + +1213A +CUNEIFORM SIGN HUB2 TIMES HAL + +1213B +CUNEIFORM SIGN HUB2 TIMES KASKAL + +1213C +CUNEIFORM SIGN HUB2 TIMES LISH + +1213D +CUNEIFORM SIGN HUB2 TIMES UD + +1213E +CUNEIFORM SIGN HUL2 + +1213F +CUNEIFORM SIGN I + +12140 +CUNEIFORM SIGN I A + +12141 +CUNEIFORM SIGN IB + +12142 +CUNEIFORM SIGN IDIM + +12143 +CUNEIFORM SIGN IDIM OVER IDIM BUR + +12144 +CUNEIFORM SIGN IDIM OVER IDIM SQUARED + +12145 +CUNEIFORM SIGN IG + +12146 +CUNEIFORM SIGN IGI + +12147 +CUNEIFORM SIGN IGI DIB + +12148 +CUNEIFORM SIGN IGI RI + +12149 +CUNEIFORM SIGN IGI OVER IGI SHIR OVER SHIR UD OVER UD + +1214A +CUNEIFORM SIGN IGI GUNU + +1214B +CUNEIFORM SIGN IL + +1214C +CUNEIFORM SIGN IL TIMES GAN2 TENU + +1214D +CUNEIFORM SIGN IL2 + +1214E +CUNEIFORM SIGN IM + +1214F +CUNEIFORM SIGN IM TIMES TAK4 + +12150 +CUNEIFORM SIGN IM CROSSING IM + +12151 +CUNEIFORM SIGN IM OPPOSING IM + +12152 +CUNEIFORM SIGN IM SQUARED + +12153 +CUNEIFORM SIGN IMIN + +12154 +CUNEIFORM SIGN IN + +12155 +CUNEIFORM SIGN IR + +12156 +CUNEIFORM SIGN ISH + +12157 +CUNEIFORM SIGN KA + +12158 +CUNEIFORM SIGN KA TIMES A + +12159 +CUNEIFORM SIGN KA TIMES AD + +1215A +CUNEIFORM SIGN KA TIMES AD PLUS KU3 + +1215B +CUNEIFORM SIGN KA TIMES ASH2 + +1215C +CUNEIFORM SIGN KA TIMES BAD + +1215D +CUNEIFORM SIGN KA TIMES BALAG + +1215E +CUNEIFORM SIGN KA TIMES BAR + +1215F +CUNEIFORM SIGN KA TIMES BI + +12160 +CUNEIFORM SIGN KA TIMES ERIN2 + +12161 +CUNEIFORM SIGN KA TIMES ESH2 + +12162 +CUNEIFORM SIGN KA TIMES GA + +12163 +CUNEIFORM SIGN KA TIMES GAL + +12164 +CUNEIFORM SIGN KA TIMES GAN2 TENU + +12165 +CUNEIFORM SIGN KA TIMES GAR + +12166 +CUNEIFORM SIGN KA TIMES GAR PLUS SHA3 PLUS A + +12167 +CUNEIFORM SIGN KA TIMES GI + +12168 +CUNEIFORM SIGN KA TIMES GIR2 + +12169 +CUNEIFORM SIGN KA TIMES GISH PLUS SAR + +1216A +CUNEIFORM SIGN KA TIMES GISH CROSSING GISH + +1216B +CUNEIFORM SIGN KA TIMES GU + +1216C +CUNEIFORM SIGN KA TIMES GUR7 + +1216D +CUNEIFORM SIGN KA TIMES IGI + +1216E +CUNEIFORM SIGN KA TIMES IM + +1216F +CUNEIFORM SIGN KA TIMES KAK + +12170 +CUNEIFORM SIGN KA TIMES KI + +12171 +CUNEIFORM SIGN KA TIMES KID + +12172 +CUNEIFORM SIGN KA TIMES LI + +12173 +CUNEIFORM SIGN KA TIMES LU + +12174 +CUNEIFORM SIGN KA TIMES ME + +12175 +CUNEIFORM SIGN KA TIMES ME PLUS DU + +12176 +CUNEIFORM SIGN KA TIMES ME PLUS GI + +12177 +CUNEIFORM SIGN KA TIMES ME PLUS TE + +12178 +CUNEIFORM SIGN KA TIMES MI + +12179 +CUNEIFORM SIGN KA TIMES MI PLUS NUNUZ + +1217A +CUNEIFORM SIGN KA TIMES NE + +1217B +CUNEIFORM SIGN KA TIMES NUN + +1217C +CUNEIFORM SIGN KA TIMES PI + +1217D +CUNEIFORM SIGN KA TIMES RU + +1217E +CUNEIFORM SIGN KA TIMES SA + +1217F +CUNEIFORM SIGN KA TIMES SAR + +12180 +CUNEIFORM SIGN KA TIMES SHA + +12181 +CUNEIFORM SIGN KA TIMES SHE + +12182 +CUNEIFORM SIGN KA TIMES SHID + +12183 +CUNEIFORM SIGN KA TIMES SHU + +12184 +CUNEIFORM SIGN KA TIMES SIG + +12185 +CUNEIFORM SIGN KA TIMES SUHUR + +12186 +CUNEIFORM SIGN KA TIMES TAR + +12187 +CUNEIFORM SIGN KA TIMES U + +12188 +CUNEIFORM SIGN KA TIMES U2 + +12189 +CUNEIFORM SIGN KA TIMES UD + +1218A +CUNEIFORM SIGN KA TIMES UMUM TIMES PA + +1218B +CUNEIFORM SIGN KA TIMES USH + +1218C +CUNEIFORM SIGN KA TIMES ZI + +1218D +CUNEIFORM SIGN KA2 + +1218E +CUNEIFORM SIGN KA2 CROSSING KA2 + +1218F +CUNEIFORM SIGN KAB + +12190 +CUNEIFORM SIGN KAD2 + +12191 +CUNEIFORM SIGN KAD3 + +12192 +CUNEIFORM SIGN KAD4 + +12193 +CUNEIFORM SIGN KAD5 + +12194 +CUNEIFORM SIGN KAD5 OVER KAD5 + +12195 +CUNEIFORM SIGN KAK + +12196 +CUNEIFORM SIGN KAK TIMES IGI GUNU + +12197 +CUNEIFORM SIGN KAL + +12198 +CUNEIFORM SIGN KAL TIMES BAD + +12199 +CUNEIFORM SIGN KAL CROSSING KAL + +1219A +CUNEIFORM SIGN KAM2 + +1219B +CUNEIFORM SIGN KAM4 + +1219C +CUNEIFORM SIGN KASKAL + +1219D +CUNEIFORM SIGN KASKAL LAGAB TIMES U OVER LAGAB TIMES U + +1219E +CUNEIFORM SIGN KASKAL OVER KASKAL LAGAB TIMES U OVER LAGAB TIMES U + +1219F +CUNEIFORM SIGN KESH2 + +121A0 +CUNEIFORM SIGN KI + +121A1 +CUNEIFORM SIGN KI TIMES BAD + +121A2 +CUNEIFORM SIGN KI TIMES U + +121A3 +CUNEIFORM SIGN KI TIMES UD + +121A4 +CUNEIFORM SIGN KID + +121A5 +CUNEIFORM SIGN KIN + +121A6 +CUNEIFORM SIGN KISAL + +121A7 +CUNEIFORM SIGN KISH + +121A8 +CUNEIFORM SIGN KISIM5 + +121A9 +CUNEIFORM SIGN KISIM5 OVER KISIM5 + +121AA +CUNEIFORM SIGN KU + +121AB +CUNEIFORM SIGN KU OVER HI TIMES ASH2 KU OVER HI TIMES ASH2 + +121AC +CUNEIFORM SIGN KU3 + +121AD +CUNEIFORM SIGN KU4 + +121AE +CUNEIFORM SIGN KU4 VARIANT FORM + +121AF +CUNEIFORM SIGN KU7 + +121B0 +CUNEIFORM SIGN KUL + +121B1 +CUNEIFORM SIGN KUL GUNU + +121B2 +CUNEIFORM SIGN KUN + +121B3 +CUNEIFORM SIGN KUR + +121B4 +CUNEIFORM SIGN KUR OPPOSING KUR + +121B5 +CUNEIFORM SIGN KUSHU2 + +121B6 +CUNEIFORM SIGN KWU318 + +121B7 +CUNEIFORM SIGN LA + +121B8 +CUNEIFORM SIGN LAGAB + +121B9 +CUNEIFORM SIGN LAGAB TIMES A + +121BA +CUNEIFORM SIGN LAGAB TIMES A PLUS DA PLUS HA + +121BB +CUNEIFORM SIGN LAGAB TIMES A PLUS GAR + +121BC +CUNEIFORM SIGN LAGAB TIMES A PLUS LAL + +121BD +CUNEIFORM SIGN LAGAB TIMES AL + +121BE +CUNEIFORM SIGN LAGAB TIMES AN + +121BF +CUNEIFORM SIGN LAGAB TIMES ASH ZIDA TENU + +121C0 +CUNEIFORM SIGN LAGAB TIMES BAD + +121C1 +CUNEIFORM SIGN LAGAB TIMES BI + +121C2 +CUNEIFORM SIGN LAGAB TIMES DAR + +121C3 +CUNEIFORM SIGN LAGAB TIMES EN + +121C4 +CUNEIFORM SIGN LAGAB TIMES GA + +121C5 +CUNEIFORM SIGN LAGAB TIMES GAR + +121C6 +CUNEIFORM SIGN LAGAB TIMES GUD + +121C7 +CUNEIFORM SIGN LAGAB TIMES GUD PLUS GUD + +121C8 +CUNEIFORM SIGN LAGAB TIMES HA + +121C9 +CUNEIFORM SIGN LAGAB TIMES HAL + +121CA +CUNEIFORM SIGN LAGAB TIMES HI TIMES NUN + +121CB +CUNEIFORM SIGN LAGAB TIMES IGI GUNU + +121CC +CUNEIFORM SIGN LAGAB TIMES IM + +121CD +CUNEIFORM SIGN LAGAB TIMES IM PLUS HA + +121CE +CUNEIFORM SIGN LAGAB TIMES IM PLUS LU + +121CF +CUNEIFORM SIGN LAGAB TIMES KI + +121D0 +CUNEIFORM SIGN LAGAB TIMES KIN + +121D1 +CUNEIFORM SIGN LAGAB TIMES KU3 + +121D2 +CUNEIFORM SIGN LAGAB TIMES KUL + +121D3 +CUNEIFORM SIGN LAGAB TIMES KUL PLUS HI PLUS A + +121D4 +CUNEIFORM SIGN LAGAB TIMES LAGAB + +121D5 +CUNEIFORM SIGN LAGAB TIMES LISH + +121D6 +CUNEIFORM SIGN LAGAB TIMES LU + +121D7 +CUNEIFORM SIGN LAGAB TIMES LUL + +121D8 +CUNEIFORM SIGN LAGAB TIMES ME + +121D9 +CUNEIFORM SIGN LAGAB TIMES ME PLUS EN + +121DA +CUNEIFORM SIGN LAGAB TIMES MUSH + +121DB +CUNEIFORM SIGN LAGAB TIMES NE + +121DC +CUNEIFORM SIGN LAGAB TIMES SHE PLUS SUM + +121DD +CUNEIFORM SIGN LAGAB TIMES SHITA PLUS GISH PLUS ERIN2 + +121DE +CUNEIFORM SIGN LAGAB TIMES SHITA PLUS GISH TENU + +121DF +CUNEIFORM SIGN LAGAB TIMES SHU2 + +121E0 +CUNEIFORM SIGN LAGAB TIMES SHU2 PLUS SHU2 + +121E1 +CUNEIFORM SIGN LAGAB TIMES SUM + +121E2 +CUNEIFORM SIGN LAGAB TIMES TAG + +121E3 +CUNEIFORM SIGN LAGAB TIMES TAK4 + +121E4 +CUNEIFORM SIGN LAGAB TIMES TE PLUS A PLUS SU PLUS NA + +121E5 +CUNEIFORM SIGN LAGAB TIMES U + +121E6 +CUNEIFORM SIGN LAGAB TIMES U PLUS A + +121E7 +CUNEIFORM SIGN LAGAB TIMES U PLUS U PLUS U + +121E8 +CUNEIFORM SIGN LAGAB TIMES U2 PLUS ASH + +121E9 +CUNEIFORM SIGN LAGAB TIMES UD + +121EA +CUNEIFORM SIGN LAGAB TIMES USH + +121EB +CUNEIFORM SIGN LAGAB SQUARED + +121EC +CUNEIFORM SIGN LAGAR + +121ED +CUNEIFORM SIGN LAGAR TIMES SHE + +121EE +CUNEIFORM SIGN LAGAR TIMES SHE PLUS SUM + +121EF +CUNEIFORM SIGN LAGAR GUNU + +121F0 +CUNEIFORM SIGN LAGAR GUNU OVER LAGAR GUNU SHE + +121F1 +CUNEIFORM SIGN LAHSHU + +121F2 +CUNEIFORM SIGN LAL + +121F3 +CUNEIFORM SIGN LAL TIMES LAL + +121F4 +CUNEIFORM SIGN LAM + +121F5 +CUNEIFORM SIGN LAM TIMES KUR + +121F6 +CUNEIFORM SIGN LAM TIMES KUR PLUS RU + +121F7 +CUNEIFORM SIGN LI + +121F8 +CUNEIFORM SIGN LIL + +121F9 +CUNEIFORM SIGN LIMMU2 + +121FA +CUNEIFORM SIGN LISH + +121FB +CUNEIFORM SIGN LU + +121FC +CUNEIFORM SIGN LU TIMES BAD + +121FD +CUNEIFORM SIGN LU2 + +121FE +CUNEIFORM SIGN LU2 TIMES AL + +121FF +CUNEIFORM SIGN LU2 TIMES BAD + +12200 +CUNEIFORM SIGN LU2 TIMES ESH2 + +12201 +CUNEIFORM SIGN LU2 TIMES ESH2 TENU + +12202 +CUNEIFORM SIGN LU2 TIMES GAN2 TENU + +12203 +CUNEIFORM SIGN LU2 TIMES HI TIMES BAD + +12204 +CUNEIFORM SIGN LU2 TIMES IM + +12205 +CUNEIFORM SIGN LU2 TIMES KAD2 + +12206 +CUNEIFORM SIGN LU2 TIMES KAD3 + +12207 +CUNEIFORM SIGN LU2 TIMES KAD3 PLUS ASH + +12208 +CUNEIFORM SIGN LU2 TIMES KI + +12209 +CUNEIFORM SIGN LU2 TIMES LA PLUS ASH + +1220A +CUNEIFORM SIGN LU2 TIMES LAGAB + +1220B +CUNEIFORM SIGN LU2 TIMES ME PLUS EN + +1220C +CUNEIFORM SIGN LU2 TIMES NE + +1220D +CUNEIFORM SIGN LU2 TIMES NU + +1220E +CUNEIFORM SIGN LU2 TIMES SI PLUS ASH + +1220F +CUNEIFORM SIGN LU2 TIMES SIK2 PLUS BU + +12210 +CUNEIFORM SIGN LU2 TIMES TUG2 + +12211 +CUNEIFORM SIGN LU2 TENU + +12212 +CUNEIFORM SIGN LU2 CROSSING LU2 + +12213 +CUNEIFORM SIGN LU2 OPPOSING LU2 + +12214 +CUNEIFORM SIGN LU2 SQUARED + +12215 +CUNEIFORM SIGN LU2 SHESHIG + +12216 +CUNEIFORM SIGN LU3 + +12217 +CUNEIFORM SIGN LUGAL + +12218 +CUNEIFORM SIGN LUGAL OVER LUGAL + +12219 +CUNEIFORM SIGN LUGAL OPPOSING LUGAL + +1221A +CUNEIFORM SIGN LUGAL SHESHIG + +1221B +CUNEIFORM SIGN LUH + +1221C +CUNEIFORM SIGN LUL + +1221D +CUNEIFORM SIGN LUM + +1221E +CUNEIFORM SIGN LUM OVER LUM + +1221F +CUNEIFORM SIGN LUM OVER LUM GAR OVER GAR + +12220 +CUNEIFORM SIGN MA + +12221 +CUNEIFORM SIGN MA TIMES TAK4 + +12222 +CUNEIFORM SIGN MA GUNU + +12223 +CUNEIFORM SIGN MA2 + +12224 +CUNEIFORM SIGN MAH + +12225 +CUNEIFORM SIGN MAR + +12226 +CUNEIFORM SIGN MASH + +12227 +CUNEIFORM SIGN MASH2 + +12228 +CUNEIFORM SIGN ME + +12229 +CUNEIFORM SIGN MES + +1222A +CUNEIFORM SIGN MI + +1222B +CUNEIFORM SIGN MIN + +1222C +CUNEIFORM SIGN MU + +1222D +CUNEIFORM SIGN MU OVER MU + +1222E +CUNEIFORM SIGN MUG + +1222F +CUNEIFORM SIGN MUG GUNU + +12230 +CUNEIFORM SIGN MUNSUB + +12231 +CUNEIFORM SIGN MURGU2 + +12232 +CUNEIFORM SIGN MUSH + +12233 +CUNEIFORM SIGN MUSH TIMES A + +12234 +CUNEIFORM SIGN MUSH TIMES KUR + +12235 +CUNEIFORM SIGN MUSH TIMES ZA + +12236 +CUNEIFORM SIGN MUSH OVER MUSH + +12237 +CUNEIFORM SIGN MUSH OVER MUSH TIMES A PLUS NA + +12238 +CUNEIFORM SIGN MUSH CROSSING MUSH + +12239 +CUNEIFORM SIGN MUSH3 + +1223A +CUNEIFORM SIGN MUSH3 TIMES A + +1223B +CUNEIFORM SIGN MUSH3 TIMES A PLUS DI + +1223C +CUNEIFORM SIGN MUSH3 TIMES DI + +1223D +CUNEIFORM SIGN MUSH3 GUNU + +1223E +CUNEIFORM SIGN NA + +1223F +CUNEIFORM SIGN NA2 + +12240 +CUNEIFORM SIGN NAGA + +12241 +CUNEIFORM SIGN NAGA INVERTED + +12242 +CUNEIFORM SIGN NAGA TIMES SHU TENU + +12243 +CUNEIFORM SIGN NAGA OPPOSING NAGA + +12244 +CUNEIFORM SIGN NAGAR + +12245 +CUNEIFORM SIGN NAM NUTILLU + +12246 +CUNEIFORM SIGN NAM + +12247 +CUNEIFORM SIGN NAM2 + +12248 +CUNEIFORM SIGN NE + +12249 +CUNEIFORM SIGN NE TIMES A + +1224A +CUNEIFORM SIGN NE TIMES UD + +1224B +CUNEIFORM SIGN NE SHESHIG + +1224C +CUNEIFORM SIGN NI + +1224D +CUNEIFORM SIGN NI TIMES E + +1224E +CUNEIFORM SIGN NI2 + +1224F +CUNEIFORM SIGN NIM + +12250 +CUNEIFORM SIGN NIM TIMES GAN2 TENU + +12251 +CUNEIFORM SIGN NIM TIMES GAR PLUS GAN2 TENU + +12252 +CUNEIFORM SIGN NINDA2 + +12253 +CUNEIFORM SIGN NINDA2 TIMES AN + +12254 +CUNEIFORM SIGN NINDA2 TIMES ASH + +12255 +CUNEIFORM SIGN NINDA2 TIMES ASH PLUS ASH + +12256 +CUNEIFORM SIGN NINDA2 TIMES GUD + +12257 +CUNEIFORM SIGN NINDA2 TIMES ME PLUS GAN2 TENU + +12258 +CUNEIFORM SIGN NINDA2 TIMES NE + +12259 +CUNEIFORM SIGN NINDA2 TIMES NUN + +1225A +CUNEIFORM SIGN NINDA2 TIMES SHE + +1225B +CUNEIFORM SIGN NINDA2 TIMES SHE PLUS A AN + +1225C +CUNEIFORM SIGN NINDA2 TIMES SHE PLUS ASH + +1225D +CUNEIFORM SIGN NINDA2 TIMES SHE PLUS ASH PLUS ASH + +1225E +CUNEIFORM SIGN NINDA2 TIMES U2 PLUS ASH + +1225F +CUNEIFORM SIGN NINDA2 TIMES USH + +12260 +CUNEIFORM SIGN NISAG + +12261 +CUNEIFORM SIGN NU + +12262 +CUNEIFORM SIGN NU11 + +12263 +CUNEIFORM SIGN NUN + +12264 +CUNEIFORM SIGN NUN LAGAR TIMES GAR + +12265 +CUNEIFORM SIGN NUN LAGAR TIMES MASH + +12266 +CUNEIFORM SIGN NUN LAGAR TIMES SAL + +12267 +CUNEIFORM SIGN NUN LAGAR TIMES SAL OVER NUN LAGAR TIMES SAL + +12268 +CUNEIFORM SIGN NUN LAGAR TIMES USH + +12269 +CUNEIFORM SIGN NUN TENU + +1226A +CUNEIFORM SIGN NUN OVER NUN + +1226B +CUNEIFORM SIGN NUN CROSSING NUN + +1226C +CUNEIFORM SIGN NUN CROSSING NUN LAGAR OVER LAGAR + +1226D +CUNEIFORM SIGN NUNUZ + +1226E +CUNEIFORM SIGN NUNUZ AB2 TIMES ASHGAB + +1226F +CUNEIFORM SIGN NUNUZ AB2 TIMES BI + +12270 +CUNEIFORM SIGN NUNUZ AB2 TIMES DUG + +12271 +CUNEIFORM SIGN NUNUZ AB2 TIMES GUD + +12272 +CUNEIFORM SIGN NUNUZ AB2 TIMES IGI GUNU + +12273 +CUNEIFORM SIGN NUNUZ AB2 TIMES KAD3 + +12274 +CUNEIFORM SIGN NUNUZ AB2 TIMES LA + +12275 +CUNEIFORM SIGN NUNUZ AB2 TIMES NE + +12276 +CUNEIFORM SIGN NUNUZ AB2 TIMES SILA3 + +12277 +CUNEIFORM SIGN NUNUZ AB2 TIMES U2 + +12278 +CUNEIFORM SIGN NUNUZ KISIM5 TIMES BI + +12279 +CUNEIFORM SIGN NUNUZ KISIM5 TIMES BI U + +1227A +CUNEIFORM SIGN PA + +1227B +CUNEIFORM SIGN PAD + +1227C +CUNEIFORM SIGN PAN + +1227D +CUNEIFORM SIGN PAP + +1227E +CUNEIFORM SIGN PESH2 + +1227F +CUNEIFORM SIGN PI + +12280 +CUNEIFORM SIGN PI TIMES A + +12281 +CUNEIFORM SIGN PI TIMES AB + +12282 +CUNEIFORM SIGN PI TIMES BI + +12283 +CUNEIFORM SIGN PI TIMES BU + +12284 +CUNEIFORM SIGN PI TIMES E + +12285 +CUNEIFORM SIGN PI TIMES I + +12286 +CUNEIFORM SIGN PI TIMES IB + +12287 +CUNEIFORM SIGN PI TIMES U + +12288 +CUNEIFORM SIGN PI TIMES U2 + +12289 +CUNEIFORM SIGN PI CROSSING PI + +1228A +CUNEIFORM SIGN PIRIG + +1228B +CUNEIFORM SIGN PIRIG TIMES KAL + +1228C +CUNEIFORM SIGN PIRIG TIMES UD + +1228D +CUNEIFORM SIGN PIRIG TIMES ZA + +1228E +CUNEIFORM SIGN PIRIG OPPOSING PIRIG + +1228F +CUNEIFORM SIGN RA + +12290 +CUNEIFORM SIGN RAB + +12291 +CUNEIFORM SIGN RI + +12292 +CUNEIFORM SIGN RU + +12293 +CUNEIFORM SIGN SA + +12294 +CUNEIFORM SIGN SAG NUTILLU + +12295 +CUNEIFORM SIGN SAG + +12296 +CUNEIFORM SIGN SAG TIMES A + +12297 +CUNEIFORM SIGN SAG TIMES DU + +12298 +CUNEIFORM SIGN SAG TIMES DUB + +12299 +CUNEIFORM SIGN SAG TIMES HA + +1229A +CUNEIFORM SIGN SAG TIMES KAK + +1229B +CUNEIFORM SIGN SAG TIMES KUR + +1229C +CUNEIFORM SIGN SAG TIMES LUM + +1229D +CUNEIFORM SIGN SAG TIMES MI + +1229E +CUNEIFORM SIGN SAG TIMES NUN + +1229F +CUNEIFORM SIGN SAG TIMES SAL + +122A0 +CUNEIFORM SIGN SAG TIMES SHID + +122A1 +CUNEIFORM SIGN SAG TIMES TAB + +122A2 +CUNEIFORM SIGN SAG TIMES U2 + +122A3 +CUNEIFORM SIGN SAG TIMES UB + +122A4 +CUNEIFORM SIGN SAG TIMES UM + +122A5 +CUNEIFORM SIGN SAG TIMES UR + +122A6 +CUNEIFORM SIGN SAG TIMES USH + +122A7 +CUNEIFORM SIGN SAG OVER SAG + +122A8 +CUNEIFORM SIGN SAG GUNU + +122A9 +CUNEIFORM SIGN SAL + +122AA +CUNEIFORM SIGN SAL LAGAB TIMES ASH2 + +122AB +CUNEIFORM SIGN SANGA2 + +122AC +CUNEIFORM SIGN SAR + +122AD +CUNEIFORM SIGN SHA + +122AE +CUNEIFORM SIGN SHA3 + +122AF +CUNEIFORM SIGN SHA3 TIMES A + +122B0 +CUNEIFORM SIGN SHA3 TIMES BAD + +122B1 +CUNEIFORM SIGN SHA3 TIMES GISH + +122B2 +CUNEIFORM SIGN SHA3 TIMES NE + +122B3 +CUNEIFORM SIGN SHA3 TIMES SHU2 + +122B4 +CUNEIFORM SIGN SHA3 TIMES TUR + +122B5 +CUNEIFORM SIGN SHA3 TIMES U + +122B6 +CUNEIFORM SIGN SHA3 TIMES U PLUS A + +122B7 +CUNEIFORM SIGN SHA6 + +122B8 +CUNEIFORM SIGN SHAB6 + +122B9 +CUNEIFORM SIGN SHAR2 + +122BA +CUNEIFORM SIGN SHE + +122BB +CUNEIFORM SIGN SHE HU + +122BC +CUNEIFORM SIGN SHE OVER SHE GAD OVER GAD GAR OVER GAR + +122BD +CUNEIFORM SIGN SHE OVER SHE TAB OVER TAB GAR OVER GAR + +122BE +CUNEIFORM SIGN SHEG9 + +122BF +CUNEIFORM SIGN SHEN + +122C0 +CUNEIFORM SIGN SHESH + +122C1 +CUNEIFORM SIGN SHESH2 + +122C2 +CUNEIFORM SIGN SHESHLAM + +122C3 +CUNEIFORM SIGN SHID + +122C4 +CUNEIFORM SIGN SHID TIMES A + +122C5 +CUNEIFORM SIGN SHID TIMES IM + +122C6 +CUNEIFORM SIGN SHIM + +122C7 +CUNEIFORM SIGN SHIM TIMES A + +122C8 +CUNEIFORM SIGN SHIM TIMES BAL + +122C9 +CUNEIFORM SIGN SHIM TIMES BULUG + +122CA +CUNEIFORM SIGN SHIM TIMES DIN + +122CB +CUNEIFORM SIGN SHIM TIMES GAR + +122CC +CUNEIFORM SIGN SHIM TIMES IGI + +122CD +CUNEIFORM SIGN SHIM TIMES IGI GUNU + +122CE +CUNEIFORM SIGN SHIM TIMES KUSHU2 + +122CF +CUNEIFORM SIGN SHIM TIMES LUL + +122D0 +CUNEIFORM SIGN SHIM TIMES MUG + +122D1 +CUNEIFORM SIGN SHIM TIMES SAL + +122D2 +CUNEIFORM SIGN SHINIG + +122D3 +CUNEIFORM SIGN SHIR + +122D4 +CUNEIFORM SIGN NU11 TENU + +122D4 +CUNEIFORM SIGN SHIR TENU + +122D5 +CUNEIFORM SIGN NU11 OVER NU11 BUR OVER BUR + +122D5 +CUNEIFORM SIGN SHIR OVER SHIR BUR OVER BUR + +122D6 +CUNEIFORM SIGN SHITA + +122D7 +CUNEIFORM SIGN SHU + +122D8 +CUNEIFORM SIGN SHU OVER INVERTED SHU + +122D9 +CUNEIFORM SIGN SHU2 + +122DA +CUNEIFORM SIGN SHUBUR + +122DB +CUNEIFORM SIGN SI + +122DC +CUNEIFORM SIGN SI GUNU + +122DD +CUNEIFORM SIGN SIG + +122DE +CUNEIFORM SIGN SIG4 + +122DF +CUNEIFORM SIGN SIG4 OVER SIG4 SHU2 + +122E0 +CUNEIFORM SIGN SIK2 + +122E1 +CUNEIFORM SIGN SILA3 + +122E2 +CUNEIFORM SIGN SU + +122E3 +CUNEIFORM SIGN SU OVER SU + +122E4 +CUNEIFORM SIGN SUD + +122E5 +CUNEIFORM SIGN SUD2 + +122E6 +CUNEIFORM SIGN SUHUR + +122E7 +CUNEIFORM SIGN SUM + +122E8 +CUNEIFORM SIGN SUMASH + +122E9 +CUNEIFORM SIGN SUR + +122EA +CUNEIFORM SIGN SUR9 + +122EB +CUNEIFORM SIGN TA + +122EC +CUNEIFORM SIGN TA ASTERISK + +122ED +CUNEIFORM SIGN TA TIMES HI + +122EE +CUNEIFORM SIGN TA TIMES MI + +122EF +CUNEIFORM SIGN TA GUNU + +122F0 +CUNEIFORM SIGN TAB + +122F1 +CUNEIFORM SIGN TAB OVER TAB NI OVER NI DISH OVER DISH + +122F2 +CUNEIFORM SIGN TAB SQUARED + +122F3 +CUNEIFORM SIGN TAG + +122F4 +CUNEIFORM SIGN TAG TIMES BI + +122F5 +CUNEIFORM SIGN TAG TIMES GUD + +122F6 +CUNEIFORM SIGN TAG TIMES SHE + +122F7 +CUNEIFORM SIGN TAG TIMES SHU + +122F8 +CUNEIFORM SIGN TAG TIMES TUG2 + +122F9 +CUNEIFORM SIGN TAG TIMES UD + +122FA +CUNEIFORM SIGN TAK4 + +122FB +CUNEIFORM SIGN TAR + +122FC +CUNEIFORM SIGN TE + +122FD +CUNEIFORM SIGN TE GUNU + +122FE +CUNEIFORM SIGN TI + +122FF +CUNEIFORM SIGN TI TENU + +12300 +CUNEIFORM SIGN TIL + +12301 +CUNEIFORM SIGN TIR + +12302 +CUNEIFORM SIGN TIR TIMES TAK4 + +12303 +CUNEIFORM SIGN TIR OVER TIR + +12304 +CUNEIFORM SIGN TIR OVER TIR GAD OVER GAD GAR OVER GAR + +12305 +CUNEIFORM SIGN TU + +12306 +CUNEIFORM SIGN TUG2 + +12307 +CUNEIFORM SIGN TUK + +12308 +CUNEIFORM SIGN TUM + +12309 +CUNEIFORM SIGN TUR + +1230A +CUNEIFORM SIGN TUR OVER TUR ZA OVER ZA + +1230B +CUNEIFORM SIGN U + +1230C +CUNEIFORM SIGN U GUD + +1230D +CUNEIFORM SIGN U U U + +1230E +CUNEIFORM SIGN U OVER U PA OVER PA GAR OVER GAR + +1230F +CUNEIFORM SIGN U OVER U SUR OVER SUR + +12310 +CUNEIFORM SIGN U OVER U U REVERSED OVER U REVERSED + +12311 +CUNEIFORM SIGN U2 + +12312 +CUNEIFORM SIGN UB + +12313 +CUNEIFORM SIGN UD + +12314 +CUNEIFORM SIGN UD KUSHU2 + +12315 +CUNEIFORM SIGN UD TIMES BAD + +12316 +CUNEIFORM SIGN UD TIMES MI + +12317 +CUNEIFORM SIGN UD TIMES U PLUS U PLUS U + +12318 +CUNEIFORM SIGN UD TIMES U PLUS U PLUS U GUNU + +12319 +CUNEIFORM SIGN UD GUNU + +1231A +CUNEIFORM SIGN UD SHESHIG + +1231B +CUNEIFORM SIGN UD SHESHIG TIMES BAD + +1231C +CUNEIFORM SIGN UDUG + +1231D +CUNEIFORM SIGN UM + +1231E +CUNEIFORM SIGN UM TIMES LAGAB + +1231F +CUNEIFORM SIGN UM TIMES ME PLUS DA + +12320 +CUNEIFORM SIGN UM TIMES SHA3 + +12321 +CUNEIFORM SIGN UM TIMES U + +12322 +CUNEIFORM SIGN UMBIN + +12323 +CUNEIFORM SIGN UMUM + +12324 +CUNEIFORM SIGN UMUM TIMES KASKAL + +12325 +CUNEIFORM SIGN UMUM TIMES PA + +12326 +CUNEIFORM SIGN UN + +12327 +CUNEIFORM SIGN KALAM + +12327 +CUNEIFORM SIGN UN GUNU + +12328 +CUNEIFORM SIGN UR + +12329 +CUNEIFORM SIGN UR CROSSING UR + +1232A +CUNEIFORM SIGN UR SHESHIG + +1232B +CUNEIFORM SIGN UR2 + +1232C +CUNEIFORM SIGN UR2 TIMES A PLUS HA + +1232D +CUNEIFORM SIGN UR2 TIMES A PLUS NA + +1232E +CUNEIFORM SIGN UR2 TIMES AL + +1232F +CUNEIFORM SIGN UR2 TIMES HA + +12330 +CUNEIFORM SIGN UR2 TIMES NUN + +12331 +CUNEIFORM SIGN UR2 TIMES U2 + +12332 +CUNEIFORM SIGN UR2 TIMES U2 PLUS ASH + +12333 +CUNEIFORM SIGN UR2 TIMES U2 PLUS BI + +12334 +CUNEIFORM SIGN UR4 + +12335 +CUNEIFORM SIGN URI + +12336 +CUNEIFORM SIGN URI3 + +12337 +CUNEIFORM SIGN URU + +12338 +CUNEIFORM SIGN URU TIMES A + +12339 +CUNEIFORM SIGN URU TIMES ASHGAB + +1233A +CUNEIFORM SIGN URU TIMES BAR + +1233B +CUNEIFORM SIGN URU TIMES DUN + +1233C +CUNEIFORM SIGN URU TIMES GA + +1233D +CUNEIFORM SIGN URU TIMES GAL + +1233E +CUNEIFORM SIGN URU TIMES GAN2 TENU + +1233F +CUNEIFORM SIGN URU TIMES GAR + +12340 +CUNEIFORM SIGN URU TIMES GU + +12341 +CUNEIFORM SIGN URU TIMES HA + +12342 +CUNEIFORM SIGN URU TIMES IGI + +12343 +CUNEIFORM SIGN URU TIMES IM + +12344 +CUNEIFORM SIGN URU TIMES ISH + +12345 +CUNEIFORM SIGN URU TIMES KI + +12346 +CUNEIFORM SIGN URU TIMES LUM + +12347 +CUNEIFORM SIGN URU TIMES MIN + +12348 +CUNEIFORM SIGN URU TIMES PA + +12349 +CUNEIFORM SIGN URU TIMES SHE + +1234A +CUNEIFORM SIGN URU TIMES SIG4 + +1234B +CUNEIFORM SIGN URU TIMES TU + +1234C +CUNEIFORM SIGN URU TIMES U PLUS GUD + +1234D +CUNEIFORM SIGN URU TIMES UD + +1234E +CUNEIFORM SIGN URU TIMES URUDA + +1234F +CUNEIFORM SIGN URUDA + +12350 +CUNEIFORM SIGN URUDA TIMES U + +12351 +CUNEIFORM SIGN USH + +12352 +CUNEIFORM SIGN USH TIMES A + +12353 +CUNEIFORM SIGN USH TIMES KU + +12354 +CUNEIFORM SIGN USH TIMES KUR + +12355 +CUNEIFORM SIGN USH TIMES TAK4 + +12356 +CUNEIFORM SIGN USHX + +12357 +CUNEIFORM SIGN USH2 + +12358 +CUNEIFORM SIGN USHUMX + +12359 +CUNEIFORM SIGN UTUKI + +1235A +CUNEIFORM SIGN UZ3 + +1235B +CUNEIFORM SIGN UZ3 TIMES KASKAL + +1235C +CUNEIFORM SIGN UZU + +1235D +CUNEIFORM SIGN ZA + +1235E +CUNEIFORM SIGN ZA TENU + +1235F +CUNEIFORM SIGN ZA SQUARED TIMES KUR + +12360 +CUNEIFORM SIGN ZAG + +12361 +CUNEIFORM SIGN ZAMX + +12362 +CUNEIFORM SIGN ZE2 + +12363 +CUNEIFORM SIGN ZI + +12364 +CUNEIFORM SIGN ZI OVER ZI + +12365 +CUNEIFORM SIGN ZI3 + +12366 +CUNEIFORM SIGN ZIB + +12367 +CUNEIFORM SIGN ZIB KABA TENU + +12368 +CUNEIFORM SIGN ZIG + +12369 +CUNEIFORM SIGN ZIZ2 + +1236A +CUNEIFORM SIGN ZU + +1236B +CUNEIFORM SIGN ZU5 + +1236C +CUNEIFORM SIGN ZU5 TIMES A + +1236D +CUNEIFORM SIGN ZUBUR + +1236E +CUNEIFORM SIGN ZUM + +1236F +CUNEIFORM SIGN KAP ELAMITE + +12370 +CUNEIFORM SIGN AB TIMES NUN + +12371 +CUNEIFORM SIGN AB2 TIMES A + +12372 +CUNEIFORM SIGN AMAR TIMES KUG + +12373 +CUNEIFORM SIGN DAG KISIM5 TIMES U2 PLUS MASH + +12374 +CUNEIFORM SIGN DAG3 + +12375 +CUNEIFORM SIGN DISH PLUS SHU + +12376 +CUNEIFORM SIGN DUB TIMES SHE + +12377 +CUNEIFORM SIGN EZEN TIMES GUD + +12378 +CUNEIFORM SIGN EZEN TIMES SHE + +12379 +CUNEIFORM SIGN GA2 TIMES AN PLUS KAK PLUS A + +1237A +CUNEIFORM SIGN GA2 TIMES ASH2 + +1237B +CUNEIFORM SIGN GE22 + +1237C +CUNEIFORM SIGN GIG + +1237D +CUNEIFORM SIGN HUSH + +1237E +CUNEIFORM SIGN KA TIMES ANSHE + +1237F +CUNEIFORM SIGN KA TIMES ASH3 + +12380 +CUNEIFORM SIGN KA TIMES GISH + +12381 +CUNEIFORM SIGN KA TIMES GUD + +12382 +CUNEIFORM SIGN KA TIMES HI TIMES ASH2 + +12383 +CUNEIFORM SIGN KA TIMES LUM + +12384 +CUNEIFORM SIGN KA TIMES PA + +12385 +CUNEIFORM SIGN KA TIMES SHUL + +12386 +CUNEIFORM SIGN KA TIMES TU + +12387 +CUNEIFORM SIGN KA TIMES UR2 + +12388 +CUNEIFORM SIGN LAGAB TIMES GI + +12389 +CUNEIFORM SIGN LU2 SHESHIG TIMES BAD + +1238A +CUNEIFORM SIGN LU2 TIMES ESH2 PLUS LAL + +1238B +CUNEIFORM SIGN LU2 TIMES SHU + +1238C +CUNEIFORM SIGN MESH + +1238D +CUNEIFORM SIGN MUSH3 TIMES ZA + +1238E +CUNEIFORM SIGN NA4 + +1238F +CUNEIFORM SIGN NIN + +12390 +CUNEIFORM SIGN NIN9 + +12391 +CUNEIFORM SIGN NINDA2 TIMES BAL + +12392 +CUNEIFORM SIGN NINDA2 TIMES GI + +12393 +CUNEIFORM SIGN NU11 ROTATED NINETY DEGREES + +12394 +CUNEIFORM SIGN PESH2 ASTERISK + +12395 +CUNEIFORM SIGN PIR2 + +12396 +CUNEIFORM SIGN SAG TIMES IGI GUNU + +12397 +CUNEIFORM SIGN TI2 + +12398 +CUNEIFORM SIGN UM TIMES ME + +12399 +CUNEIFORM SIGN U U + +12400 +CUNEIFORM NUMERIC SIGN TWO ASH + +12401 +CUNEIFORM NUMERIC SIGN THREE ASH + +12402 +CUNEIFORM NUMERIC SIGN FOUR ASH + +12403 +CUNEIFORM NUMERIC SIGN FIVE ASH + +12404 +CUNEIFORM NUMERIC SIGN SIX ASH + +12405 +CUNEIFORM NUMERIC SIGN SEVEN ASH + +12406 +CUNEIFORM NUMERIC SIGN EIGHT ASH + +12407 +CUNEIFORM NUMERIC SIGN NINE ASH + +12408 +CUNEIFORM NUMERIC SIGN THREE DISH + +12409 +CUNEIFORM NUMERIC SIGN FOUR DISH + +1240A +CUNEIFORM NUMERIC SIGN FIVE DISH + +1240B +CUNEIFORM NUMERIC SIGN SIX DISH + +1240C +CUNEIFORM NUMERIC SIGN SEVEN DISH + +1240D +CUNEIFORM NUMERIC SIGN EIGHT DISH + +1240E +CUNEIFORM NUMERIC SIGN NINE DISH + +1240F +CUNEIFORM NUMERIC SIGN FOUR U + +12410 +CUNEIFORM NUMERIC SIGN FIVE U + +12411 +CUNEIFORM NUMERIC SIGN SIX U + +12412 +CUNEIFORM NUMERIC SIGN SEVEN U + +12413 +CUNEIFORM NUMERIC SIGN EIGHT U + +12414 +CUNEIFORM NUMERIC SIGN NINE U + +12415 +CUNEIFORM NUMERIC SIGN ONE GESH2 + +12416 +CUNEIFORM NUMERIC SIGN TWO GESH2 + +12417 +CUNEIFORM NUMERIC SIGN THREE GESH2 + +12418 +CUNEIFORM NUMERIC SIGN FOUR GESH2 + +12419 +CUNEIFORM NUMERIC SIGN FIVE GESH2 + +1241A +CUNEIFORM NUMERIC SIGN SIX GESH2 + +1241B +CUNEIFORM NUMERIC SIGN SEVEN GESH2 + +1241C +CUNEIFORM NUMERIC SIGN EIGHT GESH2 + +1241D +CUNEIFORM NUMERIC SIGN NINE GESH2 + +1241E +CUNEIFORM NUMERIC SIGN ONE GESHU + +1241F +CUNEIFORM NUMERIC SIGN TWO GESHU + +12420 +CUNEIFORM NUMERIC SIGN THREE GESHU + +12421 +CUNEIFORM NUMERIC SIGN FOUR GESHU + +12422 +CUNEIFORM NUMERIC SIGN FIVE GESHU + +12423 +CUNEIFORM NUMERIC SIGN TWO SHAR2 + +12424 +CUNEIFORM NUMERIC SIGN THREE SHAR2 + +12425 +CUNEIFORM NUMERIC SIGN THREE SHAR2 VARIANT FORM + +12426 +CUNEIFORM NUMERIC SIGN FOUR SHAR2 + +12427 +CUNEIFORM NUMERIC SIGN FIVE SHAR2 + +12428 +CUNEIFORM NUMERIC SIGN SIX SHAR2 + +12429 +CUNEIFORM NUMERIC SIGN SEVEN SHAR2 + +1242A +CUNEIFORM NUMERIC SIGN EIGHT SHAR2 + +1242B +CUNEIFORM NUMERIC SIGN NINE SHAR2 + +1242C +CUNEIFORM NUMERIC SIGN ONE SHARU + +1242D +CUNEIFORM NUMERIC SIGN TWO SHARU + +1242E +CUNEIFORM NUMERIC SIGN THREE SHARU + +1242F +CUNEIFORM NUMERIC SIGN THREE SHARU VARIANT FORM + +12430 +CUNEIFORM NUMERIC SIGN FOUR SHARU + +12431 +CUNEIFORM NUMERIC SIGN FIVE SHARU + +12432 +CUNEIFORM NUMERIC SIGN SHAR2 TIMES GAL PLUS DISH + +12433 +CUNEIFORM NUMERIC SIGN SHAR2 TIMES GAL PLUS MIN + +12434 +CUNEIFORM NUMERIC SIGN ONE BURU + +12435 +CUNEIFORM NUMERIC SIGN TWO BURU + +12436 +CUNEIFORM NUMERIC SIGN THREE BURU + +12437 +CUNEIFORM NUMERIC SIGN THREE BURU VARIANT FORM + +12438 +CUNEIFORM NUMERIC SIGN FOUR BURU + +12439 +CUNEIFORM NUMERIC SIGN FIVE BURU + +1243A +CUNEIFORM NUMERIC SIGN THREE VARIANT FORM ESH16 + +1243B +CUNEIFORM NUMERIC SIGN THREE VARIANT FORM ESH21 + +1243C +CUNEIFORM NUMERIC SIGN FOUR VARIANT FORM LIMMU + +1243D +CUNEIFORM NUMERIC SIGN FOUR VARIANT FORM LIMMU4 + +1243E +CUNEIFORM NUMERIC SIGN FOUR VARIANT FORM LIMMU A + +1243F +CUNEIFORM NUMERIC SIGN FOUR VARIANT FORM LIMMU B + +12440 +CUNEIFORM NUMERIC SIGN SIX VARIANT FORM ASH9 + +12441 +CUNEIFORM NUMERIC SIGN SEVEN VARIANT FORM IMIN3 + +12442 +CUNEIFORM NUMERIC SIGN SEVEN VARIANT FORM IMIN A + +12443 +CUNEIFORM NUMERIC SIGN SEVEN VARIANT FORM IMIN B + +12444 +CUNEIFORM NUMERIC SIGN EIGHT VARIANT FORM USSU + +12445 +CUNEIFORM NUMERIC SIGN EIGHT VARIANT FORM USSU3 + +12446 +CUNEIFORM NUMERIC SIGN NINE VARIANT FORM ILIMMU + +12447 +CUNEIFORM NUMERIC SIGN NINE VARIANT FORM ILIMMU3 + +12448 +CUNEIFORM NUMERIC SIGN NINE VARIANT FORM ILIMMU4 + +12449 +CUNEIFORM NUMERIC SIGN NINE VARIANT FORM ILIMMU A + +1244A +CUNEIFORM NUMERIC SIGN TWO ASH TENU + +1244B +CUNEIFORM NUMERIC SIGN THREE ASH TENU + +1244C +CUNEIFORM NUMERIC SIGN FOUR ASH TENU + +1244D +CUNEIFORM NUMERIC SIGN FIVE ASH TENU + +1244E +CUNEIFORM NUMERIC SIGN SIX ASH TENU + +1244F +CUNEIFORM NUMERIC SIGN ONE BAN2 + +12450 +CUNEIFORM NUMERIC SIGN TWO BAN2 + +12451 +CUNEIFORM NUMERIC SIGN THREE BAN2 + +12452 +CUNEIFORM NUMERIC SIGN FOUR BAN2 + +12453 +CUNEIFORM NUMERIC SIGN FOUR BAN2 VARIANT FORM + +12454 +CUNEIFORM NUMERIC SIGN FIVE BAN2 + +12455 +CUNEIFORM NUMERIC SIGN FIVE BAN2 VARIANT FORM + +12456 +CUNEIFORM NUMERIC SIGN NIGIDAMIN + +12457 +CUNEIFORM NUMERIC SIGN NIGIDAESH + +12458 +CUNEIFORM NUMERIC SIGN ONE ESHE3 + +12459 +CUNEIFORM NUMERIC SIGN TWO ESHE3 + +1245A +CUNEIFORM NUMERIC SIGN ONE THIRD DISH + +1245B +CUNEIFORM NUMERIC SIGN TWO THIRDS DISH + +1245C +CUNEIFORM NUMERIC SIGN FIVE SIXTHS DISH + +1245D +CUNEIFORM NUMERIC SIGN ONE THIRD VARIANT FORM A + +1245E +CUNEIFORM NUMERIC SIGN TWO THIRDS VARIANT FORM A + +1245F +CUNEIFORM NUMERIC SIGN ONE EIGHTH ASH + +12460 +CUNEIFORM NUMERIC SIGN ONE QUARTER ASH + +12461 +CUNEIFORM NUMERIC SIGN OLD ASSYRIAN ONE SIXTH + +12462 +CUNEIFORM NUMERIC SIGN OLD ASSYRIAN ONE QUARTER + +12463 +CUNEIFORM NUMERIC SIGN ONE QUARTER GUR + +12464 +CUNEIFORM NUMERIC SIGN ONE HALF GUR + +12465 +CUNEIFORM NUMERIC SIGN ELAMITE ONE THIRD + +12466 +CUNEIFORM NUMERIC SIGN ELAMITE TWO THIRDS + +12467 +CUNEIFORM NUMERIC SIGN ELAMITE FORTY + +12468 +CUNEIFORM NUMERIC SIGN ELAMITE FIFTY + +12469 +CUNEIFORM NUMERIC SIGN FOUR U VARIANT FORM + +1246A +CUNEIFORM NUMERIC SIGN FIVE U VARIANT FORM + +1246B +CUNEIFORM NUMERIC SIGN SIX U VARIANT FORM + +1246C +CUNEIFORM NUMERIC SIGN SEVEN U VARIANT FORM + +1246D +CUNEIFORM NUMERIC SIGN EIGHT U VARIANT FORM + +1246E +CUNEIFORM NUMERIC SIGN NINE U VARIANT FORM + +12470 +CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER + +12471 +CUNEIFORM PUNCTUATION SIGN VERTICAL COLON + +12472 +CUNEIFORM PUNCTUATION SIGN DIAGONAL COLON + +12473 +CUNEIFORM PUNCTUATION SIGN DIAGONAL TRICOLON + +12474 +CUNEIFORM PUNCTUATION SIGN DIAGONAL QUADCOLON + +12480 +CUNEIFORM SIGN AB TIMES NUN TENU + +12481 +CUNEIFORM SIGN AB TIMES SHU2 + +12482 +CUNEIFORM SIGN AD TIMES ESH2 + +12483 +CUNEIFORM SIGN BAD TIMES DISH TENU + +12484 +CUNEIFORM SIGN BAHAR2 TIMES AB2 + +12485 +CUNEIFORM SIGN BAHAR2 TIMES NI + +12486 +CUNEIFORM SIGN BAHAR2 TIMES ZA + +12487 +CUNEIFORM SIGN BU OVER BU TIMES NA2 + +12488 +CUNEIFORM SIGN DA TIMES TAK4 + +12489 +CUNEIFORM SIGN DAG TIMES KUR + +1248A +CUNEIFORM SIGN DIM TIMES IGI + +1248B +CUNEIFORM SIGN DIM TIMES U U U + +1248C +CUNEIFORM SIGN DIM2 TIMES UD + +1248D +CUNEIFORM SIGN DUG TIMES ANSHE + +1248E +CUNEIFORM SIGN DUG TIMES ASH + +1248F +CUNEIFORM SIGN DUG TIMES ASH AT LEFT + +12490 +CUNEIFORM SIGN DUG TIMES DIN + +12491 +CUNEIFORM SIGN DUG TIMES DUN + +12492 +CUNEIFORM SIGN DUG TIMES ERIN2 + +12493 +CUNEIFORM SIGN DUG TIMES GA + +12494 +CUNEIFORM SIGN DUG TIMES GI + +12495 +CUNEIFORM SIGN DUG TIMES GIR2 GUNU + +12496 +CUNEIFORM SIGN DUG TIMES GISH + +12497 +CUNEIFORM SIGN DUG TIMES HA + +12498 +CUNEIFORM SIGN DUG TIMES HI + +12499 +CUNEIFORM SIGN DUG TIMES IGI GUNU + +1249A +CUNEIFORM SIGN DUG TIMES KASKAL + +1249B +CUNEIFORM SIGN DUG TIMES KUR + +1249C +CUNEIFORM SIGN DUG TIMES KUSHU2 + +1249D +CUNEIFORM SIGN DUG TIMES KUSHU2 PLUS KASKAL + +1249E +CUNEIFORM SIGN DUG TIMES LAK-020 + +1249F +CUNEIFORM SIGN DUG TIMES LAM + +124A0 +CUNEIFORM SIGN DUG TIMES LAM TIMES KUR + +124A1 +CUNEIFORM SIGN DUG TIMES LUH PLUS GISH + +124A2 +CUNEIFORM SIGN DUG TIMES MASH + +124A3 +CUNEIFORM SIGN DUG TIMES MES + +124A4 +CUNEIFORM SIGN DUG TIMES MI + +124A5 +CUNEIFORM SIGN DUG TIMES NI + +124A6 +CUNEIFORM SIGN DUG TIMES PI + +124A7 +CUNEIFORM SIGN DUG TIMES SHE + +124A8 +CUNEIFORM SIGN DUG TIMES SI GUNU + +124A9 +CUNEIFORM SIGN E2 TIMES KUR + +124AA +CUNEIFORM SIGN E2 TIMES PAP + +124AB +CUNEIFORM SIGN ERIN2 X + +124AC +CUNEIFORM SIGN ESH2 CROSSING ESH2 + +124AD +CUNEIFORM SIGN EZEN SHESHIG TIMES ASH + +124AE +CUNEIFORM SIGN EZEN SHESHIG TIMES HI + +124AF +CUNEIFORM SIGN EZEN SHESHIG TIMES IGI GUNU + +124B0 +CUNEIFORM SIGN EZEN SHESHIG TIMES LA + +124B1 +CUNEIFORM SIGN EZEN SHESHIG TIMES LAL + +124B2 +CUNEIFORM SIGN EZEN SHESHIG TIMES ME + +124B3 +CUNEIFORM SIGN EZEN SHESHIG TIMES MES + +124B4 +CUNEIFORM SIGN EZEN SHESHIG TIMES SU + +124B5 +CUNEIFORM SIGN EZEN TIMES SU + +124B6 +CUNEIFORM SIGN GA2 TIMES BAHAR2 + +124B7 +CUNEIFORM SIGN GA2 TIMES DIM GUNU + +124B8 +CUNEIFORM SIGN GA2 TIMES DUG TIMES IGI GUNU + +124B9 +CUNEIFORM SIGN GA2 TIMES DUG TIMES KASKAL + +124BA +CUNEIFORM SIGN GA2 TIMES EREN + +124BB +CUNEIFORM SIGN GA2 TIMES GA + +124BC +CUNEIFORM SIGN GA2 TIMES GAR PLUS DI + +124BD +CUNEIFORM SIGN GA2 TIMES GAR PLUS NE + +124BE +CUNEIFORM SIGN GA2 TIMES HA PLUS A + +124BF +CUNEIFORM SIGN GA2 TIMES KUSHU2 PLUS KASKAL + +124C0 +CUNEIFORM SIGN GA2 TIMES LAM + +124C1 +CUNEIFORM SIGN GA2 TIMES LAM TIMES KUR + +124C2 +CUNEIFORM SIGN GA2 TIMES LUH + +124C3 +CUNEIFORM SIGN GA2 TIMES MUSH + +124C4 +CUNEIFORM SIGN GA2 TIMES NE + +124C5 +CUNEIFORM SIGN GA2 TIMES NE PLUS E2 + +124C6 +CUNEIFORM SIGN GA2 TIMES NE PLUS GI + +124C7 +CUNEIFORM SIGN GA2 TIMES SHIM + +124C8 +CUNEIFORM SIGN GA2 TIMES ZIZ2 + +124C9 +CUNEIFORM SIGN GABA ROTATED NINETY DEGREES + +124CA +CUNEIFORM SIGN GESHTIN TIMES U + +124CB +CUNEIFORM SIGN GISH TIMES GISH CROSSING GISH + +124CC +CUNEIFORM SIGN GU2 TIMES IGI GUNU + +124CD +CUNEIFORM SIGN GUD PLUS GISH TIMES TAK4 + +124CE +CUNEIFORM SIGN HA TENU GUNU + +124CF +CUNEIFORM SIGN HI TIMES ASH OVER HI TIMES ASH + +124D0 +CUNEIFORM SIGN KA TIMES BU + +124D1 +CUNEIFORM SIGN KA TIMES KA + +124D2 +CUNEIFORM SIGN KA TIMES U U U + +124D3 +CUNEIFORM SIGN KA TIMES UR + +124D4 +CUNEIFORM SIGN LAGAB TIMES ZU OVER ZU + +124D5 +CUNEIFORM SIGN LAK-003 + +124D6 +CUNEIFORM SIGN LAK-021 + +124D7 +CUNEIFORM SIGN LAK-025 + +124D8 +CUNEIFORM SIGN LAK-030 + +124D9 +CUNEIFORM SIGN LAK-050 + +124DA +CUNEIFORM SIGN LAK-051 + +124DB +CUNEIFORM SIGN LAK-062 + +124DC +CUNEIFORM SIGN LAK-079 OVER LAK-079 GUNU + +124DD +CUNEIFORM SIGN LAK-080 + +124DE +CUNEIFORM SIGN LAK-081 OVER LAK-081 + +124DF +CUNEIFORM SIGN LAK-092 + +124E0 +CUNEIFORM SIGN LAK-130 + +124E1 +CUNEIFORM SIGN LAK-142 + +124E2 +CUNEIFORM SIGN LAK-210 + +124E3 +CUNEIFORM SIGN LAK-219 + +124E4 +CUNEIFORM SIGN LAK-220 + +124E5 +CUNEIFORM SIGN LAK-225 + +124E6 +CUNEIFORM SIGN LAK-228 + +124E7 +CUNEIFORM SIGN LAK-238 + +124E8 +CUNEIFORM SIGN LAK-265 + +124E9 +CUNEIFORM SIGN LAK-266 + +124EA +CUNEIFORM SIGN LAK-343 + +124EB +CUNEIFORM SIGN LAK-347 + +124EC +CUNEIFORM SIGN LAK-348 + +124ED +CUNEIFORM SIGN LAK-383 + +124EE +CUNEIFORM SIGN LAK-384 + +124EF +CUNEIFORM SIGN LAK-390 + +124F0 +CUNEIFORM SIGN LAK-441 + +124F1 +CUNEIFORM SIGN LAK-449 + +124F2 +CUNEIFORM SIGN LAK-449 TIMES GU + +124F3 +CUNEIFORM SIGN LAK-449 TIMES IGI + +124F4 +CUNEIFORM SIGN LAK-449 TIMES PAP PLUS LU3 + +124F5 +CUNEIFORM SIGN LAK-449 TIMES PAP PLUS PAP PLUS LU3 + +124F6 +CUNEIFORM SIGN LAK-449 TIMES U2 PLUS BA + +124F7 +CUNEIFORM SIGN LAK-450 + +124F8 +CUNEIFORM SIGN LAK-457 + +124F9 +CUNEIFORM SIGN LAK-470 + +124FA +CUNEIFORM SIGN LAK-483 + +124FB +CUNEIFORM SIGN LAK-490 + +124FC +CUNEIFORM SIGN LAK-492 + +124FD +CUNEIFORM SIGN LAK-493 + +124FE +CUNEIFORM SIGN LAK-495 + +124FF +CUNEIFORM SIGN LAK-550 + +12500 +CUNEIFORM SIGN LAK-608 + +12501 +CUNEIFORM SIGN LAK-617 + +12502 +CUNEIFORM SIGN LAK-617 TIMES ASH + +12503 +CUNEIFORM SIGN LAK-617 TIMES BAD + +12504 +CUNEIFORM SIGN LAK-617 TIMES DUN3 GUNU GUNU + +12505 +CUNEIFORM SIGN LAK-617 TIMES KU3 + +12506 +CUNEIFORM SIGN LAK-617 TIMES LA + +12507 +CUNEIFORM SIGN LAK-617 TIMES TAR + +12508 +CUNEIFORM SIGN LAK-617 TIMES TE + +12509 +CUNEIFORM SIGN LAK-617 TIMES U2 + +1250A +CUNEIFORM SIGN LAK-617 TIMES UD + +1250B +CUNEIFORM SIGN LAK-617 TIMES URUDA + +1250C +CUNEIFORM SIGN LAK-636 + +1250D +CUNEIFORM SIGN LAK-648 + +1250E +CUNEIFORM SIGN LAK-648 TIMES DUB + +1250F +CUNEIFORM SIGN LAK-648 TIMES GA + +12510 +CUNEIFORM SIGN LAK-648 TIMES IGI + +12511 +CUNEIFORM SIGN LAK-648 TIMES IGI GUNU + +12512 +CUNEIFORM SIGN LAK-648 TIMES NI + +12513 +CUNEIFORM SIGN LAK-648 TIMES PAP PLUS PAP PLUS LU3 + +12514 +CUNEIFORM SIGN LAK-648 TIMES SHESH PLUS KI + +12515 +CUNEIFORM SIGN LAK-648 TIMES UD + +12516 +CUNEIFORM SIGN LAK-648 TIMES URUDA + +12517 +CUNEIFORM SIGN LAK-724 + +12518 +CUNEIFORM SIGN LAK-749 + +12519 +CUNEIFORM SIGN LU2 GUNU TIMES ASH + +1251A +CUNEIFORM SIGN LU2 TIMES DISH + +1251B +CUNEIFORM SIGN LU2 TIMES HAL + +1251C +CUNEIFORM SIGN LU2 TIMES PAP + +1251D +CUNEIFORM SIGN LU2 TIMES PAP PLUS PAP PLUS LU3 + +1251E +CUNEIFORM SIGN LU2 TIMES TAK4 + +1251F +CUNEIFORM SIGN MI PLUS ZA7 + +12520 +CUNEIFORM SIGN MUSH OVER MUSH TIMES GA + +12521 +CUNEIFORM SIGN MUSH OVER MUSH TIMES KAK + +12522 +CUNEIFORM SIGN NINDA2 TIMES DIM GUNU + +12523 +CUNEIFORM SIGN NINDA2 TIMES GISH + +12524 +CUNEIFORM SIGN NINDA2 TIMES GUL + +12525 +CUNEIFORM SIGN NINDA2 TIMES HI + +12526 +CUNEIFORM SIGN NINDA2 TIMES KESH2 + +12527 +CUNEIFORM SIGN NINDA2 TIMES LAK-050 + +12528 +CUNEIFORM SIGN NINDA2 TIMES MASH + +12529 +CUNEIFORM SIGN NINDA2 TIMES PAP PLUS PAP + +1252A +CUNEIFORM SIGN NINDA2 TIMES U + +1252B +CUNEIFORM SIGN NINDA2 TIMES U PLUS U + +1252C +CUNEIFORM SIGN NINDA2 TIMES URUDA + +1252D +CUNEIFORM SIGN SAG GUNU TIMES HA + +1252E +CUNEIFORM SIGN SAG TIMES EN + +1252F +CUNEIFORM SIGN SAG TIMES SHE AT LEFT + +12530 +CUNEIFORM SIGN SAG TIMES TAK4 + +12531 +CUNEIFORM SIGN SHA6 TENU + +12532 +CUNEIFORM SIGN SHE OVER SHE + +12533 +CUNEIFORM SIGN SHE PLUS HUB2 + +12534 +CUNEIFORM SIGN SHE PLUS NAM2 + +12535 +CUNEIFORM SIGN SHE PLUS SAR + +12536 +CUNEIFORM SIGN SHU2 PLUS DUG TIMES NI + +12537 +CUNEIFORM SIGN SHU2 PLUS E2 TIMES AN + +12538 +CUNEIFORM SIGN SI TIMES TAK4 + +12539 +CUNEIFORM SIGN TAK4 PLUS SAG + +1253A +CUNEIFORM SIGN TUM TIMES GAN2 TENU + +1253B +CUNEIFORM SIGN TUM TIMES THREE DISH + +1253C +CUNEIFORM SIGN UR2 INVERTED + +1253D +CUNEIFORM SIGN UR2 TIMES UD + +1253E +CUNEIFORM SIGN URU TIMES DARA3 + +1253F +CUNEIFORM SIGN URU TIMES LAK-668 + +12540 +CUNEIFORM SIGN URU TIMES LU3 + +12541 +CUNEIFORM SIGN ZA7 + +12542 +CUNEIFORM SIGN ZU OVER ZU PLUS SAR + +12543 +CUNEIFORM SIGN ZU5 TIMES THREE DISH TENU + +12F90 +CYPRO-MINOAN SIGN CM001 + +12F91 +CYPRO-MINOAN SIGN CM002 + +12F92 +CYPRO-MINOAN SIGN CM004 + +12F93 +CYPRO-MINOAN SIGN CM005 + +12F94 +CYPRO-MINOAN SIGN CM006 + +12F95 +CYPRO-MINOAN SIGN CM007 + +12F96 +CYPRO-MINOAN SIGN CM008 + +12F97 +CYPRO-MINOAN SIGN CM009 + +12F98 +CYPRO-MINOAN SIGN CM010 + +12F99 +CYPRO-MINOAN SIGN CM011 + +12F9A +CYPRO-MINOAN SIGN CM012 + +12F9B +CYPRO-MINOAN SIGN CM012B + +12F9C +CYPRO-MINOAN SIGN CM013 + +12F9D +CYPRO-MINOAN SIGN CM015 + +12F9E +CYPRO-MINOAN SIGN CM017 + +12F9F +CYPRO-MINOAN SIGN CM019 + +12FA0 +CYPRO-MINOAN SIGN CM021 + +12FA1 +CYPRO-MINOAN SIGN CM023 + +12FA2 +CYPRO-MINOAN SIGN CM024 + +12FA3 +CYPRO-MINOAN SIGN CM025 + +12FA4 +CYPRO-MINOAN SIGN CM026 + +12FA5 +CYPRO-MINOAN SIGN CM027 + +12FA6 +CYPRO-MINOAN SIGN CM028 + +12FA7 +CYPRO-MINOAN SIGN CM029 + +12FA8 +CYPRO-MINOAN SIGN CM030 + +12FA9 +CYPRO-MINOAN SIGN CM033 + +12FAA +CYPRO-MINOAN SIGN CM034 + +12FAB +CYPRO-MINOAN SIGN CM035 + +12FAC +CYPRO-MINOAN SIGN CM036 + +12FAD +CYPRO-MINOAN SIGN CM037 + +12FAE +CYPRO-MINOAN SIGN CM038 + +12FAF +CYPRO-MINOAN SIGN CM039 + +12FB0 +CYPRO-MINOAN SIGN CM040 + +12FB1 +CYPRO-MINOAN SIGN CM041 + +12FB2 +CYPRO-MINOAN SIGN CM044 + +12FB3 +CYPRO-MINOAN SIGN CM046 + +12FB4 +CYPRO-MINOAN SIGN CM047 + +12FB5 +CYPRO-MINOAN SIGN CM049 + +12FB6 +CYPRO-MINOAN SIGN CM050 + +12FB7 +CYPRO-MINOAN SIGN CM051 + +12FB8 +CYPRO-MINOAN SIGN CM052 + +12FB9 +CYPRO-MINOAN SIGN CM053 + +12FBA +CYPRO-MINOAN SIGN CM054 + +12FBB +CYPRO-MINOAN SIGN CM055 + +12FBC +CYPRO-MINOAN SIGN CM056 + +12FBD +CYPRO-MINOAN SIGN CM058 + +12FBE +CYPRO-MINOAN SIGN CM059 + +12FBF +CYPRO-MINOAN SIGN CM060 + +12FC0 +CYPRO-MINOAN SIGN CM061 + +12FC1 +CYPRO-MINOAN SIGN CM062 + +12FC2 +CYPRO-MINOAN SIGN CM063 + +12FC3 +CYPRO-MINOAN SIGN CM064 + +12FC4 +CYPRO-MINOAN SIGN CM066 + +12FC5 +CYPRO-MINOAN SIGN CM067 + +12FC6 +CYPRO-MINOAN SIGN CM068 + +12FC7 +CYPRO-MINOAN SIGN CM069 + +12FC8 +CYPRO-MINOAN SIGN CM070 + +12FC9 +CYPRO-MINOAN SIGN CM071 + +12FCA +CYPRO-MINOAN SIGN CM072 + +12FCB +CYPRO-MINOAN SIGN CM073 + +12FCC +CYPRO-MINOAN SIGN CM074 + +12FCD +CYPRO-MINOAN SIGN CM075 + +12FCE +CYPRO-MINOAN SIGN CM075B + +12FCF +CYPRO-MINOAN SIGN CM076 + +12FD0 +CYPRO-MINOAN SIGN CM078 + +12FD1 +CYPRO-MINOAN SIGN CM079 + +12FD2 +CYPRO-MINOAN SIGN CM080 + +12FD3 +CYPRO-MINOAN SIGN CM081 + +12FD4 +CYPRO-MINOAN SIGN CM082 + +12FD5 +CYPRO-MINOAN SIGN CM083 + +12FD6 +CYPRO-MINOAN SIGN CM084 + +12FD7 +CYPRO-MINOAN SIGN CM085 + +12FD8 +CYPRO-MINOAN SIGN CM086 + +12FD9 +CYPRO-MINOAN SIGN CM087 + +12FDA +CYPRO-MINOAN SIGN CM088 + +12FDB +CYPRO-MINOAN SIGN CM089 + +12FDC +CYPRO-MINOAN SIGN CM090 + +12FDD +CYPRO-MINOAN SIGN CM091 + +12FDE +CYPRO-MINOAN SIGN CM092 + +12FDF +CYPRO-MINOAN SIGN CM094 + +12FE0 +CYPRO-MINOAN SIGN CM095 + +12FE1 +CYPRO-MINOAN SIGN CM096 + +12FE2 +CYPRO-MINOAN SIGN CM097 + +12FE3 +CYPRO-MINOAN SIGN CM098 + +12FE4 +CYPRO-MINOAN SIGN CM099 + +12FE5 +CYPRO-MINOAN SIGN CM100 + +12FE6 +CYPRO-MINOAN SIGN CM101 + +12FE7 +CYPRO-MINOAN SIGN CM102 + +12FE8 +CYPRO-MINOAN SIGN CM103 + +12FE9 +CYPRO-MINOAN SIGN CM104 + +12FEA +CYPRO-MINOAN SIGN CM105 + +12FEB +CYPRO-MINOAN SIGN CM107 + +12FEC +CYPRO-MINOAN SIGN CM108 + +12FED +CYPRO-MINOAN SIGN CM109 + +12FEE +CYPRO-MINOAN SIGN CM110 + +12FEF +CYPRO-MINOAN SIGN CM112 + +12FF0 +CYPRO-MINOAN SIGN CM114 + +12FF1 +CYPRO-MINOAN SIGN CM301 + +12FF2 +CYPRO-MINOAN SIGN CM302 + +13000 +EGYPTIAN HIEROGLYPH A001 + +13001 +EGYPTIAN HIEROGLYPH A002 + +13002 +EGYPTIAN HIEROGLYPH A003 + +13003 +EGYPTIAN HIEROGLYPH A004 + +13004 +EGYPTIAN HIEROGLYPH A005 + +13005 +EGYPTIAN HIEROGLYPH A005A + +13006 +EGYPTIAN HIEROGLYPH A006 + +13007 +EGYPTIAN HIEROGLYPH A006A + +13008 +EGYPTIAN HIEROGLYPH A006B + +13009 +EGYPTIAN HIEROGLYPH A007 + +1300A +EGYPTIAN HIEROGLYPH A008 + +1300B +EGYPTIAN HIEROGLYPH A009 + +1300C +EGYPTIAN HIEROGLYPH A010 + +1300D +EGYPTIAN HIEROGLYPH A011 + +1300E +EGYPTIAN HIEROGLYPH A012 + +1300F +EGYPTIAN HIEROGLYPH A013 + +13010 +EGYPTIAN HIEROGLYPH A014 + +13011 +EGYPTIAN HIEROGLYPH A014A + +13012 +EGYPTIAN HIEROGLYPH A015 + +13013 +EGYPTIAN HIEROGLYPH A016 + +13014 +EGYPTIAN HIEROGLYPH A017 + +13015 +EGYPTIAN HIEROGLYPH A017A + +13016 +EGYPTIAN HIEROGLYPH A018 + +13017 +EGYPTIAN HIEROGLYPH A019 + +13018 +EGYPTIAN HIEROGLYPH A020 + +13019 +EGYPTIAN HIEROGLYPH A021 + +1301A +EGYPTIAN HIEROGLYPH A022 + +1301B +EGYPTIAN HIEROGLYPH A023 + +1301C +EGYPTIAN HIEROGLYPH A024 + +1301D +EGYPTIAN HIEROGLYPH A025 + +1301E +EGYPTIAN HIEROGLYPH A026 + +1301F +EGYPTIAN HIEROGLYPH A027 + +13020 +EGYPTIAN HIEROGLYPH A028 + +13021 +EGYPTIAN HIEROGLYPH A029 + +13022 +EGYPTIAN HIEROGLYPH A030 + +13023 +EGYPTIAN HIEROGLYPH A031 + +13024 +EGYPTIAN HIEROGLYPH A032 + +13025 +EGYPTIAN HIEROGLYPH A032A + +13026 +EGYPTIAN HIEROGLYPH A033 + +13027 +EGYPTIAN HIEROGLYPH A034 + +13028 +EGYPTIAN HIEROGLYPH A035 + +13029 +EGYPTIAN HIEROGLYPH A036 + +1302A +EGYPTIAN HIEROGLYPH A037 + +1302B +EGYPTIAN HIEROGLYPH A038 + +1302C +EGYPTIAN HIEROGLYPH A039 + +1302D +EGYPTIAN HIEROGLYPH A040 + +1302E +EGYPTIAN HIEROGLYPH A040A + +1302F +EGYPTIAN HIEROGLYPH A041 + +13030 +EGYPTIAN HIEROGLYPH A042 + +13031 +EGYPTIAN HIEROGLYPH A042A + +13032 +EGYPTIAN HIEROGLYPH A043 + +13033 +EGYPTIAN HIEROGLYPH A043A + +13034 +EGYPTIAN HIEROGLYPH A044 + +13035 +EGYPTIAN HIEROGLYPH A045 + +13036 +EGYPTIAN HIEROGLYPH A045A + +13037 +EGYPTIAN HIEROGLYPH A046 + +13038 +EGYPTIAN HIEROGLYPH A047 + +13039 +EGYPTIAN HIEROGLYPH A048 + +1303A +EGYPTIAN HIEROGLYPH A049 + +1303B +EGYPTIAN HIEROGLYPH A050 + +1303C +EGYPTIAN HIEROGLYPH A051 + +1303D +EGYPTIAN HIEROGLYPH A052 + +1303E +EGYPTIAN HIEROGLYPH A053 + +1303F +EGYPTIAN HIEROGLYPH A054 + +13040 +EGYPTIAN HIEROGLYPH A055 + +13041 +EGYPTIAN HIEROGLYPH A056 + +13042 +EGYPTIAN HIEROGLYPH A057 + +13043 +EGYPTIAN HIEROGLYPH A058 + +13044 +EGYPTIAN HIEROGLYPH A059 + +13045 +EGYPTIAN HIEROGLYPH A060 + +13046 +EGYPTIAN HIEROGLYPH A061 + +13047 +EGYPTIAN HIEROGLYPH A062 + +13048 +EGYPTIAN HIEROGLYPH A063 + +13049 +EGYPTIAN HIEROGLYPH A064 + +1304A +EGYPTIAN HIEROGLYPH A065 + +1304B +EGYPTIAN HIEROGLYPH A066 + +1304C +EGYPTIAN HIEROGLYPH A067 + +1304D +EGYPTIAN HIEROGLYPH A068 + +1304E +EGYPTIAN HIEROGLYPH A069 + +1304F +EGYPTIAN HIEROGLYPH A070 + +13050 +EGYPTIAN HIEROGLYPH B001 + +13051 +EGYPTIAN HIEROGLYPH B002 + +13052 +EGYPTIAN HIEROGLYPH B003 + +13053 +EGYPTIAN HIEROGLYPH B004 + +13054 +EGYPTIAN HIEROGLYPH B005 + +13055 +EGYPTIAN HIEROGLYPH B005A + +13056 +EGYPTIAN HIEROGLYPH B006 + +13057 +EGYPTIAN HIEROGLYPH B007 + +13058 +EGYPTIAN HIEROGLYPH B008 + +13059 +EGYPTIAN HIEROGLYPH B009 + +1305A +EGYPTIAN HIEROGLYPH C001 + +1305B +EGYPTIAN HIEROGLYPH C002 + +1305C +EGYPTIAN HIEROGLYPH C002A + +1305D +EGYPTIAN HIEROGLYPH C002B + +1305E +EGYPTIAN HIEROGLYPH C002C + +1305F +EGYPTIAN HIEROGLYPH C003 + +13060 +EGYPTIAN HIEROGLYPH C004 + +13061 +EGYPTIAN HIEROGLYPH C005 + +13062 +EGYPTIAN HIEROGLYPH C006 + +13063 +EGYPTIAN HIEROGLYPH C007 + +13064 +EGYPTIAN HIEROGLYPH C008 + +13065 +EGYPTIAN HIEROGLYPH C009 + +13066 +EGYPTIAN HIEROGLYPH C010 + +13067 +EGYPTIAN HIEROGLYPH C010A + +13068 +EGYPTIAN HIEROGLYPH C011 + +13069 +EGYPTIAN HIEROGLYPH C012 + +1306A +EGYPTIAN HIEROGLYPH C013 + +1306B +EGYPTIAN HIEROGLYPH C014 + +1306C +EGYPTIAN HIEROGLYPH C015 + +1306D +EGYPTIAN HIEROGLYPH C016 + +1306E +EGYPTIAN HIEROGLYPH C017 + +1306F +EGYPTIAN HIEROGLYPH C018 + +13070 +EGYPTIAN HIEROGLYPH C019 + +13071 +EGYPTIAN HIEROGLYPH C020 + +13072 +EGYPTIAN HIEROGLYPH C021 + +13073 +EGYPTIAN HIEROGLYPH C022 + +13074 +EGYPTIAN HIEROGLYPH C023 + +13075 +EGYPTIAN HIEROGLYPH C024 + +13076 +EGYPTIAN HIEROGLYPH D001 + +13077 +EGYPTIAN HIEROGLYPH D002 + +13078 +EGYPTIAN HIEROGLYPH D003 + +13079 +EGYPTIAN HIEROGLYPH D004 + +1307A +EGYPTIAN HIEROGLYPH D005 + +1307B +EGYPTIAN HIEROGLYPH D006 + +1307C +EGYPTIAN HIEROGLYPH D007 + +1307D +EGYPTIAN HIEROGLYPH D008 + +1307E +EGYPTIAN HIEROGLYPH D008A + +1307F +EGYPTIAN HIEROGLYPH D009 + +13080 +EGYPTIAN HIEROGLYPH D010 + +13081 +EGYPTIAN HIEROGLYPH D011 + +13082 +EGYPTIAN HIEROGLYPH D012 + +13083 +EGYPTIAN HIEROGLYPH D013 + +13084 +EGYPTIAN HIEROGLYPH D014 + +13085 +EGYPTIAN HIEROGLYPH D015 + +13086 +EGYPTIAN HIEROGLYPH D016 + +13087 +EGYPTIAN HIEROGLYPH D017 + +13088 +EGYPTIAN HIEROGLYPH D018 + +13089 +EGYPTIAN HIEROGLYPH D019 + +1308A +EGYPTIAN HIEROGLYPH D020 + +1308B +EGYPTIAN HIEROGLYPH D021 + +1308C +EGYPTIAN HIEROGLYPH D022 + +1308D +EGYPTIAN HIEROGLYPH D023 + +1308E +EGYPTIAN HIEROGLYPH D024 + +1308F +EGYPTIAN HIEROGLYPH D025 + +13090 +EGYPTIAN HIEROGLYPH D026 + +13091 +EGYPTIAN HIEROGLYPH D027 + +13092 +EGYPTIAN HIEROGLYPH D027A + +13093 +EGYPTIAN HIEROGLYPH D028 + +13094 +EGYPTIAN HIEROGLYPH D029 + +13095 +EGYPTIAN HIEROGLYPH D030 + +13096 +EGYPTIAN HIEROGLYPH D031 + +13097 +EGYPTIAN HIEROGLYPH D031A + +13098 +EGYPTIAN HIEROGLYPH D032 + +13099 +EGYPTIAN HIEROGLYPH D033 + +1309A +EGYPTIAN HIEROGLYPH D034 + +1309B +EGYPTIAN HIEROGLYPH D034A + +1309C +EGYPTIAN HIEROGLYPH D035 + +1309D +EGYPTIAN HIEROGLYPH D036 + +1309E +EGYPTIAN HIEROGLYPH D037 + +1309F +EGYPTIAN HIEROGLYPH D038 + +130A0 +EGYPTIAN HIEROGLYPH D039 + +130A1 +EGYPTIAN HIEROGLYPH D040 + +130A2 +EGYPTIAN HIEROGLYPH D041 + +130A3 +EGYPTIAN HIEROGLYPH D042 + +130A4 +EGYPTIAN HIEROGLYPH D043 + +130A5 +EGYPTIAN HIEROGLYPH D044 + +130A6 +EGYPTIAN HIEROGLYPH D045 + +130A7 +EGYPTIAN HIEROGLYPH D046 + +130A8 +EGYPTIAN HIEROGLYPH D046A + +130A9 +EGYPTIAN HIEROGLYPH D047 + +130AA +EGYPTIAN HIEROGLYPH D048 + +130AB +EGYPTIAN HIEROGLYPH D048A + +130AC +EGYPTIAN HIEROGLYPH D049 + +130AD +EGYPTIAN HIEROGLYPH D050 + +130AE +EGYPTIAN HIEROGLYPH D050A + +130AF +EGYPTIAN HIEROGLYPH D050B + +130B0 +EGYPTIAN HIEROGLYPH D050C + +130B1 +EGYPTIAN HIEROGLYPH D050D + +130B2 +EGYPTIAN HIEROGLYPH D050E + +130B3 +EGYPTIAN HIEROGLYPH D050F + +130B4 +EGYPTIAN HIEROGLYPH D050G + +130B5 +EGYPTIAN HIEROGLYPH D050H + +130B6 +EGYPTIAN HIEROGLYPH D050I + +130B7 +EGYPTIAN HIEROGLYPH D051 + +130B8 +EGYPTIAN HIEROGLYPH D052 + +130B9 +EGYPTIAN HIEROGLYPH D052A + +130BA +EGYPTIAN HIEROGLYPH D053 + +130BB +EGYPTIAN HIEROGLYPH D054 + +130BC +EGYPTIAN HIEROGLYPH D054A + +130BD +EGYPTIAN HIEROGLYPH D055 + +130BE +EGYPTIAN HIEROGLYPH D056 + +130BF +EGYPTIAN HIEROGLYPH D057 + +130C0 +EGYPTIAN HIEROGLYPH D058 + +130C1 +EGYPTIAN HIEROGLYPH D059 + +130C2 +EGYPTIAN HIEROGLYPH D060 + +130C3 +EGYPTIAN HIEROGLYPH D061 + +130C4 +EGYPTIAN HIEROGLYPH D062 + +130C5 +EGYPTIAN HIEROGLYPH D063 + +130C6 +EGYPTIAN HIEROGLYPH D064 + +130C7 +EGYPTIAN HIEROGLYPH D065 + +130C8 +EGYPTIAN HIEROGLYPH D066 + +130C9 +EGYPTIAN HIEROGLYPH D067 + +130CA +EGYPTIAN HIEROGLYPH D067A + +130CB +EGYPTIAN HIEROGLYPH D067B + +130CC +EGYPTIAN HIEROGLYPH D067C + +130CD +EGYPTIAN HIEROGLYPH D067D + +130CE +EGYPTIAN HIEROGLYPH D067E + +130CF +EGYPTIAN HIEROGLYPH D067F + +130D0 +EGYPTIAN HIEROGLYPH D067G + +130D1 +EGYPTIAN HIEROGLYPH D067H + +130D2 +EGYPTIAN HIEROGLYPH E001 + +130D3 +EGYPTIAN HIEROGLYPH E002 + +130D4 +EGYPTIAN HIEROGLYPH E003 + +130D5 +EGYPTIAN HIEROGLYPH E004 + +130D6 +EGYPTIAN HIEROGLYPH E005 + +130D7 +EGYPTIAN HIEROGLYPH E006 + +130D8 +EGYPTIAN HIEROGLYPH E007 + +130D9 +EGYPTIAN HIEROGLYPH E008 + +130DA +EGYPTIAN HIEROGLYPH E008A + +130DB +EGYPTIAN HIEROGLYPH E009 + +130DC +EGYPTIAN HIEROGLYPH E009A + +130DD +EGYPTIAN HIEROGLYPH E010 + +130DE +EGYPTIAN HIEROGLYPH E011 + +130DF +EGYPTIAN HIEROGLYPH E012 + +130E0 +EGYPTIAN HIEROGLYPH E013 + +130E1 +EGYPTIAN HIEROGLYPH E014 + +130E2 +EGYPTIAN HIEROGLYPH E015 + +130E3 +EGYPTIAN HIEROGLYPH E016 + +130E4 +EGYPTIAN HIEROGLYPH E016A + +130E5 +EGYPTIAN HIEROGLYPH E017 + +130E6 +EGYPTIAN HIEROGLYPH E017A + +130E7 +EGYPTIAN HIEROGLYPH E018 + +130E8 +EGYPTIAN HIEROGLYPH E019 + +130E9 +EGYPTIAN HIEROGLYPH E020 + +130EA +EGYPTIAN HIEROGLYPH E020A + +130EB +EGYPTIAN HIEROGLYPH E021 + +130EC +EGYPTIAN HIEROGLYPH E022 + +130ED +EGYPTIAN HIEROGLYPH E023 + +130EE +EGYPTIAN HIEROGLYPH E024 + +130EF +EGYPTIAN HIEROGLYPH E025 + +130F0 +EGYPTIAN HIEROGLYPH E026 + +130F1 +EGYPTIAN HIEROGLYPH E027 + +130F2 +EGYPTIAN HIEROGLYPH E028 + +130F3 +EGYPTIAN HIEROGLYPH E028A + +130F4 +EGYPTIAN HIEROGLYPH E029 + +130F5 +EGYPTIAN HIEROGLYPH E030 + +130F6 +EGYPTIAN HIEROGLYPH E031 + +130F7 +EGYPTIAN HIEROGLYPH E032 + +130F8 +EGYPTIAN HIEROGLYPH E033 + +130F9 +EGYPTIAN HIEROGLYPH E034 + +130FA +EGYPTIAN HIEROGLYPH E034A + +130FB +EGYPTIAN HIEROGLYPH E036 + +130FC +EGYPTIAN HIEROGLYPH E037 + +130FD +EGYPTIAN HIEROGLYPH E038 + +130FE +EGYPTIAN HIEROGLYPH F001 + +130FF +EGYPTIAN HIEROGLYPH F001A + +13100 +EGYPTIAN HIEROGLYPH F002 + +13101 +EGYPTIAN HIEROGLYPH F003 + +13102 +EGYPTIAN HIEROGLYPH F004 + +13103 +EGYPTIAN HIEROGLYPH F005 + +13104 +EGYPTIAN HIEROGLYPH F006 + +13105 +EGYPTIAN HIEROGLYPH F007 + +13106 +EGYPTIAN HIEROGLYPH F008 + +13107 +EGYPTIAN HIEROGLYPH F009 + +13108 +EGYPTIAN HIEROGLYPH F010 + +13109 +EGYPTIAN HIEROGLYPH F011 + +1310A +EGYPTIAN HIEROGLYPH F012 + +1310B +EGYPTIAN HIEROGLYPH F013 + +1310C +EGYPTIAN HIEROGLYPH F013A + +1310D +EGYPTIAN HIEROGLYPH F014 + +1310E +EGYPTIAN HIEROGLYPH F015 + +1310F +EGYPTIAN HIEROGLYPH F016 + +13110 +EGYPTIAN HIEROGLYPH F017 + +13111 +EGYPTIAN HIEROGLYPH F018 + +13112 +EGYPTIAN HIEROGLYPH F019 + +13113 +EGYPTIAN HIEROGLYPH F020 + +13114 +EGYPTIAN HIEROGLYPH F021 + +13115 +EGYPTIAN HIEROGLYPH F021A + +13116 +EGYPTIAN HIEROGLYPH F022 + +13117 +EGYPTIAN HIEROGLYPH F023 + +13118 +EGYPTIAN HIEROGLYPH F024 + +13119 +EGYPTIAN HIEROGLYPH F025 + +1311A +EGYPTIAN HIEROGLYPH F026 + +1311B +EGYPTIAN HIEROGLYPH F027 + +1311C +EGYPTIAN HIEROGLYPH F028 + +1311D +EGYPTIAN HIEROGLYPH F029 + +1311E +EGYPTIAN HIEROGLYPH F030 + +1311F +EGYPTIAN HIEROGLYPH F031 + +13120 +EGYPTIAN HIEROGLYPH F031A + +13121 +EGYPTIAN HIEROGLYPH F032 + +13122 +EGYPTIAN HIEROGLYPH F033 + +13123 +EGYPTIAN HIEROGLYPH F034 + +13124 +EGYPTIAN HIEROGLYPH F035 + +13125 +EGYPTIAN HIEROGLYPH F036 + +13126 +EGYPTIAN HIEROGLYPH F037 + +13127 +EGYPTIAN HIEROGLYPH F037A + +13128 +EGYPTIAN HIEROGLYPH F038 + +13129 +EGYPTIAN HIEROGLYPH F038A + +1312A +EGYPTIAN HIEROGLYPH F039 + +1312B +EGYPTIAN HIEROGLYPH F040 + +1312C +EGYPTIAN HIEROGLYPH F041 + +1312D +EGYPTIAN HIEROGLYPH F042 + +1312E +EGYPTIAN HIEROGLYPH F043 + +1312F +EGYPTIAN HIEROGLYPH F044 + +13130 +EGYPTIAN HIEROGLYPH F045 + +13131 +EGYPTIAN HIEROGLYPH F045A + +13132 +EGYPTIAN HIEROGLYPH F046 + +13133 +EGYPTIAN HIEROGLYPH F046A + +13134 +EGYPTIAN HIEROGLYPH F047 + +13135 +EGYPTIAN HIEROGLYPH F047A + +13136 +EGYPTIAN HIEROGLYPH F048 + +13137 +EGYPTIAN HIEROGLYPH F049 + +13138 +EGYPTIAN HIEROGLYPH F050 + +13139 +EGYPTIAN HIEROGLYPH F051 + +1313A +EGYPTIAN HIEROGLYPH F051A + +1313B +EGYPTIAN HIEROGLYPH F051B + +1313C +EGYPTIAN HIEROGLYPH F051C + +1313D +EGYPTIAN HIEROGLYPH F052 + +1313E +EGYPTIAN HIEROGLYPH F053 + +1313F +EGYPTIAN HIEROGLYPH G001 + +13140 +EGYPTIAN HIEROGLYPH G002 + +13141 +EGYPTIAN HIEROGLYPH G003 + +13142 +EGYPTIAN HIEROGLYPH G004 + +13143 +EGYPTIAN HIEROGLYPH G005 + +13144 +EGYPTIAN HIEROGLYPH G006 + +13145 +EGYPTIAN HIEROGLYPH G006A + +13146 +EGYPTIAN HIEROGLYPH G007 + +13147 +EGYPTIAN HIEROGLYPH G007A + +13148 +EGYPTIAN HIEROGLYPH G007B + +13149 +EGYPTIAN HIEROGLYPH G008 + +1314A +EGYPTIAN HIEROGLYPH G009 + +1314B +EGYPTIAN HIEROGLYPH G010 + +1314C +EGYPTIAN HIEROGLYPH G011 + +1314D +EGYPTIAN HIEROGLYPH G011A + +1314E +EGYPTIAN HIEROGLYPH G012 + +1314F +EGYPTIAN HIEROGLYPH G013 + +13150 +EGYPTIAN HIEROGLYPH G014 + +13151 +EGYPTIAN HIEROGLYPH G015 + +13152 +EGYPTIAN HIEROGLYPH G016 + +13153 +EGYPTIAN HIEROGLYPH G017 + +13154 +EGYPTIAN HIEROGLYPH G018 + +13155 +EGYPTIAN HIEROGLYPH G019 + +13156 +EGYPTIAN HIEROGLYPH G020 + +13157 +EGYPTIAN HIEROGLYPH G020A + +13158 +EGYPTIAN HIEROGLYPH G021 + +13159 +EGYPTIAN HIEROGLYPH G022 + +1315A +EGYPTIAN HIEROGLYPH G023 + +1315B +EGYPTIAN HIEROGLYPH G024 + +1315C +EGYPTIAN HIEROGLYPH G025 + +1315D +EGYPTIAN HIEROGLYPH G026 + +1315E +EGYPTIAN HIEROGLYPH G026A + +1315F +EGYPTIAN HIEROGLYPH G027 + +13160 +EGYPTIAN HIEROGLYPH G028 + +13161 +EGYPTIAN HIEROGLYPH G029 + +13162 +EGYPTIAN HIEROGLYPH G030 + +13163 +EGYPTIAN HIEROGLYPH G031 + +13164 +EGYPTIAN HIEROGLYPH G032 + +13165 +EGYPTIAN HIEROGLYPH G033 + +13166 +EGYPTIAN HIEROGLYPH G034 + +13167 +EGYPTIAN HIEROGLYPH G035 + +13168 +EGYPTIAN HIEROGLYPH G036 + +13169 +EGYPTIAN HIEROGLYPH G036A + +1316A +EGYPTIAN HIEROGLYPH G037 + +1316B +EGYPTIAN HIEROGLYPH G037A + +1316C +EGYPTIAN HIEROGLYPH G038 + +1316D +EGYPTIAN HIEROGLYPH G039 + +1316E +EGYPTIAN HIEROGLYPH G040 + +1316F +EGYPTIAN HIEROGLYPH G041 + +13170 +EGYPTIAN HIEROGLYPH G042 + +13171 +EGYPTIAN HIEROGLYPH G043 + +13172 +EGYPTIAN HIEROGLYPH G043A + +13173 +EGYPTIAN HIEROGLYPH G044 + +13174 +EGYPTIAN HIEROGLYPH G045 + +13175 +EGYPTIAN HIEROGLYPH G045A + +13176 +EGYPTIAN HIEROGLYPH G046 + +13177 +EGYPTIAN HIEROGLYPH G047 + +13178 +EGYPTIAN HIEROGLYPH G048 + +13179 +EGYPTIAN HIEROGLYPH G049 + +1317A +EGYPTIAN HIEROGLYPH G050 + +1317B +EGYPTIAN HIEROGLYPH G051 + +1317C +EGYPTIAN HIEROGLYPH G052 + +1317D +EGYPTIAN HIEROGLYPH G053 + +1317E +EGYPTIAN HIEROGLYPH G054 + +1317F +EGYPTIAN HIEROGLYPH H001 + +13180 +EGYPTIAN HIEROGLYPH H002 + +13181 +EGYPTIAN HIEROGLYPH H003 + +13182 +EGYPTIAN HIEROGLYPH H004 + +13183 +EGYPTIAN HIEROGLYPH H005 + +13184 +EGYPTIAN HIEROGLYPH H006 + +13185 +EGYPTIAN HIEROGLYPH H006A + +13186 +EGYPTIAN HIEROGLYPH H007 + +13187 +EGYPTIAN HIEROGLYPH H008 + +13188 +EGYPTIAN HIEROGLYPH I001 + +13189 +EGYPTIAN HIEROGLYPH I002 + +1318A +EGYPTIAN HIEROGLYPH I003 + +1318B +EGYPTIAN HIEROGLYPH I004 + +1318C +EGYPTIAN HIEROGLYPH I005 + +1318D +EGYPTIAN HIEROGLYPH I005A + +1318E +EGYPTIAN HIEROGLYPH I006 + +1318F +EGYPTIAN HIEROGLYPH I007 + +13190 +EGYPTIAN HIEROGLYPH I008 + +13191 +EGYPTIAN HIEROGLYPH I009 + +13192 +EGYPTIAN HIEROGLYPH I009A + +13193 +EGYPTIAN HIEROGLYPH I010 + +13194 +EGYPTIAN HIEROGLYPH I010A + +13195 +EGYPTIAN HIEROGLYPH I011 + +13196 +EGYPTIAN HIEROGLYPH I011A + +13197 +EGYPTIAN HIEROGLYPH I012 + +13198 +EGYPTIAN HIEROGLYPH I013 + +13199 +EGYPTIAN HIEROGLYPH I014 + +1319A +EGYPTIAN HIEROGLYPH I015 + +1319B +EGYPTIAN HIEROGLYPH K001 + +1319C +EGYPTIAN HIEROGLYPH K002 + +1319D +EGYPTIAN HIEROGLYPH K003 + +1319E +EGYPTIAN HIEROGLYPH K004 + +1319F +EGYPTIAN HIEROGLYPH K005 + +131A0 +EGYPTIAN HIEROGLYPH K006 + +131A1 +EGYPTIAN HIEROGLYPH K007 + +131A2 +EGYPTIAN HIEROGLYPH K008 + +131A3 +EGYPTIAN HIEROGLYPH L001 + +131A4 +EGYPTIAN HIEROGLYPH L002 + +131A5 +EGYPTIAN HIEROGLYPH L002A + +131A6 +EGYPTIAN HIEROGLYPH L003 + +131A7 +EGYPTIAN HIEROGLYPH L004 + +131A8 +EGYPTIAN HIEROGLYPH L005 + +131A9 +EGYPTIAN HIEROGLYPH L006 + +131AA +EGYPTIAN HIEROGLYPH L006A + +131AB +EGYPTIAN HIEROGLYPH L007 + +131AC +EGYPTIAN HIEROGLYPH L008 + +131AD +EGYPTIAN HIEROGLYPH M001 + +131AE +EGYPTIAN HIEROGLYPH M001A + +131AF +EGYPTIAN HIEROGLYPH M001B + +131B0 +EGYPTIAN HIEROGLYPH M002 + +131B1 +EGYPTIAN HIEROGLYPH M003 + +131B2 +EGYPTIAN HIEROGLYPH M003A + +131B3 +EGYPTIAN HIEROGLYPH M004 + +131B4 +EGYPTIAN HIEROGLYPH M005 + +131B5 +EGYPTIAN HIEROGLYPH M006 + +131B6 +EGYPTIAN HIEROGLYPH M007 + +131B7 +EGYPTIAN HIEROGLYPH M008 + +131B8 +EGYPTIAN HIEROGLYPH M009 + +131B9 +EGYPTIAN HIEROGLYPH M010 + +131BA +EGYPTIAN HIEROGLYPH M010A + +131BB +EGYPTIAN HIEROGLYPH M011 + +131BC +EGYPTIAN HIEROGLYPH M012 + +131BD +EGYPTIAN HIEROGLYPH M012A + +131BE +EGYPTIAN HIEROGLYPH M012B + +131BF +EGYPTIAN HIEROGLYPH M012C + +131C0 +EGYPTIAN HIEROGLYPH M012D + +131C1 +EGYPTIAN HIEROGLYPH M012E + +131C2 +EGYPTIAN HIEROGLYPH M012F + +131C3 +EGYPTIAN HIEROGLYPH M012G + +131C4 +EGYPTIAN HIEROGLYPH M012H + +131C5 +EGYPTIAN HIEROGLYPH M013 + +131C6 +EGYPTIAN HIEROGLYPH M014 + +131C7 +EGYPTIAN HIEROGLYPH M015 + +131C8 +EGYPTIAN HIEROGLYPH M015A + +131C9 +EGYPTIAN HIEROGLYPH M016 + +131CA +EGYPTIAN HIEROGLYPH M016A + +131CB +EGYPTIAN HIEROGLYPH M017 + +131CC +EGYPTIAN HIEROGLYPH M017A + +131CD +EGYPTIAN HIEROGLYPH M018 + +131CE +EGYPTIAN HIEROGLYPH M019 + +131CF +EGYPTIAN HIEROGLYPH M020 + +131D0 +EGYPTIAN HIEROGLYPH M021 + +131D1 +EGYPTIAN HIEROGLYPH M022 + +131D2 +EGYPTIAN HIEROGLYPH M022A + +131D3 +EGYPTIAN HIEROGLYPH M023 + +131D4 +EGYPTIAN HIEROGLYPH M024 + +131D5 +EGYPTIAN HIEROGLYPH M024A + +131D6 +EGYPTIAN HIEROGLYPH M025 + +131D7 +EGYPTIAN HIEROGLYPH M026 + +131D8 +EGYPTIAN HIEROGLYPH M027 + +131D9 +EGYPTIAN HIEROGLYPH M028 + +131DA +EGYPTIAN HIEROGLYPH M028A + +131DB +EGYPTIAN HIEROGLYPH M029 + +131DC +EGYPTIAN HIEROGLYPH M030 + +131DD +EGYPTIAN HIEROGLYPH M031 + +131DE +EGYPTIAN HIEROGLYPH M031A + +131DF +EGYPTIAN HIEROGLYPH M032 + +131E0 +EGYPTIAN HIEROGLYPH M033 + +131E1 +EGYPTIAN HIEROGLYPH M033A + +131E2 +EGYPTIAN HIEROGLYPH M033B + +131E3 +EGYPTIAN HIEROGLYPH M034 + +131E4 +EGYPTIAN HIEROGLYPH M035 + +131E5 +EGYPTIAN HIEROGLYPH M036 + +131E6 +EGYPTIAN HIEROGLYPH M037 + +131E7 +EGYPTIAN HIEROGLYPH M038 + +131E8 +EGYPTIAN HIEROGLYPH M039 + +131E9 +EGYPTIAN HIEROGLYPH M040 + +131EA +EGYPTIAN HIEROGLYPH M040A + +131EB +EGYPTIAN HIEROGLYPH M041 + +131EC +EGYPTIAN HIEROGLYPH M042 + +131ED +EGYPTIAN HIEROGLYPH M043 + +131EE +EGYPTIAN HIEROGLYPH M044 + +131EF +EGYPTIAN HIEROGLYPH N001 + +131F0 +EGYPTIAN HIEROGLYPH N002 + +131F1 +EGYPTIAN HIEROGLYPH N003 + +131F2 +EGYPTIAN HIEROGLYPH N004 + +131F3 +EGYPTIAN HIEROGLYPH N005 + +131F4 +EGYPTIAN HIEROGLYPH N006 + +131F5 +EGYPTIAN HIEROGLYPH N007 + +131F6 +EGYPTIAN HIEROGLYPH N008 + +131F7 +EGYPTIAN HIEROGLYPH N009 + +131F8 +EGYPTIAN HIEROGLYPH N010 + +131F9 +EGYPTIAN HIEROGLYPH N011 + +131FA +EGYPTIAN HIEROGLYPH N012 + +131FB +EGYPTIAN HIEROGLYPH N013 + +131FC +EGYPTIAN HIEROGLYPH N014 + +131FD +EGYPTIAN HIEROGLYPH N015 + +131FE +EGYPTIAN HIEROGLYPH N016 + +131FF +EGYPTIAN HIEROGLYPH N017 + +13200 +EGYPTIAN HIEROGLYPH N018 + +13201 +EGYPTIAN HIEROGLYPH N018A + +13202 +EGYPTIAN HIEROGLYPH N018B + +13203 +EGYPTIAN HIEROGLYPH N019 + +13204 +EGYPTIAN HIEROGLYPH N020 + +13205 +EGYPTIAN HIEROGLYPH N021 + +13206 +EGYPTIAN HIEROGLYPH N022 + +13207 +EGYPTIAN HIEROGLYPH N023 + +13208 +EGYPTIAN HIEROGLYPH N024 + +13209 +EGYPTIAN HIEROGLYPH N025 + +1320A +EGYPTIAN HIEROGLYPH N025A + +1320B +EGYPTIAN HIEROGLYPH N026 + +1320C +EGYPTIAN HIEROGLYPH N027 + +1320D +EGYPTIAN HIEROGLYPH N028 + +1320E +EGYPTIAN HIEROGLYPH N029 + +1320F +EGYPTIAN HIEROGLYPH N030 + +13210 +EGYPTIAN HIEROGLYPH N031 + +13211 +EGYPTIAN HIEROGLYPH N032 + +13212 +EGYPTIAN HIEROGLYPH N033 + +13213 +EGYPTIAN HIEROGLYPH N033A + +13214 +EGYPTIAN HIEROGLYPH N034 + +13215 +EGYPTIAN HIEROGLYPH N034A + +13216 +EGYPTIAN HIEROGLYPH N035 + +13217 +EGYPTIAN HIEROGLYPH N035A + +13218 +EGYPTIAN HIEROGLYPH N036 + +13219 +EGYPTIAN HIEROGLYPH N037 + +1321A +EGYPTIAN HIEROGLYPH N037A + +1321B +EGYPTIAN HIEROGLYPH N038 + +1321C +EGYPTIAN HIEROGLYPH N039 + +1321D +EGYPTIAN HIEROGLYPH N040 + +1321E +EGYPTIAN HIEROGLYPH N041 + +1321F +EGYPTIAN HIEROGLYPH N042 + +13220 +EGYPTIAN HIEROGLYPH NL001 + +13221 +EGYPTIAN HIEROGLYPH NL002 + +13222 +EGYPTIAN HIEROGLYPH NL003 + +13223 +EGYPTIAN HIEROGLYPH NL004 + +13224 +EGYPTIAN HIEROGLYPH NL005 + +13225 +EGYPTIAN HIEROGLYPH NL005A + +13226 +EGYPTIAN HIEROGLYPH NL006 + +13227 +EGYPTIAN HIEROGLYPH NL007 + +13228 +EGYPTIAN HIEROGLYPH NL008 + +13229 +EGYPTIAN HIEROGLYPH NL009 + +1322A +EGYPTIAN HIEROGLYPH NL010 + +1322B +EGYPTIAN HIEROGLYPH NL011 + +1322C +EGYPTIAN HIEROGLYPH NL012 + +1322D +EGYPTIAN HIEROGLYPH NL013 + +1322E +EGYPTIAN HIEROGLYPH NL014 + +1322F +EGYPTIAN HIEROGLYPH NL015 + +13230 +EGYPTIAN HIEROGLYPH NL016 + +13231 +EGYPTIAN HIEROGLYPH NL017 + +13232 +EGYPTIAN HIEROGLYPH NL017A + +13233 +EGYPTIAN HIEROGLYPH NL018 + +13234 +EGYPTIAN HIEROGLYPH NL019 + +13235 +EGYPTIAN HIEROGLYPH NL020 + +13236 +EGYPTIAN HIEROGLYPH NU001 + +13237 +EGYPTIAN HIEROGLYPH NU002 + +13238 +EGYPTIAN HIEROGLYPH NU003 + +13239 +EGYPTIAN HIEROGLYPH NU004 + +1323A +EGYPTIAN HIEROGLYPH NU005 + +1323B +EGYPTIAN HIEROGLYPH NU006 + +1323C +EGYPTIAN HIEROGLYPH NU007 + +1323D +EGYPTIAN HIEROGLYPH NU008 + +1323E +EGYPTIAN HIEROGLYPH NU009 + +1323F +EGYPTIAN HIEROGLYPH NU010 + +13240 +EGYPTIAN HIEROGLYPH NU010A + +13241 +EGYPTIAN HIEROGLYPH NU011 + +13242 +EGYPTIAN HIEROGLYPH NU011A + +13243 +EGYPTIAN HIEROGLYPH NU012 + +13244 +EGYPTIAN HIEROGLYPH NU013 + +13245 +EGYPTIAN HIEROGLYPH NU014 + +13246 +EGYPTIAN HIEROGLYPH NU015 + +13247 +EGYPTIAN HIEROGLYPH NU016 + +13248 +EGYPTIAN HIEROGLYPH NU017 + +13249 +EGYPTIAN HIEROGLYPH NU018 + +1324A +EGYPTIAN HIEROGLYPH NU018A + +1324B +EGYPTIAN HIEROGLYPH NU019 + +1324C +EGYPTIAN HIEROGLYPH NU020 + +1324D +EGYPTIAN HIEROGLYPH NU021 + +1324E +EGYPTIAN HIEROGLYPH NU022 + +1324F +EGYPTIAN HIEROGLYPH NU022A + +13250 +EGYPTIAN HIEROGLYPH O001 + +13251 +EGYPTIAN HIEROGLYPH O001A + +13252 +EGYPTIAN HIEROGLYPH O002 + +13253 +EGYPTIAN HIEROGLYPH O003 + +13254 +EGYPTIAN HIEROGLYPH O004 + +13255 +EGYPTIAN HIEROGLYPH O005 + +13256 +EGYPTIAN HIEROGLYPH O005A + +13257 +EGYPTIAN HIEROGLYPH O006 + +13258 +EGYPTIAN HIEROGLYPH O006A + +13259 +EGYPTIAN HIEROGLYPH O006B + +1325A +EGYPTIAN HIEROGLYPH O006C + +1325B +EGYPTIAN HIEROGLYPH O006D + +1325C +EGYPTIAN HIEROGLYPH O006E + +1325D +EGYPTIAN HIEROGLYPH O006F + +1325E +EGYPTIAN HIEROGLYPH O007 + +1325F +EGYPTIAN HIEROGLYPH O008 + +13260 +EGYPTIAN HIEROGLYPH O009 + +13261 +EGYPTIAN HIEROGLYPH O010 + +13262 +EGYPTIAN HIEROGLYPH O010A + +13263 +EGYPTIAN HIEROGLYPH O010B + +13264 +EGYPTIAN HIEROGLYPH O010C + +13265 +EGYPTIAN HIEROGLYPH O011 + +13266 +EGYPTIAN HIEROGLYPH O012 + +13267 +EGYPTIAN HIEROGLYPH O013 + +13268 +EGYPTIAN HIEROGLYPH O014 + +13269 +EGYPTIAN HIEROGLYPH O015 + +1326A +EGYPTIAN HIEROGLYPH O016 + +1326B +EGYPTIAN HIEROGLYPH O017 + +1326C +EGYPTIAN HIEROGLYPH O018 + +1326D +EGYPTIAN HIEROGLYPH O019 + +1326E +EGYPTIAN HIEROGLYPH O019A + +1326F +EGYPTIAN HIEROGLYPH O020 + +13270 +EGYPTIAN HIEROGLYPH O020A + +13271 +EGYPTIAN HIEROGLYPH O021 + +13272 +EGYPTIAN HIEROGLYPH O022 + +13273 +EGYPTIAN HIEROGLYPH O023 + +13274 +EGYPTIAN HIEROGLYPH O024 + +13275 +EGYPTIAN HIEROGLYPH O024A + +13276 +EGYPTIAN HIEROGLYPH O025 + +13277 +EGYPTIAN HIEROGLYPH O025A + +13278 +EGYPTIAN HIEROGLYPH O026 + +13279 +EGYPTIAN HIEROGLYPH O027 + +1327A +EGYPTIAN HIEROGLYPH O028 + +1327B +EGYPTIAN HIEROGLYPH O029 + +1327C +EGYPTIAN HIEROGLYPH O029A + +1327D +EGYPTIAN HIEROGLYPH O030 + +1327E +EGYPTIAN HIEROGLYPH O030A + +1327F +EGYPTIAN HIEROGLYPH O031 + +13280 +EGYPTIAN HIEROGLYPH O032 + +13281 +EGYPTIAN HIEROGLYPH O033 + +13282 +EGYPTIAN HIEROGLYPH O033A + +13283 +EGYPTIAN HIEROGLYPH O034 + +13284 +EGYPTIAN HIEROGLYPH O035 + +13285 +EGYPTIAN HIEROGLYPH O036 + +13286 +EGYPTIAN HIEROGLYPH O036A + +13287 +EGYPTIAN HIEROGLYPH O036B + +13288 +EGYPTIAN HIEROGLYPH O036C + +13289 +EGYPTIAN HIEROGLYPH O036D + +1328A +EGYPTIAN HIEROGLYPH O037 + +1328B +EGYPTIAN HIEROGLYPH O038 + +1328C +EGYPTIAN HIEROGLYPH O039 + +1328D +EGYPTIAN HIEROGLYPH O040 + +1328E +EGYPTIAN HIEROGLYPH O041 + +1328F +EGYPTIAN HIEROGLYPH O042 + +13290 +EGYPTIAN HIEROGLYPH O043 + +13291 +EGYPTIAN HIEROGLYPH O044 + +13292 +EGYPTIAN HIEROGLYPH O045 + +13293 +EGYPTIAN HIEROGLYPH O046 + +13294 +EGYPTIAN HIEROGLYPH O047 + +13295 +EGYPTIAN HIEROGLYPH O048 + +13296 +EGYPTIAN HIEROGLYPH O049 + +13297 +EGYPTIAN HIEROGLYPH O050 + +13298 +EGYPTIAN HIEROGLYPH O050A + +13299 +EGYPTIAN HIEROGLYPH O050B + +1329A +EGYPTIAN HIEROGLYPH O051 + +1329B +EGYPTIAN HIEROGLYPH P001 + +1329C +EGYPTIAN HIEROGLYPH P001A + +1329D +EGYPTIAN HIEROGLYPH P002 + +1329E +EGYPTIAN HIEROGLYPH P003 + +1329F +EGYPTIAN HIEROGLYPH P003A + +132A0 +EGYPTIAN HIEROGLYPH P004 + +132A1 +EGYPTIAN HIEROGLYPH P005 + +132A2 +EGYPTIAN HIEROGLYPH P006 + +132A3 +EGYPTIAN HIEROGLYPH P007 + +132A4 +EGYPTIAN HIEROGLYPH P008 + +132A5 +EGYPTIAN HIEROGLYPH P009 + +132A6 +EGYPTIAN HIEROGLYPH P010 + +132A7 +EGYPTIAN HIEROGLYPH P011 + +132A8 +EGYPTIAN HIEROGLYPH Q001 + +132A9 +EGYPTIAN HIEROGLYPH Q002 + +132AA +EGYPTIAN HIEROGLYPH Q003 + +132AB +EGYPTIAN HIEROGLYPH Q004 + +132AC +EGYPTIAN HIEROGLYPH Q005 + +132AD +EGYPTIAN HIEROGLYPH Q006 + +132AE +EGYPTIAN HIEROGLYPH Q007 + +132AF +EGYPTIAN HIEROGLYPH R001 + +132B0 +EGYPTIAN HIEROGLYPH R002 + +132B1 +EGYPTIAN HIEROGLYPH R002A + +132B2 +EGYPTIAN HIEROGLYPH R003 + +132B3 +EGYPTIAN HIEROGLYPH R003A + +132B4 +EGYPTIAN HIEROGLYPH R003B + +132B5 +EGYPTIAN HIEROGLYPH R004 + +132B6 +EGYPTIAN HIEROGLYPH R005 + +132B7 +EGYPTIAN HIEROGLYPH R006 + +132B8 +EGYPTIAN HIEROGLYPH R007 + +132B9 +EGYPTIAN HIEROGLYPH R008 + +132BA +EGYPTIAN HIEROGLYPH R009 + +132BB +EGYPTIAN HIEROGLYPH R010 + +132BC +EGYPTIAN HIEROGLYPH R010A + +132BD +EGYPTIAN HIEROGLYPH R011 + +132BE +EGYPTIAN HIEROGLYPH R012 + +132BF +EGYPTIAN HIEROGLYPH R013 + +132C0 +EGYPTIAN HIEROGLYPH R014 + +132C1 +EGYPTIAN HIEROGLYPH R015 + +132C2 +EGYPTIAN HIEROGLYPH R016 + +132C3 +EGYPTIAN HIEROGLYPH R016A + +132C4 +EGYPTIAN HIEROGLYPH R017 + +132C5 +EGYPTIAN HIEROGLYPH R018 + +132C6 +EGYPTIAN HIEROGLYPH R019 + +132C7 +EGYPTIAN HIEROGLYPH R020 + +132C8 +EGYPTIAN HIEROGLYPH R021 + +132C9 +EGYPTIAN HIEROGLYPH R022 + +132CA +EGYPTIAN HIEROGLYPH R023 + +132CB +EGYPTIAN HIEROGLYPH R024 + +132CC +EGYPTIAN HIEROGLYPH R025 + +132CD +EGYPTIAN HIEROGLYPH R026 + +132CE +EGYPTIAN HIEROGLYPH R027 + +132CF +EGYPTIAN HIEROGLYPH R028 + +132D0 +EGYPTIAN HIEROGLYPH R029 + +132D1 +EGYPTIAN HIEROGLYPH S001 + +132D2 +EGYPTIAN HIEROGLYPH S002 + +132D3 +EGYPTIAN HIEROGLYPH S002A + +132D4 +EGYPTIAN HIEROGLYPH S003 + +132D5 +EGYPTIAN HIEROGLYPH S004 + +132D6 +EGYPTIAN HIEROGLYPH S005 + +132D7 +EGYPTIAN HIEROGLYPH S006 + +132D8 +EGYPTIAN HIEROGLYPH S006A + +132D9 +EGYPTIAN HIEROGLYPH S007 + +132DA +EGYPTIAN HIEROGLYPH S008 + +132DB +EGYPTIAN HIEROGLYPH S009 + +132DC +EGYPTIAN HIEROGLYPH S010 + +132DD +EGYPTIAN HIEROGLYPH S011 + +132DE +EGYPTIAN HIEROGLYPH S012 + +132DF +EGYPTIAN HIEROGLYPH S013 + +132E0 +EGYPTIAN HIEROGLYPH S014 + +132E1 +EGYPTIAN HIEROGLYPH S014A + +132E2 +EGYPTIAN HIEROGLYPH S014B + +132E3 +EGYPTIAN HIEROGLYPH S015 + +132E4 +EGYPTIAN HIEROGLYPH S016 + +132E5 +EGYPTIAN HIEROGLYPH S017 + +132E6 +EGYPTIAN HIEROGLYPH S017A + +132E7 +EGYPTIAN HIEROGLYPH S018 + +132E8 +EGYPTIAN HIEROGLYPH S019 + +132E9 +EGYPTIAN HIEROGLYPH S020 + +132EA +EGYPTIAN HIEROGLYPH S021 + +132EB +EGYPTIAN HIEROGLYPH S022 + +132EC +EGYPTIAN HIEROGLYPH S023 + +132ED +EGYPTIAN HIEROGLYPH S024 + +132EE +EGYPTIAN HIEROGLYPH S025 + +132EF +EGYPTIAN HIEROGLYPH S026 + +132F0 +EGYPTIAN HIEROGLYPH S026A + +132F1 +EGYPTIAN HIEROGLYPH S026B + +132F2 +EGYPTIAN HIEROGLYPH S027 + +132F3 +EGYPTIAN HIEROGLYPH S028 + +132F4 +EGYPTIAN HIEROGLYPH S029 + +132F5 +EGYPTIAN HIEROGLYPH S030 + +132F6 +EGYPTIAN HIEROGLYPH S031 + +132F7 +EGYPTIAN HIEROGLYPH S032 + +132F8 +EGYPTIAN HIEROGLYPH S033 + +132F9 +EGYPTIAN HIEROGLYPH S034 + +132FA +EGYPTIAN HIEROGLYPH S035 + +132FB +EGYPTIAN HIEROGLYPH S035A + +132FC +EGYPTIAN HIEROGLYPH S036 + +132FD +EGYPTIAN HIEROGLYPH S037 + +132FE +EGYPTIAN HIEROGLYPH S038 + +132FF +EGYPTIAN HIEROGLYPH S039 + +13300 +EGYPTIAN HIEROGLYPH S040 + +13301 +EGYPTIAN HIEROGLYPH S041 + +13302 +EGYPTIAN HIEROGLYPH S042 + +13303 +EGYPTIAN HIEROGLYPH S043 + +13304 +EGYPTIAN HIEROGLYPH S044 + +13305 +EGYPTIAN HIEROGLYPH S045 + +13306 +EGYPTIAN HIEROGLYPH S046 + +13307 +EGYPTIAN HIEROGLYPH T001 + +13308 +EGYPTIAN HIEROGLYPH T002 + +13309 +EGYPTIAN HIEROGLYPH T003 + +1330A +EGYPTIAN HIEROGLYPH T003A + +1330B +EGYPTIAN HIEROGLYPH T004 + +1330C +EGYPTIAN HIEROGLYPH T005 + +1330D +EGYPTIAN HIEROGLYPH T006 + +1330E +EGYPTIAN HIEROGLYPH T007 + +1330F +EGYPTIAN HIEROGLYPH T007A + +13310 +EGYPTIAN HIEROGLYPH T008 + +13311 +EGYPTIAN HIEROGLYPH T008A + +13312 +EGYPTIAN HIEROGLYPH T009 + +13313 +EGYPTIAN HIEROGLYPH T009A + +13314 +EGYPTIAN HIEROGLYPH T010 + +13315 +EGYPTIAN HIEROGLYPH T011 + +13316 +EGYPTIAN HIEROGLYPH T011A + +13317 +EGYPTIAN HIEROGLYPH T012 + +13318 +EGYPTIAN HIEROGLYPH T013 + +13319 +EGYPTIAN HIEROGLYPH T014 + +1331A +EGYPTIAN HIEROGLYPH T015 + +1331B +EGYPTIAN HIEROGLYPH T016 + +1331C +EGYPTIAN HIEROGLYPH T016A + +1331D +EGYPTIAN HIEROGLYPH T017 + +1331E +EGYPTIAN HIEROGLYPH T018 + +1331F +EGYPTIAN HIEROGLYPH T019 + +13320 +EGYPTIAN HIEROGLYPH T020 + +13321 +EGYPTIAN HIEROGLYPH T021 + +13322 +EGYPTIAN HIEROGLYPH T022 + +13323 +EGYPTIAN HIEROGLYPH T023 + +13324 +EGYPTIAN HIEROGLYPH T024 + +13325 +EGYPTIAN HIEROGLYPH T025 + +13326 +EGYPTIAN HIEROGLYPH T026 + +13327 +EGYPTIAN HIEROGLYPH T027 + +13328 +EGYPTIAN HIEROGLYPH T028 + +13329 +EGYPTIAN HIEROGLYPH T029 + +1332A +EGYPTIAN HIEROGLYPH T030 + +1332B +EGYPTIAN HIEROGLYPH T031 + +1332C +EGYPTIAN HIEROGLYPH T032 + +1332D +EGYPTIAN HIEROGLYPH T032A + +1332E +EGYPTIAN HIEROGLYPH T033 + +1332F +EGYPTIAN HIEROGLYPH T033A + +13330 +EGYPTIAN HIEROGLYPH T034 + +13331 +EGYPTIAN HIEROGLYPH T035 + +13332 +EGYPTIAN HIEROGLYPH T036 + +13333 +EGYPTIAN HIEROGLYPH U001 + +13334 +EGYPTIAN HIEROGLYPH U002 + +13335 +EGYPTIAN HIEROGLYPH U003 + +13336 +EGYPTIAN HIEROGLYPH U004 + +13337 +EGYPTIAN HIEROGLYPH U005 + +13338 +EGYPTIAN HIEROGLYPH U006 + +13339 +EGYPTIAN HIEROGLYPH U006A + +1333A +EGYPTIAN HIEROGLYPH U006B + +1333B +EGYPTIAN HIEROGLYPH U007 + +1333C +EGYPTIAN HIEROGLYPH U008 + +1333D +EGYPTIAN HIEROGLYPH U009 + +1333E +EGYPTIAN HIEROGLYPH U010 + +1333F +EGYPTIAN HIEROGLYPH U011 + +13340 +EGYPTIAN HIEROGLYPH U012 + +13341 +EGYPTIAN HIEROGLYPH U013 + +13342 +EGYPTIAN HIEROGLYPH U014 + +13343 +EGYPTIAN HIEROGLYPH U015 + +13344 +EGYPTIAN HIEROGLYPH U016 + +13345 +EGYPTIAN HIEROGLYPH U017 + +13346 +EGYPTIAN HIEROGLYPH U018 + +13347 +EGYPTIAN HIEROGLYPH U019 + +13348 +EGYPTIAN HIEROGLYPH U020 + +13349 +EGYPTIAN HIEROGLYPH U021 + +1334A +EGYPTIAN HIEROGLYPH U022 + +1334B +EGYPTIAN HIEROGLYPH U023 + +1334C +EGYPTIAN HIEROGLYPH U023A + +1334D +EGYPTIAN HIEROGLYPH U024 + +1334E +EGYPTIAN HIEROGLYPH U025 + +1334F +EGYPTIAN HIEROGLYPH U026 + +13350 +EGYPTIAN HIEROGLYPH U027 + +13351 +EGYPTIAN HIEROGLYPH U028 + +13352 +EGYPTIAN HIEROGLYPH U029 + +13353 +EGYPTIAN HIEROGLYPH U029A + +13354 +EGYPTIAN HIEROGLYPH U030 + +13355 +EGYPTIAN HIEROGLYPH U031 + +13356 +EGYPTIAN HIEROGLYPH U032 + +13357 +EGYPTIAN HIEROGLYPH U032A + +13358 +EGYPTIAN HIEROGLYPH U033 + +13359 +EGYPTIAN HIEROGLYPH U034 + +1335A +EGYPTIAN HIEROGLYPH U035 + +1335B +EGYPTIAN HIEROGLYPH U036 + +1335C +EGYPTIAN HIEROGLYPH U037 + +1335D +EGYPTIAN HIEROGLYPH U038 + +1335E +EGYPTIAN HIEROGLYPH U039 + +1335F +EGYPTIAN HIEROGLYPH U040 + +13360 +EGYPTIAN HIEROGLYPH U041 + +13361 +EGYPTIAN HIEROGLYPH U042 + +13362 +EGYPTIAN HIEROGLYPH V001 + +13363 +EGYPTIAN HIEROGLYPH V001A + +13364 +EGYPTIAN HIEROGLYPH V001B + +13365 +EGYPTIAN HIEROGLYPH V001C + +13366 +EGYPTIAN HIEROGLYPH V001D + +13367 +EGYPTIAN HIEROGLYPH V001E + +13368 +EGYPTIAN HIEROGLYPH V001F + +13369 +EGYPTIAN HIEROGLYPH V001G + +1336A +EGYPTIAN HIEROGLYPH V001H + +1336B +EGYPTIAN HIEROGLYPH V001I + +1336C +EGYPTIAN HIEROGLYPH V002 + +1336D +EGYPTIAN HIEROGLYPH V002A + +1336E +EGYPTIAN HIEROGLYPH V003 + +1336F +EGYPTIAN HIEROGLYPH V004 + +13370 +EGYPTIAN HIEROGLYPH V005 + +13371 +EGYPTIAN HIEROGLYPH V006 + +13372 +EGYPTIAN HIEROGLYPH V007 + +13373 +EGYPTIAN HIEROGLYPH V007A + +13374 +EGYPTIAN HIEROGLYPH V007B + +13375 +EGYPTIAN HIEROGLYPH V008 + +13376 +EGYPTIAN HIEROGLYPH V009 + +13377 +EGYPTIAN HIEROGLYPH V010 + +13378 +EGYPTIAN HIEROGLYPH V011 + +13379 +EGYPTIAN HIEROGLYPH V011A + +1337A +EGYPTIAN HIEROGLYPH V011B + +1337B +EGYPTIAN HIEROGLYPH V011C + +1337C +EGYPTIAN HIEROGLYPH V012 + +1337D +EGYPTIAN HIEROGLYPH V012A + +1337E +EGYPTIAN HIEROGLYPH V012B + +1337F +EGYPTIAN HIEROGLYPH V013 + +13380 +EGYPTIAN HIEROGLYPH V014 + +13381 +EGYPTIAN HIEROGLYPH V015 + +13382 +EGYPTIAN HIEROGLYPH V016 + +13383 +EGYPTIAN HIEROGLYPH V017 + +13384 +EGYPTIAN HIEROGLYPH V018 + +13385 +EGYPTIAN HIEROGLYPH V019 + +13386 +EGYPTIAN HIEROGLYPH V020 + +13387 +EGYPTIAN HIEROGLYPH V020A + +13388 +EGYPTIAN HIEROGLYPH V020B + +13389 +EGYPTIAN HIEROGLYPH V020C + +1338A +EGYPTIAN HIEROGLYPH V020D + +1338B +EGYPTIAN HIEROGLYPH V020E + +1338C +EGYPTIAN HIEROGLYPH V020F + +1338D +EGYPTIAN HIEROGLYPH V020G + +1338E +EGYPTIAN HIEROGLYPH V020H + +1338F +EGYPTIAN HIEROGLYPH V020I + +13390 +EGYPTIAN HIEROGLYPH V020J + +13391 +EGYPTIAN HIEROGLYPH V020K + +13392 +EGYPTIAN HIEROGLYPH V020L + +13393 +EGYPTIAN HIEROGLYPH V021 + +13394 +EGYPTIAN HIEROGLYPH V022 + +13395 +EGYPTIAN HIEROGLYPH V023 + +13396 +EGYPTIAN HIEROGLYPH V023A + +13397 +EGYPTIAN HIEROGLYPH V024 + +13398 +EGYPTIAN HIEROGLYPH V025 + +13399 +EGYPTIAN HIEROGLYPH V026 + +1339A +EGYPTIAN HIEROGLYPH V027 + +1339B +EGYPTIAN HIEROGLYPH V028 + +1339C +EGYPTIAN HIEROGLYPH V028A + +1339D +EGYPTIAN HIEROGLYPH V029 + +1339E +EGYPTIAN HIEROGLYPH V029A + +1339F +EGYPTIAN HIEROGLYPH V030 + +133A0 +EGYPTIAN HIEROGLYPH V030A + +133A1 +EGYPTIAN HIEROGLYPH V031 + +133A2 +EGYPTIAN HIEROGLYPH V031A + +133A3 +EGYPTIAN HIEROGLYPH V032 + +133A4 +EGYPTIAN HIEROGLYPH V033 + +133A5 +EGYPTIAN HIEROGLYPH V033A + +133A6 +EGYPTIAN HIEROGLYPH V034 + +133A7 +EGYPTIAN HIEROGLYPH V035 + +133A8 +EGYPTIAN HIEROGLYPH V036 + +133A9 +EGYPTIAN HIEROGLYPH V037 + +133AA +EGYPTIAN HIEROGLYPH V037A + +133AB +EGYPTIAN HIEROGLYPH V038 + +133AC +EGYPTIAN HIEROGLYPH V039 + +133AD +EGYPTIAN HIEROGLYPH V040 + +133AE +EGYPTIAN HIEROGLYPH V040A + +133AF +EGYPTIAN HIEROGLYPH W001 + +133B0 +EGYPTIAN HIEROGLYPH W002 + +133B1 +EGYPTIAN HIEROGLYPH W003 + +133B2 +EGYPTIAN HIEROGLYPH W003A + +133B3 +EGYPTIAN HIEROGLYPH W004 + +133B4 +EGYPTIAN HIEROGLYPH W005 + +133B5 +EGYPTIAN HIEROGLYPH W006 + +133B6 +EGYPTIAN HIEROGLYPH W007 + +133B7 +EGYPTIAN HIEROGLYPH W008 + +133B8 +EGYPTIAN HIEROGLYPH W009 + +133B9 +EGYPTIAN HIEROGLYPH W009A + +133BA +EGYPTIAN HIEROGLYPH W010 + +133BB +EGYPTIAN HIEROGLYPH W010A + +133BC +EGYPTIAN HIEROGLYPH W011 + +133BD +EGYPTIAN HIEROGLYPH W012 + +133BE +EGYPTIAN HIEROGLYPH W013 + +133BF +EGYPTIAN HIEROGLYPH W014 + +133C0 +EGYPTIAN HIEROGLYPH W014A + +133C1 +EGYPTIAN HIEROGLYPH W015 + +133C2 +EGYPTIAN HIEROGLYPH W016 + +133C3 +EGYPTIAN HIEROGLYPH W017 + +133C4 +EGYPTIAN HIEROGLYPH W017A + +133C5 +EGYPTIAN HIEROGLYPH W018 + +133C6 +EGYPTIAN HIEROGLYPH W018A + +133C7 +EGYPTIAN HIEROGLYPH W019 + +133C8 +EGYPTIAN HIEROGLYPH W020 + +133C9 +EGYPTIAN HIEROGLYPH W021 + +133CA +EGYPTIAN HIEROGLYPH W022 + +133CB +EGYPTIAN HIEROGLYPH W023 + +133CC +EGYPTIAN HIEROGLYPH W024 + +133CD +EGYPTIAN HIEROGLYPH W024A + +133CE +EGYPTIAN HIEROGLYPH W025 + +133CF +EGYPTIAN HIEROGLYPH X001 + +133D0 +EGYPTIAN HIEROGLYPH X002 + +133D1 +EGYPTIAN HIEROGLYPH X003 + +133D2 +EGYPTIAN HIEROGLYPH X004 + +133D3 +EGYPTIAN HIEROGLYPH X004A + +133D4 +EGYPTIAN HIEROGLYPH X004B + +133D5 +EGYPTIAN HIEROGLYPH X005 + +133D6 +EGYPTIAN HIEROGLYPH X006 + +133D7 +EGYPTIAN HIEROGLYPH X006A + +133D8 +EGYPTIAN HIEROGLYPH X007 + +133D9 +EGYPTIAN HIEROGLYPH X008 + +133DA +EGYPTIAN HIEROGLYPH X008A + +133DB +EGYPTIAN HIEROGLYPH Y001 + +133DC +EGYPTIAN HIEROGLYPH Y001A + +133DD +EGYPTIAN HIEROGLYPH Y002 + +133DE +EGYPTIAN HIEROGLYPH Y003 + +133DF +EGYPTIAN HIEROGLYPH Y004 + +133E0 +EGYPTIAN HIEROGLYPH Y005 + +133E1 +EGYPTIAN HIEROGLYPH Y006 + +133E2 +EGYPTIAN HIEROGLYPH Y007 + +133E3 +EGYPTIAN HIEROGLYPH Y008 + +133E4 +EGYPTIAN HIEROGLYPH Z001 + +133E5 +EGYPTIAN HIEROGLYPH Z002 + +133E6 +EGYPTIAN HIEROGLYPH Z002A + +133E7 +EGYPTIAN HIEROGLYPH Z002B + +133E8 +EGYPTIAN HIEROGLYPH Z002C + +133E9 +EGYPTIAN HIEROGLYPH Z002D + +133EA +EGYPTIAN HIEROGLYPH Z003 + +133EB +EGYPTIAN HIEROGLYPH Z003A + +133EC +EGYPTIAN HIEROGLYPH Z003B + +133ED +EGYPTIAN HIEROGLYPH Z004 + +133EE +EGYPTIAN HIEROGLYPH Z004A + +133EF +EGYPTIAN HIEROGLYPH Z005 + +133F0 +EGYPTIAN HIEROGLYPH Z005A + +133F1 +EGYPTIAN HIEROGLYPH Z006 + +133F2 +EGYPTIAN HIEROGLYPH Z007 + +133F3 +EGYPTIAN HIEROGLYPH Z008 + +133F4 +EGYPTIAN HIEROGLYPH Z009 + +133F5 +EGYPTIAN HIEROGLYPH Z010 + +133F6 +EGYPTIAN HIEROGLYPH Z011 + +133F7 +EGYPTIAN HIEROGLYPH Z012 + +133F8 +EGYPTIAN HIEROGLYPH Z013 + +133F9 +EGYPTIAN HIEROGLYPH Z014 + +133FA +EGYPTIAN HIEROGLYPH Z015 + +133FB +EGYPTIAN HIEROGLYPH Z015A + +133FC +EGYPTIAN HIEROGLYPH Z015B + +133FD +EGYPTIAN HIEROGLYPH Z015C + +133FE +EGYPTIAN HIEROGLYPH Z015D + +133FF +EGYPTIAN HIEROGLYPH Z015E + +13400 +EGYPTIAN HIEROGLYPH Z015F + +13401 +EGYPTIAN HIEROGLYPH Z015G + +13402 +EGYPTIAN HIEROGLYPH Z015H + +13403 +EGYPTIAN HIEROGLYPH Z015I + +13404 +EGYPTIAN HIEROGLYPH Z016 + +13405 +EGYPTIAN HIEROGLYPH Z016A + +13406 +EGYPTIAN HIEROGLYPH Z016B + +13407 +EGYPTIAN HIEROGLYPH Z016C + +13408 +EGYPTIAN HIEROGLYPH Z016D + +13409 +EGYPTIAN HIEROGLYPH Z016E + +1340A +EGYPTIAN HIEROGLYPH Z016F + +1340B +EGYPTIAN HIEROGLYPH Z016G + +1340C +EGYPTIAN HIEROGLYPH Z016H + +1340D +EGYPTIAN HIEROGLYPH AA001 + +1340E +EGYPTIAN HIEROGLYPH AA002 + +1340F +EGYPTIAN HIEROGLYPH AA003 + +13410 +EGYPTIAN HIEROGLYPH AA004 + +13411 +EGYPTIAN HIEROGLYPH AA005 + +13412 +EGYPTIAN HIEROGLYPH AA006 + +13413 +EGYPTIAN HIEROGLYPH AA007 + +13414 +EGYPTIAN HIEROGLYPH AA007A + +13415 +EGYPTIAN HIEROGLYPH AA007B + +13416 +EGYPTIAN HIEROGLYPH AA008 + +13417 +EGYPTIAN HIEROGLYPH AA009 + +13418 +EGYPTIAN HIEROGLYPH AA010 + +13419 +EGYPTIAN HIEROGLYPH AA011 + +1341A +EGYPTIAN HIEROGLYPH AA012 + +1341B +EGYPTIAN HIEROGLYPH AA013 + +1341C +EGYPTIAN HIEROGLYPH AA014 + +1341D +EGYPTIAN HIEROGLYPH AA015 + +1341E +EGYPTIAN HIEROGLYPH AA016 + +1341F +EGYPTIAN HIEROGLYPH AA017 + +13420 +EGYPTIAN HIEROGLYPH AA018 + +13421 +EGYPTIAN HIEROGLYPH AA019 + +13422 +EGYPTIAN HIEROGLYPH AA020 + +13423 +EGYPTIAN HIEROGLYPH AA021 + +13424 +EGYPTIAN HIEROGLYPH AA022 + +13425 +EGYPTIAN HIEROGLYPH AA023 + +13426 +EGYPTIAN HIEROGLYPH AA024 + +13427 +EGYPTIAN HIEROGLYPH AA025 + +13428 +EGYPTIAN HIEROGLYPH AA026 + +13429 +EGYPTIAN HIEROGLYPH AA027 + +1342A +EGYPTIAN HIEROGLYPH AA028 + +1342B +EGYPTIAN HIEROGLYPH AA029 + +1342C +EGYPTIAN HIEROGLYPH AA030 + +1342D +EGYPTIAN HIEROGLYPH AA031 + +1342E +EGYPTIAN HIEROGLYPH AA032 + +1342F +EGYPTIAN HIEROGLYPH V011D + +13430 +EGYPTIAN HIEROGLYPH VERTICAL JOINER + +13431 +EGYPTIAN HIEROGLYPH HORIZONTAL JOINER + +13432 +EGYPTIAN HIEROGLYPH INSERT AT TOP START + +13433 +EGYPTIAN HIEROGLYPH INSERT AT BOTTOM START + +13434 +EGYPTIAN HIEROGLYPH INSERT AT TOP END + +13435 +EGYPTIAN HIEROGLYPH INSERT AT BOTTOM END + +13436 +EGYPTIAN HIEROGLYPH OVERLAY MIDDLE + +13437 +EGYPTIAN HIEROGLYPH BEGIN SEGMENT + +13438 +EGYPTIAN HIEROGLYPH END SEGMENT + +13439 +EGYPTIAN HIEROGLYPH INSERT AT MIDDLE + +1343A +EGYPTIAN HIEROGLYPH INSERT AT TOP + +1343B +EGYPTIAN HIEROGLYPH INSERT AT BOTTOM + +1343C +EGYPTIAN HIEROGLYPH BEGIN ENCLOSURE + +1343D +EGYPTIAN HIEROGLYPH END ENCLOSURE + +1343E +EGYPTIAN HIEROGLYPH BEGIN WALLED ENCLOSURE + +1343F +EGYPTIAN HIEROGLYPH END WALLED ENCLOSURE + +13440 +EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY + +13441 +EGYPTIAN HIEROGLYPH FULL BLANK + +13442 +EGYPTIAN HIEROGLYPH HALF BLANK + +13443 +EGYPTIAN HIEROGLYPH LOST SIGN + +13444 +EGYPTIAN HIEROGLYPH HALF LOST SIGN + +13445 +EGYPTIAN HIEROGLYPH TALL LOST SIGN + +13446 +EGYPTIAN HIEROGLYPH WIDE LOST SIGN + +13447 +EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START + +13448 +EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT BOTTOM START + +13449 +EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT START + +1344A +EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP END + +1344B +EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP + +1344C +EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT BOTTOM START AND TOP END + +1344D +EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT START AND TOP + +1344E +EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT BOTTOM END + +1344F +EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START AND BOTTOM END + +13450 +EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT BOTTOM + +13451 +EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT START AND BOTTOM + +13452 +EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT END + +13453 +EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP AND END + +13454 +EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT BOTTOM AND END + +13455 +EGYPTIAN HIEROGLYPH MODIFIER DAMAGED + +14400 +ANATOLIAN HIEROGLYPH A001 + +14401 +ANATOLIAN HIEROGLYPH A002 + +14402 +ANATOLIAN HIEROGLYPH A003 + +14403 +ANATOLIAN HIEROGLYPH A004 + +14404 +ANATOLIAN HIEROGLYPH A005 + +14405 +ANATOLIAN HIEROGLYPH A006 + +14406 +ANATOLIAN HIEROGLYPH A007 + +14407 +ANATOLIAN HIEROGLYPH A008 + +14408 +ANATOLIAN HIEROGLYPH A009 + +14409 +ANATOLIAN HIEROGLYPH A010 + +1440A +ANATOLIAN HIEROGLYPH A010A + +1440B +ANATOLIAN HIEROGLYPH A011 + +1440C +ANATOLIAN HIEROGLYPH A012 + +1440D +ANATOLIAN HIEROGLYPH A013 + +1440E +ANATOLIAN HIEROGLYPH A014 + +1440F +ANATOLIAN HIEROGLYPH A015 + +14410 +ANATOLIAN HIEROGLYPH A016 + +14411 +ANATOLIAN HIEROGLYPH A017 + +14412 +ANATOLIAN HIEROGLYPH A018 + +14413 +ANATOLIAN HIEROGLYPH A019 + +14414 +ANATOLIAN HIEROGLYPH A020 + +14415 +ANATOLIAN HIEROGLYPH A021 + +14416 +ANATOLIAN HIEROGLYPH A022 + +14417 +ANATOLIAN HIEROGLYPH A023 + +14418 +ANATOLIAN HIEROGLYPH A024 + +14419 +ANATOLIAN HIEROGLYPH A025 + +1441A +ANATOLIAN HIEROGLYPH A026 + +1441B +ANATOLIAN HIEROGLYPH A026A + +1441C +ANATOLIAN HIEROGLYPH A027 + +1441D +ANATOLIAN HIEROGLYPH A028 + +1441E +ANATOLIAN HIEROGLYPH A029 + +1441F +ANATOLIAN HIEROGLYPH A030 + +14420 +ANATOLIAN HIEROGLYPH A031 + +14421 +ANATOLIAN HIEROGLYPH A032 + +14422 +ANATOLIAN HIEROGLYPH A033 + +14423 +ANATOLIAN HIEROGLYPH A034 + +14424 +ANATOLIAN HIEROGLYPH A035 + +14425 +ANATOLIAN HIEROGLYPH A036 + +14426 +ANATOLIAN HIEROGLYPH A037 + +14427 +ANATOLIAN HIEROGLYPH A038 + +14428 +ANATOLIAN HIEROGLYPH A039 + +14429 +ANATOLIAN HIEROGLYPH A039A + +1442A +ANATOLIAN HIEROGLYPH A040 + +1442B +ANATOLIAN HIEROGLYPH A041 + +1442C +ANATOLIAN HIEROGLYPH A041A + +1442D +ANATOLIAN HIEROGLYPH A042 + +1442E +ANATOLIAN HIEROGLYPH A043 + +1442F +ANATOLIAN HIEROGLYPH A044 + +14430 +ANATOLIAN HIEROGLYPH A045 + +14431 +ANATOLIAN HIEROGLYPH A045A + +14432 +ANATOLIAN HIEROGLYPH A046 + +14433 +ANATOLIAN HIEROGLYPH A046A + +14434 +ANATOLIAN HIEROGLYPH A046B + +14435 +ANATOLIAN HIEROGLYPH A047 + +14436 +ANATOLIAN HIEROGLYPH A048 + +14437 +ANATOLIAN HIEROGLYPH A049 + +14438 +ANATOLIAN HIEROGLYPH A050 + +14439 +ANATOLIAN HIEROGLYPH A051 + +1443A +ANATOLIAN HIEROGLYPH A052 + +1443B +ANATOLIAN HIEROGLYPH A053 + +1443C +ANATOLIAN HIEROGLYPH A054 + +1443D +ANATOLIAN HIEROGLYPH A055 + +1443E +ANATOLIAN HIEROGLYPH A056 + +1443F +ANATOLIAN HIEROGLYPH A057 + +14440 +ANATOLIAN HIEROGLYPH A058 + +14441 +ANATOLIAN HIEROGLYPH A059 + +14442 +ANATOLIAN HIEROGLYPH A060 + +14443 +ANATOLIAN HIEROGLYPH A061 + +14444 +ANATOLIAN HIEROGLYPH A062 + +14445 +ANATOLIAN HIEROGLYPH A063 + +14446 +ANATOLIAN HIEROGLYPH A064 + +14447 +ANATOLIAN HIEROGLYPH A065 + +14448 +ANATOLIAN HIEROGLYPH A066 + +14449 +ANATOLIAN HIEROGLYPH A066A + +1444A +ANATOLIAN HIEROGLYPH A066B + +1444B +ANATOLIAN HIEROGLYPH A066C + +1444C +ANATOLIAN HIEROGLYPH A067 + +1444D +ANATOLIAN HIEROGLYPH A068 + +1444E +ANATOLIAN HIEROGLYPH A069 + +1444F +ANATOLIAN HIEROGLYPH A070 + +14450 +ANATOLIAN HIEROGLYPH A071 + +14451 +ANATOLIAN HIEROGLYPH A072 + +14452 +ANATOLIAN HIEROGLYPH A073 + +14453 +ANATOLIAN HIEROGLYPH A074 + +14454 +ANATOLIAN HIEROGLYPH A075 + +14455 +ANATOLIAN HIEROGLYPH A076 + +14456 +ANATOLIAN HIEROGLYPH A077 + +14457 +ANATOLIAN HIEROGLYPH A078 + +14458 +ANATOLIAN HIEROGLYPH A079 + +14459 +ANATOLIAN HIEROGLYPH A080 + +1445A +ANATOLIAN HIEROGLYPH A081 + +1445B +ANATOLIAN HIEROGLYPH A082 + +1445C +ANATOLIAN HIEROGLYPH A083 + +1445D +ANATOLIAN HIEROGLYPH A084 + +1445E +ANATOLIAN HIEROGLYPH A085 + +1445F +ANATOLIAN HIEROGLYPH A086 + +14460 +ANATOLIAN HIEROGLYPH A087 + +14461 +ANATOLIAN HIEROGLYPH A088 + +14462 +ANATOLIAN HIEROGLYPH A089 + +14463 +ANATOLIAN HIEROGLYPH A090 + +14464 +ANATOLIAN HIEROGLYPH A091 + +14465 +ANATOLIAN HIEROGLYPH A092 + +14466 +ANATOLIAN HIEROGLYPH A093 + +14467 +ANATOLIAN HIEROGLYPH A094 + +14468 +ANATOLIAN HIEROGLYPH A095 + +14469 +ANATOLIAN HIEROGLYPH A096 + +1446A +ANATOLIAN HIEROGLYPH A097 + +1446B +ANATOLIAN HIEROGLYPH A097A + +1446C +ANATOLIAN HIEROGLYPH A098 + +1446D +ANATOLIAN HIEROGLYPH A098A + +1446E +ANATOLIAN HIEROGLYPH A099 + +1446F +ANATOLIAN HIEROGLYPH A100 + +14470 +ANATOLIAN HIEROGLYPH A100A + +14471 +ANATOLIAN HIEROGLYPH A101 + +14472 +ANATOLIAN HIEROGLYPH A101A + +14473 +ANATOLIAN HIEROGLYPH A102 + +14474 +ANATOLIAN HIEROGLYPH A102A + +14475 +ANATOLIAN HIEROGLYPH A103 + +14476 +ANATOLIAN HIEROGLYPH A104 + +14477 +ANATOLIAN HIEROGLYPH A104A + +14478 +ANATOLIAN HIEROGLYPH A104B + +14479 +ANATOLIAN HIEROGLYPH A104C + +1447A +ANATOLIAN HIEROGLYPH A105 + +1447B +ANATOLIAN HIEROGLYPH A105A + +1447C +ANATOLIAN HIEROGLYPH A105B + +1447D +ANATOLIAN HIEROGLYPH A106 + +1447E +ANATOLIAN HIEROGLYPH A107 + +1447F +ANATOLIAN HIEROGLYPH A107A + +14480 +ANATOLIAN HIEROGLYPH A107B + +14481 +ANATOLIAN HIEROGLYPH A107C + +14482 +ANATOLIAN HIEROGLYPH A108 + +14483 +ANATOLIAN HIEROGLYPH A109 + +14484 +ANATOLIAN HIEROGLYPH A110 + +14485 +ANATOLIAN HIEROGLYPH A110A + +14486 +ANATOLIAN HIEROGLYPH A110B + +14487 +ANATOLIAN HIEROGLYPH A111 + +14488 +ANATOLIAN HIEROGLYPH A112 + +14489 +ANATOLIAN HIEROGLYPH A113 + +1448A +ANATOLIAN HIEROGLYPH A114 + +1448B +ANATOLIAN HIEROGLYPH A115 + +1448C +ANATOLIAN HIEROGLYPH A115A + +1448D +ANATOLIAN HIEROGLYPH A116 + +1448E +ANATOLIAN HIEROGLYPH A117 + +1448F +ANATOLIAN HIEROGLYPH A118 + +14490 +ANATOLIAN HIEROGLYPH A119 + +14491 +ANATOLIAN HIEROGLYPH A120 + +14492 +ANATOLIAN HIEROGLYPH A121 + +14493 +ANATOLIAN HIEROGLYPH A122 + +14494 +ANATOLIAN HIEROGLYPH A123 + +14495 +ANATOLIAN HIEROGLYPH A124 + +14496 +ANATOLIAN HIEROGLYPH A125 + +14497 +ANATOLIAN HIEROGLYPH A125A + +14498 +ANATOLIAN HIEROGLYPH A126 + +14499 +ANATOLIAN HIEROGLYPH A127 + +1449A +ANATOLIAN HIEROGLYPH A128 + +1449B +ANATOLIAN HIEROGLYPH A129 + +1449C +ANATOLIAN HIEROGLYPH A130 + +1449D +ANATOLIAN HIEROGLYPH A131 + +1449E +ANATOLIAN HIEROGLYPH A132 + +1449F +ANATOLIAN HIEROGLYPH A133 + +144A0 +ANATOLIAN HIEROGLYPH A134 + +144A1 +ANATOLIAN HIEROGLYPH A135 + +144A2 +ANATOLIAN HIEROGLYPH A135A + +144A3 +ANATOLIAN HIEROGLYPH A136 + +144A4 +ANATOLIAN HIEROGLYPH A137 + +144A5 +ANATOLIAN HIEROGLYPH A138 + +144A6 +ANATOLIAN HIEROGLYPH A139 + +144A7 +ANATOLIAN HIEROGLYPH A140 + +144A8 +ANATOLIAN HIEROGLYPH A141 + +144A9 +ANATOLIAN HIEROGLYPH A142 + +144AA +ANATOLIAN HIEROGLYPH A143 + +144AB +ANATOLIAN HIEROGLYPH A144 + +144AC +ANATOLIAN HIEROGLYPH A145 + +144AD +ANATOLIAN HIEROGLYPH A146 + +144AE +ANATOLIAN HIEROGLYPH A147 + +144AF +ANATOLIAN HIEROGLYPH A148 + +144B0 +ANATOLIAN HIEROGLYPH A149 + +144B1 +ANATOLIAN HIEROGLYPH A150 + +144B2 +ANATOLIAN HIEROGLYPH A151 + +144B3 +ANATOLIAN HIEROGLYPH A152 + +144B4 +ANATOLIAN HIEROGLYPH A153 + +144B5 +ANATOLIAN HIEROGLYPH A154 + +144B6 +ANATOLIAN HIEROGLYPH A155 + +144B7 +ANATOLIAN HIEROGLYPH A156 + +144B8 +ANATOLIAN HIEROGLYPH A157 + +144B9 +ANATOLIAN HIEROGLYPH A158 + +144BA +ANATOLIAN HIEROGLYPH A159 + +144BB +ANATOLIAN HIEROGLYPH A160 + +144BC +ANATOLIAN HIEROGLYPH A161 + +144BD +ANATOLIAN HIEROGLYPH A162 + +144BE +ANATOLIAN HIEROGLYPH A163 + +144BF +ANATOLIAN HIEROGLYPH A164 + +144C0 +ANATOLIAN HIEROGLYPH A165 + +144C1 +ANATOLIAN HIEROGLYPH A166 + +144C2 +ANATOLIAN HIEROGLYPH A167 + +144C3 +ANATOLIAN HIEROGLYPH A168 + +144C4 +ANATOLIAN HIEROGLYPH A169 + +144C5 +ANATOLIAN HIEROGLYPH A170 + +144C6 +ANATOLIAN HIEROGLYPH A171 + +144C7 +ANATOLIAN HIEROGLYPH A172 + +144C8 +ANATOLIAN HIEROGLYPH A173 + +144C9 +ANATOLIAN HIEROGLYPH A174 + +144CA +ANATOLIAN HIEROGLYPH A175 + +144CB +ANATOLIAN HIEROGLYPH A176 + +144CC +ANATOLIAN HIEROGLYPH A177 + +144CD +ANATOLIAN HIEROGLYPH A178 + +144CE +ANATOLIAN HIEROGLYPH A179 + +144CF +ANATOLIAN HIEROGLYPH A180 + +144D0 +ANATOLIAN HIEROGLYPH A181 + +144D1 +ANATOLIAN HIEROGLYPH A182 + +144D2 +ANATOLIAN HIEROGLYPH A183 + +144D3 +ANATOLIAN HIEROGLYPH A184 + +144D4 +ANATOLIAN HIEROGLYPH A185 + +144D5 +ANATOLIAN HIEROGLYPH A186 + +144D6 +ANATOLIAN HIEROGLYPH A187 + +144D7 +ANATOLIAN HIEROGLYPH A188 + +144D8 +ANATOLIAN HIEROGLYPH A189 + +144D9 +ANATOLIAN HIEROGLYPH A190 + +144DA +ANATOLIAN HIEROGLYPH A191 + +144DB +ANATOLIAN HIEROGLYPH A192 + +144DC +ANATOLIAN HIEROGLYPH A193 + +144DD +ANATOLIAN HIEROGLYPH A194 + +144DE +ANATOLIAN HIEROGLYPH A195 + +144DF +ANATOLIAN HIEROGLYPH A196 + +144E0 +ANATOLIAN HIEROGLYPH A197 + +144E1 +ANATOLIAN HIEROGLYPH A198 + +144E2 +ANATOLIAN HIEROGLYPH A199 + +144E3 +ANATOLIAN HIEROGLYPH A200 + +144E4 +ANATOLIAN HIEROGLYPH A201 + +144E5 +ANATOLIAN HIEROGLYPH A202 + +144E6 +ANATOLIAN HIEROGLYPH A202A + +144E7 +ANATOLIAN HIEROGLYPH A202B + +144E8 +ANATOLIAN HIEROGLYPH A203 + +144E9 +ANATOLIAN HIEROGLYPH A204 + +144EA +ANATOLIAN HIEROGLYPH A205 + +144EB +ANATOLIAN HIEROGLYPH A206 + +144EC +ANATOLIAN HIEROGLYPH A207 + +144ED +ANATOLIAN HIEROGLYPH A207A + +144EE +ANATOLIAN HIEROGLYPH A208 + +144EF +ANATOLIAN HIEROGLYPH A209 + +144F0 +ANATOLIAN HIEROGLYPH A209A + +144F1 +ANATOLIAN HIEROGLYPH A210 + +144F2 +ANATOLIAN HIEROGLYPH A211 + +144F3 +ANATOLIAN HIEROGLYPH A212 + +144F4 +ANATOLIAN HIEROGLYPH A213 + +144F5 +ANATOLIAN HIEROGLYPH A214 + +144F6 +ANATOLIAN HIEROGLYPH A215 + +144F7 +ANATOLIAN HIEROGLYPH A215A + +144F8 +ANATOLIAN HIEROGLYPH A216 + +144F9 +ANATOLIAN HIEROGLYPH A216A + +144FA +ANATOLIAN HIEROGLYPH A217 + +144FB +ANATOLIAN HIEROGLYPH A218 + +144FC +ANATOLIAN HIEROGLYPH A219 + +144FD +ANATOLIAN HIEROGLYPH A220 + +144FE +ANATOLIAN HIEROGLYPH A221 + +144FF +ANATOLIAN HIEROGLYPH A222 + +14500 +ANATOLIAN HIEROGLYPH A223 + +14501 +ANATOLIAN HIEROGLYPH A224 + +14502 +ANATOLIAN HIEROGLYPH A225 + +14503 +ANATOLIAN HIEROGLYPH A226 + +14504 +ANATOLIAN HIEROGLYPH A227 + +14505 +ANATOLIAN HIEROGLYPH A227A + +14506 +ANATOLIAN HIEROGLYPH A228 + +14507 +ANATOLIAN HIEROGLYPH A229 + +14508 +ANATOLIAN HIEROGLYPH A230 + +14509 +ANATOLIAN HIEROGLYPH A231 + +1450A +ANATOLIAN HIEROGLYPH A232 + +1450B +ANATOLIAN HIEROGLYPH A233 + +1450C +ANATOLIAN HIEROGLYPH A234 + +1450D +ANATOLIAN HIEROGLYPH A235 + +1450E +ANATOLIAN HIEROGLYPH A236 + +1450F +ANATOLIAN HIEROGLYPH A237 + +14510 +ANATOLIAN HIEROGLYPH A238 + +14511 +ANATOLIAN HIEROGLYPH A239 + +14512 +ANATOLIAN HIEROGLYPH A240 + +14513 +ANATOLIAN HIEROGLYPH A241 + +14514 +ANATOLIAN HIEROGLYPH A242 + +14515 +ANATOLIAN HIEROGLYPH A243 + +14516 +ANATOLIAN HIEROGLYPH A244 + +14517 +ANATOLIAN HIEROGLYPH A245 + +14518 +ANATOLIAN HIEROGLYPH A246 + +14519 +ANATOLIAN HIEROGLYPH A247 + +1451A +ANATOLIAN HIEROGLYPH A248 + +1451B +ANATOLIAN HIEROGLYPH A249 + +1451C +ANATOLIAN HIEROGLYPH A250 + +1451D +ANATOLIAN HIEROGLYPH A251 + +1451E +ANATOLIAN HIEROGLYPH A252 + +1451F +ANATOLIAN HIEROGLYPH A253 + +14520 +ANATOLIAN HIEROGLYPH A254 + +14521 +ANATOLIAN HIEROGLYPH A255 + +14522 +ANATOLIAN HIEROGLYPH A256 + +14523 +ANATOLIAN HIEROGLYPH A257 + +14524 +ANATOLIAN HIEROGLYPH A258 + +14525 +ANATOLIAN HIEROGLYPH A259 + +14526 +ANATOLIAN HIEROGLYPH A260 + +14527 +ANATOLIAN HIEROGLYPH A261 + +14528 +ANATOLIAN HIEROGLYPH A262 + +14529 +ANATOLIAN HIEROGLYPH A263 + +1452A +ANATOLIAN HIEROGLYPH A264 + +1452B +ANATOLIAN HIEROGLYPH A265 + +1452C +ANATOLIAN HIEROGLYPH A266 + +1452D +ANATOLIAN HIEROGLYPH A267 + +1452E +ANATOLIAN HIEROGLYPH A267A + +1452F +ANATOLIAN HIEROGLYPH A268 + +14530 +ANATOLIAN HIEROGLYPH A269 + +14531 +ANATOLIAN HIEROGLYPH A270 + +14532 +ANATOLIAN HIEROGLYPH A271 + +14533 +ANATOLIAN HIEROGLYPH A272 + +14534 +ANATOLIAN HIEROGLYPH A273 + +14535 +ANATOLIAN HIEROGLYPH A274 + +14536 +ANATOLIAN HIEROGLYPH A275 + +14537 +ANATOLIAN HIEROGLYPH A276 + +14538 +ANATOLIAN HIEROGLYPH A277 + +14539 +ANATOLIAN HIEROGLYPH A278 + +1453A +ANATOLIAN HIEROGLYPH A279 + +1453B +ANATOLIAN HIEROGLYPH A280 + +1453C +ANATOLIAN HIEROGLYPH A281 + +1453D +ANATOLIAN HIEROGLYPH A282 + +1453E +ANATOLIAN HIEROGLYPH A283 + +1453F +ANATOLIAN HIEROGLYPH A284 + +14540 +ANATOLIAN HIEROGLYPH A285 + +14541 +ANATOLIAN HIEROGLYPH A286 + +14542 +ANATOLIAN HIEROGLYPH A287 + +14543 +ANATOLIAN HIEROGLYPH A288 + +14544 +ANATOLIAN HIEROGLYPH A289 + +14545 +ANATOLIAN HIEROGLYPH A289A + +14546 +ANATOLIAN HIEROGLYPH A290 + +14547 +ANATOLIAN HIEROGLYPH A291 + +14548 +ANATOLIAN HIEROGLYPH A292 + +14549 +ANATOLIAN HIEROGLYPH A293 + +1454A +ANATOLIAN HIEROGLYPH A294 + +1454B +ANATOLIAN HIEROGLYPH A294A + +1454C +ANATOLIAN HIEROGLYPH A295 + +1454D +ANATOLIAN HIEROGLYPH A296 + +1454E +ANATOLIAN HIEROGLYPH A297 + +1454F +ANATOLIAN HIEROGLYPH A298 + +14550 +ANATOLIAN HIEROGLYPH A299 + +14551 +ANATOLIAN HIEROGLYPH A299A + +14552 +ANATOLIAN HIEROGLYPH A300 + +14553 +ANATOLIAN HIEROGLYPH A301 + +14554 +ANATOLIAN HIEROGLYPH A302 + +14555 +ANATOLIAN HIEROGLYPH A303 + +14556 +ANATOLIAN HIEROGLYPH A304 + +14557 +ANATOLIAN HIEROGLYPH A305 + +14558 +ANATOLIAN HIEROGLYPH A306 + +14559 +ANATOLIAN HIEROGLYPH A307 + +1455A +ANATOLIAN HIEROGLYPH A308 + +1455B +ANATOLIAN HIEROGLYPH A309 + +1455C +ANATOLIAN HIEROGLYPH A309A + +1455D +ANATOLIAN HIEROGLYPH A310 + +1455E +ANATOLIAN HIEROGLYPH A311 + +1455F +ANATOLIAN HIEROGLYPH A312 + +14560 +ANATOLIAN HIEROGLYPH A313 + +14561 +ANATOLIAN HIEROGLYPH A314 + +14562 +ANATOLIAN HIEROGLYPH A315 + +14563 +ANATOLIAN HIEROGLYPH A316 + +14564 +ANATOLIAN HIEROGLYPH A317 + +14565 +ANATOLIAN HIEROGLYPH A318 + +14566 +ANATOLIAN HIEROGLYPH A319 + +14567 +ANATOLIAN HIEROGLYPH A320 + +14568 +ANATOLIAN HIEROGLYPH A321 + +14569 +ANATOLIAN HIEROGLYPH A322 + +1456A +ANATOLIAN HIEROGLYPH A323 + +1456B +ANATOLIAN HIEROGLYPH A324 + +1456C +ANATOLIAN HIEROGLYPH A325 + +1456D +ANATOLIAN HIEROGLYPH A326 + +1456E +ANATOLIAN HIEROGLYPH A327 + +1456F +ANATOLIAN HIEROGLYPH A328 + +14570 +ANATOLIAN HIEROGLYPH A329 + +14571 +ANATOLIAN HIEROGLYPH A329A + +14572 +ANATOLIAN HIEROGLYPH A330 + +14573 +ANATOLIAN HIEROGLYPH A331 + +14574 +ANATOLIAN HIEROGLYPH A332A + +14575 +ANATOLIAN HIEROGLYPH A332B + +14576 +ANATOLIAN HIEROGLYPH A332C + +14577 +ANATOLIAN HIEROGLYPH A333 + +14578 +ANATOLIAN HIEROGLYPH A334 + +14579 +ANATOLIAN HIEROGLYPH A335 + +1457A +ANATOLIAN HIEROGLYPH A336 + +1457B +ANATOLIAN HIEROGLYPH A336A + +1457C +ANATOLIAN HIEROGLYPH A336B + +1457D +ANATOLIAN HIEROGLYPH A336C + +1457E +ANATOLIAN HIEROGLYPH A337 + +1457F +ANATOLIAN HIEROGLYPH A338 + +14580 +ANATOLIAN HIEROGLYPH A339 + +14581 +ANATOLIAN HIEROGLYPH A340 + +14582 +ANATOLIAN HIEROGLYPH A341 + +14583 +ANATOLIAN HIEROGLYPH A342 + +14584 +ANATOLIAN HIEROGLYPH A343 + +14585 +ANATOLIAN HIEROGLYPH A344 + +14586 +ANATOLIAN HIEROGLYPH A345 + +14587 +ANATOLIAN HIEROGLYPH A346 + +14588 +ANATOLIAN HIEROGLYPH A347 + +14589 +ANATOLIAN HIEROGLYPH A348 + +1458A +ANATOLIAN HIEROGLYPH A349 + +1458B +ANATOLIAN HIEROGLYPH A350 + +1458C +ANATOLIAN HIEROGLYPH A351 + +1458D +ANATOLIAN HIEROGLYPH A352 + +1458E +ANATOLIAN HIEROGLYPH A353 + +1458F +ANATOLIAN HIEROGLYPH A354 + +14590 +ANATOLIAN HIEROGLYPH A355 + +14591 +ANATOLIAN HIEROGLYPH A356 + +14592 +ANATOLIAN HIEROGLYPH A357 + +14593 +ANATOLIAN HIEROGLYPH A358 + +14594 +ANATOLIAN HIEROGLYPH A359 + +14595 +ANATOLIAN HIEROGLYPH A359A + +14596 +ANATOLIAN HIEROGLYPH A360 + +14597 +ANATOLIAN HIEROGLYPH A361 + +14598 +ANATOLIAN HIEROGLYPH A362 + +14599 +ANATOLIAN HIEROGLYPH A363 + +1459A +ANATOLIAN HIEROGLYPH A364 + +1459B +ANATOLIAN HIEROGLYPH A364A + +1459C +ANATOLIAN HIEROGLYPH A365 + +1459D +ANATOLIAN HIEROGLYPH A366 + +1459E +ANATOLIAN HIEROGLYPH A367 + +1459F +ANATOLIAN HIEROGLYPH A368 + +145A0 +ANATOLIAN HIEROGLYPH A368A + +145A1 +ANATOLIAN HIEROGLYPH A369 + +145A2 +ANATOLIAN HIEROGLYPH A370 + +145A3 +ANATOLIAN HIEROGLYPH A371 + +145A4 +ANATOLIAN HIEROGLYPH A371A + +145A5 +ANATOLIAN HIEROGLYPH A372 + +145A6 +ANATOLIAN HIEROGLYPH A373 + +145A7 +ANATOLIAN HIEROGLYPH A374 + +145A8 +ANATOLIAN HIEROGLYPH A375 + +145A9 +ANATOLIAN HIEROGLYPH A376 + +145AA +ANATOLIAN HIEROGLYPH A377 + +145AB +ANATOLIAN HIEROGLYPH A378 + +145AC +ANATOLIAN HIEROGLYPH A379 + +145AD +ANATOLIAN HIEROGLYPH A380 + +145AE +ANATOLIAN HIEROGLYPH A381 + +145AF +ANATOLIAN HIEROGLYPH A381A + +145B0 +ANATOLIAN HIEROGLYPH A382 + +145B1 +ANATOLIAN HIEROGLYPH A383 RA OR RI + +145B2 +ANATOLIAN HIEROGLYPH A383A + +145B3 +ANATOLIAN HIEROGLYPH A384 + +145B4 +ANATOLIAN HIEROGLYPH A385 + +145B5 +ANATOLIAN HIEROGLYPH A386 + +145B6 +ANATOLIAN HIEROGLYPH A386A + +145B7 +ANATOLIAN HIEROGLYPH A387 + +145B8 +ANATOLIAN HIEROGLYPH A388 + +145B9 +ANATOLIAN HIEROGLYPH A389 + +145BA +ANATOLIAN HIEROGLYPH A390 + +145BB +ANATOLIAN HIEROGLYPH A391 + +145BC +ANATOLIAN HIEROGLYPH A392 + +145BD +ANATOLIAN HIEROGLYPH A393 EIGHT + +145BE +ANATOLIAN HIEROGLYPH A394 + +145BF +ANATOLIAN HIEROGLYPH A395 + +145C0 +ANATOLIAN HIEROGLYPH A396 + +145C1 +ANATOLIAN HIEROGLYPH A397 + +145C2 +ANATOLIAN HIEROGLYPH A398 + +145C3 +ANATOLIAN HIEROGLYPH A399 + +145C4 +ANATOLIAN HIEROGLYPH A400 + +145C5 +ANATOLIAN HIEROGLYPH A401 + +145C6 +ANATOLIAN HIEROGLYPH A402 + +145C7 +ANATOLIAN HIEROGLYPH A403 + +145C8 +ANATOLIAN HIEROGLYPH A404 + +145C9 +ANATOLIAN HIEROGLYPH A405 + +145CA +ANATOLIAN HIEROGLYPH A406 + +145CB +ANATOLIAN HIEROGLYPH A407 + +145CC +ANATOLIAN HIEROGLYPH A408 + +145CD +ANATOLIAN HIEROGLYPH A409 + +145CE +ANATOLIAN HIEROGLYPH A410 BEGIN LOGOGRAM MARK + +145CF +ANATOLIAN HIEROGLYPH A410A END LOGOGRAM MARK + +145D0 +ANATOLIAN HIEROGLYPH A411 + +145D1 +ANATOLIAN HIEROGLYPH A412 + +145D2 +ANATOLIAN HIEROGLYPH A413 + +145D3 +ANATOLIAN HIEROGLYPH A414 + +145D4 +ANATOLIAN HIEROGLYPH A415 + +145D5 +ANATOLIAN HIEROGLYPH A416 + +145D6 +ANATOLIAN HIEROGLYPH A417 + +145D7 +ANATOLIAN HIEROGLYPH A418 + +145D8 +ANATOLIAN HIEROGLYPH A419 + +145D9 +ANATOLIAN HIEROGLYPH A420 + +145DA +ANATOLIAN HIEROGLYPH A421 + +145DB +ANATOLIAN HIEROGLYPH A422 + +145DC +ANATOLIAN HIEROGLYPH A423 + +145DD +ANATOLIAN HIEROGLYPH A424 + +145DE +ANATOLIAN HIEROGLYPH A425 + +145DF +ANATOLIAN HIEROGLYPH A426 + +145E0 +ANATOLIAN HIEROGLYPH A427 + +145E1 +ANATOLIAN HIEROGLYPH A428 + +145E2 +ANATOLIAN HIEROGLYPH A429 + +145E3 +ANATOLIAN HIEROGLYPH A430 + +145E4 +ANATOLIAN HIEROGLYPH A431 + +145E5 +ANATOLIAN HIEROGLYPH A432 + +145E6 +ANATOLIAN HIEROGLYPH A433 + +145E7 +ANATOLIAN HIEROGLYPH A434 + +145E8 +ANATOLIAN HIEROGLYPH A435 + +145E9 +ANATOLIAN HIEROGLYPH A436 + +145EA +ANATOLIAN HIEROGLYPH A437 + +145EB +ANATOLIAN HIEROGLYPH A438 + +145EC +ANATOLIAN HIEROGLYPH A439 + +145ED +ANATOLIAN HIEROGLYPH A440 + +145EE +ANATOLIAN HIEROGLYPH A441 + +145EF +ANATOLIAN HIEROGLYPH A442 + +145F0 +ANATOLIAN HIEROGLYPH A443 + +145F1 +ANATOLIAN HIEROGLYPH A444 + +145F2 +ANATOLIAN HIEROGLYPH A445 + +145F3 +ANATOLIAN HIEROGLYPH A446 + +145F4 +ANATOLIAN HIEROGLYPH A447 + +145F5 +ANATOLIAN HIEROGLYPH A448 + +145F6 +ANATOLIAN HIEROGLYPH A449 + +145F7 +ANATOLIAN HIEROGLYPH A450 + +145F8 +ANATOLIAN HIEROGLYPH A450A + +145F9 +ANATOLIAN HIEROGLYPH A451 + +145FA +ANATOLIAN HIEROGLYPH A452 + +145FB +ANATOLIAN HIEROGLYPH A453 + +145FC +ANATOLIAN HIEROGLYPH A454 + +145FD +ANATOLIAN HIEROGLYPH A455 + +145FE +ANATOLIAN HIEROGLYPH A456 + +145FF +ANATOLIAN HIEROGLYPH A457 + +14600 +ANATOLIAN HIEROGLYPH A457A + +14601 +ANATOLIAN HIEROGLYPH A458 + +14602 +ANATOLIAN HIEROGLYPH A459 + +14603 +ANATOLIAN HIEROGLYPH A460 + +14604 +ANATOLIAN HIEROGLYPH A461 + +14605 +ANATOLIAN HIEROGLYPH A462 + +14606 +ANATOLIAN HIEROGLYPH A463 + +14607 +ANATOLIAN HIEROGLYPH A464 + +14608 +ANATOLIAN HIEROGLYPH A465 + +14609 +ANATOLIAN HIEROGLYPH A466 + +1460A +ANATOLIAN HIEROGLYPH A467 + +1460B +ANATOLIAN HIEROGLYPH A468 + +1460C +ANATOLIAN HIEROGLYPH A469 + +1460D +ANATOLIAN HIEROGLYPH A470 + +1460E +ANATOLIAN HIEROGLYPH A471 + +1460F +ANATOLIAN HIEROGLYPH A472 + +14610 +ANATOLIAN HIEROGLYPH A473 + +14611 +ANATOLIAN HIEROGLYPH A474 + +14612 +ANATOLIAN HIEROGLYPH A475 + +14613 +ANATOLIAN HIEROGLYPH A476 + +14614 +ANATOLIAN HIEROGLYPH A477 + +14615 +ANATOLIAN HIEROGLYPH A478 + +14616 +ANATOLIAN HIEROGLYPH A479 + +14617 +ANATOLIAN HIEROGLYPH A480 + +14618 +ANATOLIAN HIEROGLYPH A481 + +14619 +ANATOLIAN HIEROGLYPH A482 + +1461A +ANATOLIAN HIEROGLYPH A483 + +1461B +ANATOLIAN HIEROGLYPH A484 + +1461C +ANATOLIAN HIEROGLYPH A485 + +1461D +ANATOLIAN HIEROGLYPH A486 + +1461E +ANATOLIAN HIEROGLYPH A487 + +1461F +ANATOLIAN HIEROGLYPH A488 + +14620 +ANATOLIAN HIEROGLYPH A489 + +14621 +ANATOLIAN HIEROGLYPH A490 + +14622 +ANATOLIAN HIEROGLYPH A491 + +14623 +ANATOLIAN HIEROGLYPH A492 + +14624 +ANATOLIAN HIEROGLYPH A493 + +14625 +ANATOLIAN HIEROGLYPH A494 + +14626 +ANATOLIAN HIEROGLYPH A495 + +14627 +ANATOLIAN HIEROGLYPH A496 + +14628 +ANATOLIAN HIEROGLYPH A497 + +14629 +ANATOLIAN HIEROGLYPH A501 + +1462A +ANATOLIAN HIEROGLYPH A502 + +1462B +ANATOLIAN HIEROGLYPH A503 + +1462C +ANATOLIAN HIEROGLYPH A504 + +1462D +ANATOLIAN HIEROGLYPH A505 + +1462E +ANATOLIAN HIEROGLYPH A506 + +1462F +ANATOLIAN HIEROGLYPH A507 + +14630 +ANATOLIAN HIEROGLYPH A508 + +14631 +ANATOLIAN HIEROGLYPH A509 + +14632 +ANATOLIAN HIEROGLYPH A510 + +14633 +ANATOLIAN HIEROGLYPH A511 + +14634 +ANATOLIAN HIEROGLYPH A512 + +14635 +ANATOLIAN HIEROGLYPH A513 + +14636 +ANATOLIAN HIEROGLYPH A514 + +14637 +ANATOLIAN HIEROGLYPH A515 + +14638 +ANATOLIAN HIEROGLYPH A516 + +14639 +ANATOLIAN HIEROGLYPH A517 + +1463A +ANATOLIAN HIEROGLYPH A518 + +1463B +ANATOLIAN HIEROGLYPH A519 + +1463C +ANATOLIAN HIEROGLYPH A520 + +1463D +ANATOLIAN HIEROGLYPH A521 + +1463E +ANATOLIAN HIEROGLYPH A522 + +1463F +ANATOLIAN HIEROGLYPH A523 + +14640 +ANATOLIAN HIEROGLYPH A524 + +14641 +ANATOLIAN HIEROGLYPH A525 + +14642 +ANATOLIAN HIEROGLYPH A526 + +14643 +ANATOLIAN HIEROGLYPH A527 + +14644 +ANATOLIAN HIEROGLYPH A528 + +14645 +ANATOLIAN HIEROGLYPH A529 + +14646 +ANATOLIAN HIEROGLYPH A530 + +16100 +GURUNG KHEMA LETTER A + +16101 +GURUNG KHEMA LETTER KA + +16102 +GURUNG KHEMA LETTER KHA + +16103 +GURUNG KHEMA LETTER GA + +16104 +GURUNG KHEMA LETTER GHA + +16105 +GURUNG KHEMA LETTER NGA + +16106 +GURUNG KHEMA LETTER CA + +16107 +GURUNG KHEMA LETTER CHA + +16108 +GURUNG KHEMA LETTER JA + +16109 +GURUNG KHEMA LETTER JHA + +1610A +GURUNG KHEMA LETTER HA + +1610B +GURUNG KHEMA LETTER TTA + +1610C +GURUNG KHEMA LETTER TTHA + +1610D +GURUNG KHEMA LETTER DDA + +1610E +GURUNG KHEMA LETTER DDHA + +1610F +GURUNG KHEMA LETTER VA + +16110 +GURUNG KHEMA LETTER TA + +16111 +GURUNG KHEMA LETTER THA + +16112 +GURUNG KHEMA LETTER DA + +16113 +GURUNG KHEMA LETTER DHA + +16114 +GURUNG KHEMA LETTER NA + +16115 +GURUNG KHEMA LETTER PA + +16116 +GURUNG KHEMA LETTER PHA + +16117 +GURUNG KHEMA LETTER BA + +16118 +GURUNG KHEMA LETTER BHA + +16119 +GURUNG KHEMA LETTER MA + +1611A +GURUNG KHEMA LETTER YA + +1611B +GURUNG KHEMA LETTER RA + +1611C +GURUNG KHEMA LETTER LA + +1611D +GURUNG KHEMA LETTER SA + +1611E +GURUNG KHEMA VOWEL SIGN AA + +1611F +GURUNG KHEMA VOWEL SIGN I + +16120 +GURUNG KHEMA VOWEL SIGN II + +16121 +GURUNG KHEMA VOWEL SIGN U + +16122 +GURUNG KHEMA VOWEL SIGN UU + +16123 +GURUNG KHEMA VOWEL SIGN E + +16124 +GURUNG KHEMA VOWEL SIGN EE + +16125 +GURUNG KHEMA VOWEL SIGN AI + +16126 +GURUNG KHEMA VOWEL SIGN O + +16127 +GURUNG KHEMA VOWEL SIGN OO + +16128 +GURUNG KHEMA VOWEL SIGN AU + +16129 +GURUNG KHEMA VOWEL LENGTH MARK + +1612A +GURUNG KHEMA CONSONANT SIGN MEDIAL YA + +1612B +GURUNG KHEMA CONSONANT SIGN MEDIAL VA + +1612C +GURUNG KHEMA CONSONANT SIGN MEDIAL HA + +1612D +GURUNG KHEMA SIGN ANUSVARA + +1612E +GURUNG KHEMA CONSONANT SIGN MEDIAL RA + +1612F +GURUNG KHEMA SIGN THOLHOMA + +16130 +GURUNG KHEMA DIGIT ZERO + +16131 +GURUNG KHEMA DIGIT ONE + +16132 +GURUNG KHEMA DIGIT TWO + +16133 +GURUNG KHEMA DIGIT THREE + +16134 +GURUNG KHEMA DIGIT FOUR + +16135 +GURUNG KHEMA DIGIT FIVE + +16136 +GURUNG KHEMA DIGIT SIX + +16137 +GURUNG KHEMA DIGIT SEVEN + +16138 +GURUNG KHEMA DIGIT EIGHT + +16139 +GURUNG KHEMA DIGIT NINE + +16800 +BAMUM LETTER PHASE-A NGKUE MFON + +16801 +BAMUM LETTER PHASE-A GBIEE FON + +16802 +BAMUM LETTER PHASE-A PON MFON PIPAEMGBIEE + +16803 +BAMUM LETTER PHASE-A PON MFON PIPAEMBA + +16804 +BAMUM LETTER PHASE-A NAA MFON + +16805 +BAMUM LETTER PHASE-A SHUENSHUET + +16806 +BAMUM LETTER PHASE-A TITA MFON + +16807 +BAMUM LETTER PHASE-A NZA MFON + +16808 +BAMUM LETTER PHASE-A SHINDA PA NJI + +16809 +BAMUM LETTER PHASE-A PON PA NJI PIPAEMGBIEE + +1680A +BAMUM LETTER PHASE-A PON PA NJI PIPAEMBA + +1680B +BAMUM LETTER PHASE-A MAEMGBIEE + +1680B +BAMUM LETTER PHASE-A MAEMBGBIEE + +1680C +BAMUM LETTER PHASE-A TU MAEMBA + +1680D +BAMUM LETTER PHASE-A NGANGU + +1680E +BAMUM LETTER PHASE-A MAEMVEUX + +1680F +BAMUM LETTER PHASE-A MANSUAE + +16810 +BAMUM LETTER PHASE-A MVEUAENGAM + +16811 +BAMUM LETTER PHASE-A SEUNYAM + +16812 +BAMUM LETTER PHASE-A NTOQPEN + +16813 +BAMUM LETTER PHASE-A KEUKEUTNDA + +16814 +BAMUM LETTER PHASE-A NKINDI + +16815 +BAMUM LETTER PHASE-A SUU + +16816 +BAMUM LETTER PHASE-A NGKUENZEUM + +16817 +BAMUM LETTER PHASE-A LAPAQ + +16818 +BAMUM LETTER PHASE-A LET KUT + +16819 +BAMUM LETTER PHASE-A NTAP MFAA + +1681A +BAMUM LETTER PHASE-A MAEKEUP + +1681B +BAMUM LETTER PHASE-A PASHAE + +1681C +BAMUM LETTER PHASE-A GHEUAERAE + +1681D +BAMUM LETTER PHASE-A PAMSHAE + +1681E +BAMUM LETTER PHASE-A MON NGGEUAET + +1681F +BAMUM LETTER PHASE-A NZUN MEUT + +16820 +BAMUM LETTER PHASE-A U YUQ NAE + +16821 +BAMUM LETTER PHASE-A GHEUAEGHEUAE + +16822 +BAMUM LETTER PHASE-A NTAP NTAA + +16823 +BAMUM LETTER PHASE-A SISA + +16824 +BAMUM LETTER PHASE-A MGBASA + +16825 +BAMUM LETTER PHASE-A MEUNJOMNDEUQ + +16826 +BAMUM LETTER PHASE-A MOOMPUQ + +16827 +BAMUM LETTER PHASE-A KAFA + +16828 +BAMUM LETTER PHASE-A PA LEERAEWA + +16829 +BAMUM LETTER PHASE-A NDA LEERAEWA + +1682A +BAMUM LETTER PHASE-A PET + +1682B +BAMUM LETTER PHASE-A MAEMKPEN + +1682C +BAMUM LETTER PHASE-A NIKA + +1682D +BAMUM LETTER PHASE-A PUP + +1682E +BAMUM LETTER PHASE-A TUAEP + +1682F +BAMUM LETTER PHASE-A LUAEP + +16830 +BAMUM LETTER PHASE-A SONJAM + +16831 +BAMUM LETTER PHASE-A TEUTEUWEN + +16832 +BAMUM LETTER PHASE-A MAENYI + +16833 +BAMUM LETTER PHASE-A KET + +16834 +BAMUM LETTER PHASE-A NDAANGGEUAET + +16835 +BAMUM LETTER PHASE-A KUOQ + +16836 +BAMUM LETTER PHASE-A MOOMEUT + +16837 +BAMUM LETTER PHASE-A SHUM + +16838 +BAMUM LETTER PHASE-A LOMMAE + +16839 +BAMUM LETTER PHASE-A FIRI + +1683A +BAMUM LETTER PHASE-A ROM + +1683B +BAMUM LETTER PHASE-A KPOQ + +1683C +BAMUM LETTER PHASE-A SOQ + +1683D +BAMUM LETTER PHASE-A MAP PIEET + +1683E +BAMUM LETTER PHASE-A SHIRAE + +1683F +BAMUM LETTER PHASE-A NTAP + +16840 +BAMUM LETTER PHASE-A SHOQ NSHUT YUM + +16841 +BAMUM LETTER PHASE-A NYIT MONGKEUAEQ + +16842 +BAMUM LETTER PHASE-A PAARAE + +16843 +BAMUM LETTER PHASE-A NKAARAE + +16844 +BAMUM LETTER PHASE-A UNKNOWN + +16845 +BAMUM LETTER PHASE-A NGGEN + +16846 +BAMUM LETTER PHASE-A MAESI + +16847 +BAMUM LETTER PHASE-A NJAM + +16848 +BAMUM LETTER PHASE-A MBANYI + +16849 +BAMUM LETTER PHASE-A NYET + +1684A +BAMUM LETTER PHASE-A TEUAEN + +1684B +BAMUM LETTER PHASE-A SOT + +1684C +BAMUM LETTER PHASE-A PAAM + +1684D +BAMUM LETTER PHASE-A NSHIEE + +1684E +BAMUM LETTER PHASE-A MAEM + +1684F +BAMUM LETTER PHASE-A NYI + +16850 +BAMUM LETTER PHASE-A KAQ + +16851 +BAMUM LETTER PHASE-A NSHA + +16852 +BAMUM LETTER PHASE-A VEE + +16853 +BAMUM LETTER PHASE-A LU + +16854 +BAMUM LETTER PHASE-A NEN + +16855 +BAMUM LETTER PHASE-A NAQ + +16856 +BAMUM LETTER PHASE-A MBAQ + +16857 +BAMUM LETTER PHASE-B NSHUET + +16858 +BAMUM LETTER PHASE-B TU MAEMGBIEE + +16859 +BAMUM LETTER PHASE-B SIEE + +1685A +BAMUM LETTER PHASE-B SET TU + +1685B +BAMUM LETTER PHASE-B LOM NTEUM + +1685C +BAMUM LETTER PHASE-B MBA MAELEE + +1685D +BAMUM LETTER PHASE-B KIEEM + +1685E +BAMUM LETTER PHASE-B YEURAE + +1685F +BAMUM LETTER PHASE-B MBAARAE + +16860 +BAMUM LETTER PHASE-B KAM + +16861 +BAMUM LETTER PHASE-B PEESHI + +16862 +BAMUM LETTER PHASE-B YAFU LEERAEWA + +16863 +BAMUM LETTER PHASE-B LAM NSHUT NYAM + +16864 +BAMUM LETTER PHASE-B NTIEE SHEUOQ + +16865 +BAMUM LETTER PHASE-B NDU NJAA + +16866 +BAMUM LETTER PHASE-B GHEUGHEUAEM + +16867 +BAMUM LETTER PHASE-B PIT + +16868 +BAMUM LETTER PHASE-B TU NSIEE + +16869 +BAMUM LETTER PHASE-B SHET NJAQ + +1686A +BAMUM LETTER PHASE-B SHEUAEQTU + +1686B +BAMUM LETTER PHASE-B MFON TEUAEQ + +1686C +BAMUM LETTER PHASE-B MBIT MBAAKET + +1686D +BAMUM LETTER PHASE-B NYI NTEUM + +1686E +BAMUM LETTER PHASE-B KEUPUQ + +1686F +BAMUM LETTER PHASE-B GHEUGHEN + +16870 +BAMUM LETTER PHASE-B KEUYEUX + +16871 +BAMUM LETTER PHASE-B LAANAE + +16872 +BAMUM LETTER PHASE-B PARUM + +16873 +BAMUM LETTER PHASE-B VEUM + +16874 +BAMUM LETTER PHASE-B NGKINDI MVOP + +16875 +BAMUM LETTER PHASE-B NGGEU MBU + +16876 +BAMUM LETTER PHASE-B WUAET + +16877 +BAMUM LETTER PHASE-B SAKEUAE + +16878 +BAMUM LETTER PHASE-B TAAM + +16879 +BAMUM LETTER PHASE-B MEUQ + +1687A +BAMUM LETTER PHASE-B NGGUOQ + +1687B +BAMUM LETTER PHASE-B NGGUOQ LARGE + +1687C +BAMUM LETTER PHASE-B MFIYAQ + +1687D +BAMUM LETTER PHASE-B SUE + +1687E +BAMUM LETTER PHASE-B MBEURI + +1687F +BAMUM LETTER PHASE-B MONTIEEN + +16880 +BAMUM LETTER PHASE-B NYAEMAE + +16881 +BAMUM LETTER PHASE-B PUNGGAAM + +16881 +BAMUM LETTER PHASE-B PUNGAAM + +16882 +BAMUM LETTER PHASE-B MEUT NGGEET + +16883 +BAMUM LETTER PHASE-B FEUX + +16884 +BAMUM LETTER PHASE-B MBUOQ + +16885 +BAMUM LETTER PHASE-B FEE + +16886 +BAMUM LETTER PHASE-B KEUAEM + +16887 +BAMUM LETTER PHASE-B MA NJEUAENA + +16888 +BAMUM LETTER PHASE-B MA NJUQA + +16889 +BAMUM LETTER PHASE-B LET + +1688A +BAMUM LETTER PHASE-B NGGAAM + +1688B +BAMUM LETTER PHASE-B NSEN + +1688C +BAMUM LETTER PHASE-B MA + +1688D +BAMUM LETTER PHASE-B KIQ + +1688E +BAMUM LETTER PHASE-B NGGOM + +1688E +BAMUM LETTER PHASE-B NGOM + +1688F +BAMUM LETTER PHASE-C NGKUE MAEMBA + +16890 +BAMUM LETTER PHASE-C NZA + +16891 +BAMUM LETTER PHASE-C YUM + +16892 +BAMUM LETTER PHASE-C WANGKUOQ + +16893 +BAMUM LETTER PHASE-C NGGEN + +16894 +BAMUM LETTER PHASE-C NDEUAEREE + +16895 +BAMUM LETTER PHASE-C NGKAQ + +16896 +BAMUM LETTER PHASE-C GHARAE + +16897 +BAMUM LETTER PHASE-C MBEEKEET + +16898 +BAMUM LETTER PHASE-C GBAYI + +16899 +BAMUM LETTER PHASE-C NYIR MKPARAQ MEUN + +1689A +BAMUM LETTER PHASE-C NTU MBIT + +1689B +BAMUM LETTER PHASE-C MBEUM + +1689C +BAMUM LETTER PHASE-C PIRIEEN + +1689D +BAMUM LETTER PHASE-C NDOMBU + +1689E +BAMUM LETTER PHASE-C MBAA CABBAGE-TREE + +1689F +BAMUM LETTER PHASE-C KEUSHEUAEP + +168A0 +BAMUM LETTER PHASE-C GHAP + +168A1 +BAMUM LETTER PHASE-C KEUKAQ + +168A2 +BAMUM LETTER PHASE-C YU MUOMAE + +168A3 +BAMUM LETTER PHASE-C NZEUM + +168A4 +BAMUM LETTER PHASE-C MBUE + +168A5 +BAMUM LETTER PHASE-C NSEUAEN + +168A6 +BAMUM LETTER PHASE-C MBIT + +168A7 +BAMUM LETTER PHASE-C YEUQ + +168A8 +BAMUM LETTER PHASE-C KPARAQ + +168A9 +BAMUM LETTER PHASE-C KAA + +168AA +BAMUM LETTER PHASE-C SEUX + +168AB +BAMUM LETTER PHASE-C NDIDA + +168AC +BAMUM LETTER PHASE-C TAASHAE + +168AD +BAMUM LETTER PHASE-C NJUEQ + +168AE +BAMUM LETTER PHASE-C TITA YUE + +168AF +BAMUM LETTER PHASE-C SUAET + +168B0 +BAMUM LETTER PHASE-C NGGUAEN NYAM + +168B1 +BAMUM LETTER PHASE-C VEUX + +168B2 +BAMUM LETTER PHASE-C NANSANAQ + +168B3 +BAMUM LETTER PHASE-C MA KEUAERI + +168B4 +BAMUM LETTER PHASE-C NTAA + +168B5 +BAMUM LETTER PHASE-C NGGUON + +168B6 +BAMUM LETTER PHASE-C LAP + +168B7 +BAMUM LETTER PHASE-C MBIRIEEN + +168B8 +BAMUM LETTER PHASE-C MGBASAQ + +168B9 +BAMUM LETTER PHASE-C NTEUNGBA + +168BA +BAMUM LETTER PHASE-C TEUTEUX + +168BB +BAMUM LETTER PHASE-C NGGUM + +168BC +BAMUM LETTER PHASE-C FUE + +168BD +BAMUM LETTER PHASE-C NDEUT + +168BE +BAMUM LETTER PHASE-C NSA + +168BF +BAMUM LETTER PHASE-C NSHAQ + +168C0 +BAMUM LETTER PHASE-C BUNG + +168C1 +BAMUM LETTER PHASE-C VEUAEPEN + +168C2 +BAMUM LETTER PHASE-C MBERAE + +168C3 +BAMUM LETTER PHASE-C RU + +168C4 +BAMUM LETTER PHASE-C NJAEM + +168C5 +BAMUM LETTER PHASE-C LAM + +168C6 +BAMUM LETTER PHASE-C TITUAEP + +168C7 +BAMUM LETTER PHASE-C NSUOT NGOM + +168C8 +BAMUM LETTER PHASE-C NJEEEE + +168C9 +BAMUM LETTER PHASE-C KET + +168CA +BAMUM LETTER PHASE-C NGGU + +168CB +BAMUM LETTER PHASE-C MAESI + +168CC +BAMUM LETTER PHASE-C MBUAEM + +168CD +BAMUM LETTER PHASE-C LU + +168CE +BAMUM LETTER PHASE-C KUT + +168CF +BAMUM LETTER PHASE-C NJAM + +168D0 +BAMUM LETTER PHASE-C NGOM + +168D1 +BAMUM LETTER PHASE-C WUP + +168D2 +BAMUM LETTER PHASE-C NGGUEET + +168D3 +BAMUM LETTER PHASE-C NSOM + +168D4 +BAMUM LETTER PHASE-C NTEN + +168D5 +BAMUM LETTER PHASE-C KUOP NKAARAE + +168D6 +BAMUM LETTER PHASE-C NSUN + +168D7 +BAMUM LETTER PHASE-C NDAM + +168D8 +BAMUM LETTER PHASE-C MA NSIEE + +168D9 +BAMUM LETTER PHASE-C YAA + +168DA +BAMUM LETTER PHASE-C NDAP + +168DB +BAMUM LETTER PHASE-C SHUEQ + +168DC +BAMUM LETTER PHASE-C SHETFON + +168DC +BAMUM LETTER PHASE-C SETFON + +168DD +BAMUM LETTER PHASE-C MBI + +168DE +BAMUM LETTER PHASE-C MAEMBA + +168DF +BAMUM LETTER PHASE-C MBANYI + +168E0 +BAMUM LETTER PHASE-C KEUSEUX + +168E1 +BAMUM LETTER PHASE-C MBEUX + +168E2 +BAMUM LETTER PHASE-C KEUM + +168E3 +BAMUM LETTER PHASE-C MBAA PICKET + +168E4 +BAMUM LETTER PHASE-C YUWOQ + +168E5 +BAMUM LETTER PHASE-C NJEUX + +168E6 +BAMUM LETTER PHASE-C MIEE + +168E7 +BAMUM LETTER PHASE-C MUAE + +168E8 +BAMUM LETTER PHASE-C SHIQ + +168E9 +BAMUM LETTER PHASE-C KEN LAW + +168EA +BAMUM LETTER PHASE-C KEN FATIGUE + +168EB +BAMUM LETTER PHASE-C NGAQ + +168EC +BAMUM LETTER PHASE-C NAQ + +168ED +BAMUM LETTER PHASE-C LIQ + +168EE +BAMUM LETTER PHASE-C PIN + +168EF +BAMUM LETTER PHASE-C PEN + +168F0 +BAMUM LETTER PHASE-C TET + +168F1 +BAMUM LETTER PHASE-D MBUO + +168F2 +BAMUM LETTER PHASE-D WAP + +168F3 +BAMUM LETTER PHASE-D NJI + +168F4 +BAMUM LETTER PHASE-D MFON + +168F5 +BAMUM LETTER PHASE-D NJIEE + +168F6 +BAMUM LETTER PHASE-D LIEE + +168F7 +BAMUM LETTER PHASE-D NJEUT + +168F8 +BAMUM LETTER PHASE-D NSHEE + +168F9 +BAMUM LETTER PHASE-D NGGAAMAE + +168FA +BAMUM LETTER PHASE-D NYAM + +168FB +BAMUM LETTER PHASE-D WUAEN + +168FC +BAMUM LETTER PHASE-D NGKUN + +168FD +BAMUM LETTER PHASE-D SHEE + +168FE +BAMUM LETTER PHASE-D NGKAP + +168FF +BAMUM LETTER PHASE-D KEUAETMEUN + +16900 +BAMUM LETTER PHASE-D TEUT + +16901 +BAMUM LETTER PHASE-D SHEUAE + +16902 +BAMUM LETTER PHASE-D NJAP + +16903 +BAMUM LETTER PHASE-D SUE + +16904 +BAMUM LETTER PHASE-D KET + +16905 +BAMUM LETTER PHASE-D YAEMMAE + +16906 +BAMUM LETTER PHASE-D KUOM + +16907 +BAMUM LETTER PHASE-D SAP + +16908 +BAMUM LETTER PHASE-D MFEUT + +16909 +BAMUM LETTER PHASE-D NDEUX + +1690A +BAMUM LETTER PHASE-D MALEERI + +1690B +BAMUM LETTER PHASE-D MEUT + +1690C +BAMUM LETTER PHASE-D SEUAEQ + +1690D +BAMUM LETTER PHASE-D YEN + +1690E +BAMUM LETTER PHASE-D NJEUAEM + +1690F +BAMUM LETTER PHASE-D KEUOT MBUAE + +16910 +BAMUM LETTER PHASE-D NGKEURI + +16911 +BAMUM LETTER PHASE-D TU + +16912 +BAMUM LETTER PHASE-D GHAA + +16913 +BAMUM LETTER PHASE-D NGKYEE + +16914 +BAMUM LETTER PHASE-D FEUFEUAET + +16915 +BAMUM LETTER PHASE-D NDEE + +16916 +BAMUM LETTER PHASE-D MGBOFUM + +16917 +BAMUM LETTER PHASE-D LEUAEP + +16918 +BAMUM LETTER PHASE-D NDON + +16919 +BAMUM LETTER PHASE-D MONI + +1691A +BAMUM LETTER PHASE-D MGBEUN + +1691B +BAMUM LETTER PHASE-D PUUT + +1691C +BAMUM LETTER PHASE-D MGBIEE + +1691D +BAMUM LETTER PHASE-D MFO + +1691E +BAMUM LETTER PHASE-D LUM + +1691F +BAMUM LETTER PHASE-D NSIEEP + +16920 +BAMUM LETTER PHASE-D MBAA + +16921 +BAMUM LETTER PHASE-D KWAET + +16922 +BAMUM LETTER PHASE-D NYET + +16923 +BAMUM LETTER PHASE-D TEUAEN + +16924 +BAMUM LETTER PHASE-D SOT + +16925 +BAMUM LETTER PHASE-D YUWOQ + +16926 +BAMUM LETTER PHASE-D KEUM + +16927 +BAMUM LETTER PHASE-D RAEM + +16928 +BAMUM LETTER PHASE-D TEEEE + +16929 +BAMUM LETTER PHASE-D NGKEUAEQ + +1692A +BAMUM LETTER PHASE-D MFEUAE + +1692B +BAMUM LETTER PHASE-D NSIEET + +1692C +BAMUM LETTER PHASE-D KEUP + +1692D +BAMUM LETTER PHASE-D PIP + +1692E +BAMUM LETTER PHASE-D PEUTAE + +1692F +BAMUM LETTER PHASE-D NYUE + +16930 +BAMUM LETTER PHASE-D LET + +16931 +BAMUM LETTER PHASE-D NGGAAM + +16932 +BAMUM LETTER PHASE-D MFIEE + +16933 +BAMUM LETTER PHASE-D NGGWAEN + +16934 +BAMUM LETTER PHASE-D YUOM + +16935 +BAMUM LETTER PHASE-D PAP + +16936 +BAMUM LETTER PHASE-D YUOP + +16937 +BAMUM LETTER PHASE-D NDAM + +16938 +BAMUM LETTER PHASE-D NTEUM + +16939 +BAMUM LETTER PHASE-D SUAE + +1693A +BAMUM LETTER PHASE-D KUN + +1693B +BAMUM LETTER PHASE-D NGGEUX + +1693C +BAMUM LETTER PHASE-D NGKIEE + +1693D +BAMUM LETTER PHASE-D TUOT + +1693E +BAMUM LETTER PHASE-D MEUN + +1693F +BAMUM LETTER PHASE-D KUQ + +16940 +BAMUM LETTER PHASE-D NSUM + +16941 +BAMUM LETTER PHASE-D TEUN + +16942 +BAMUM LETTER PHASE-D MAENJET + +16943 +BAMUM LETTER PHASE-D NGGAP + +16944 +BAMUM LETTER PHASE-D LEUM + +16945 +BAMUM LETTER PHASE-D NGGUOM + +16946 +BAMUM LETTER PHASE-D NSHUT + +16947 +BAMUM LETTER PHASE-D NJUEQ + +16948 +BAMUM LETTER PHASE-D GHEUAE + +16949 +BAMUM LETTER PHASE-D KU + +1694A +BAMUM LETTER PHASE-D REN OLD + +1694B +BAMUM LETTER PHASE-D TAE + +1694C +BAMUM LETTER PHASE-D TOQ + +1694D +BAMUM LETTER PHASE-D NYI + +1694E +BAMUM LETTER PHASE-D RII + +1694F +BAMUM LETTER PHASE-D LEEEE + +16950 +BAMUM LETTER PHASE-D MEEEE + +16951 +BAMUM LETTER PHASE-D M + +16952 +BAMUM LETTER PHASE-D SUU + +16953 +BAMUM LETTER PHASE-D MU + +16954 +BAMUM LETTER PHASE-D SHII + +16955 +BAMUM LETTER PHASE-D SHEUX + +16956 +BAMUM LETTER PHASE-D KYEE + +16957 +BAMUM LETTER PHASE-D NU + +16958 +BAMUM LETTER PHASE-D SHU + +16959 +BAMUM LETTER PHASE-D NTEE + +1695A +BAMUM LETTER PHASE-D PEE + +1695B +BAMUM LETTER PHASE-D NI + +1695C +BAMUM LETTER PHASE-D SHOQ + +1695D +BAMUM LETTER PHASE-D PUQ + +1695E +BAMUM LETTER PHASE-D MVOP + +1695F +BAMUM LETTER PHASE-D LOQ + +16960 +BAMUM LETTER PHASE-D REN MUCH + +16961 +BAMUM LETTER PHASE-D TI + +16962 +BAMUM LETTER PHASE-D NTUU + +16963 +BAMUM LETTER PHASE-D MBAA SEVEN + +16964 +BAMUM LETTER PHASE-D SAQ + +16965 +BAMUM LETTER PHASE-D FAA + +16966 +BAMUM LETTER PHASE-E NDAP + +16967 +BAMUM LETTER PHASE-E TOON + +16968 +BAMUM LETTER PHASE-E MBEUM + +16969 +BAMUM LETTER PHASE-E LAP + +1696A +BAMUM LETTER PHASE-E VOM + +1696B +BAMUM LETTER PHASE-E LOON + +1696C +BAMUM LETTER PHASE-E PAA + +1696D +BAMUM LETTER PHASE-E SOM + +1696E +BAMUM LETTER PHASE-E RAQ + +1696F +BAMUM LETTER PHASE-E NSHUOP + +16970 +BAMUM LETTER PHASE-E NDUN + +16971 +BAMUM LETTER PHASE-E PUAE + +16972 +BAMUM LETTER PHASE-E TAM + +16973 +BAMUM LETTER PHASE-E NGKA + +16974 +BAMUM LETTER PHASE-E KPEUX + +16975 +BAMUM LETTER PHASE-E WUO + +16976 +BAMUM LETTER PHASE-E SEE + +16977 +BAMUM LETTER PHASE-E NGGEUAET + +16978 +BAMUM LETTER PHASE-E PAAM + +16979 +BAMUM LETTER PHASE-E TOO + +1697A +BAMUM LETTER PHASE-E KUOP + +1697B +BAMUM LETTER PHASE-E LOM + +1697C +BAMUM LETTER PHASE-E NSHIEE + +1697D +BAMUM LETTER PHASE-E NGGOP + +1697D +BAMUM LETTER PHASE-E NGOP + +1697E +BAMUM LETTER PHASE-E MAEM + +1697F +BAMUM LETTER PHASE-E NGKEUX + +16980 +BAMUM LETTER PHASE-E NGOQ + +16981 +BAMUM LETTER PHASE-E NSHUE + +16982 +BAMUM LETTER PHASE-E RIMGBA + +16983 +BAMUM LETTER PHASE-E NJEUX + +16984 +BAMUM LETTER PHASE-E PEEM + +16985 +BAMUM LETTER PHASE-E SAA + +16986 +BAMUM LETTER PHASE-E NGGURAE + +16987 +BAMUM LETTER PHASE-E MGBA + +16988 +BAMUM LETTER PHASE-E GHEUX + +16989 +BAMUM LETTER PHASE-E NGKEUAEM + +1698A +BAMUM LETTER PHASE-E NJAEMLI + +1698B +BAMUM LETTER PHASE-E MAP + +1698C +BAMUM LETTER PHASE-E LOOT + +1698D +BAMUM LETTER PHASE-E NGGEEEE + +1698E +BAMUM LETTER PHASE-E NDIQ + +1698F +BAMUM LETTER PHASE-E TAEN NTEUM + +16990 +BAMUM LETTER PHASE-E SET + +16991 +BAMUM LETTER PHASE-E PUM + +16992 +BAMUM LETTER PHASE-E NDAA SOFTNESS + +16993 +BAMUM LETTER PHASE-E NGGUAESHAE NYAM + +16994 +BAMUM LETTER PHASE-E YIEE + +16995 +BAMUM LETTER PHASE-E GHEUN + +16996 +BAMUM LETTER PHASE-E TUAE + +16997 +BAMUM LETTER PHASE-E YEUAE + +16998 +BAMUM LETTER PHASE-E PO + +16999 +BAMUM LETTER PHASE-E TUMAE + +1699A +BAMUM LETTER PHASE-E KEUAE + +1699B +BAMUM LETTER PHASE-E SUAEN + +1699C +BAMUM LETTER PHASE-E TEUAEQ + +1699D +BAMUM LETTER PHASE-E VEUAE + +1699E +BAMUM LETTER PHASE-E WEUX + +1699F +BAMUM LETTER PHASE-E LAAM + +169A0 +BAMUM LETTER PHASE-E PU + +169A1 +BAMUM LETTER PHASE-E TAAQ + +169A2 +BAMUM LETTER PHASE-E GHAAMAE + +169A3 +BAMUM LETTER PHASE-E NGEUREUT + +169A4 +BAMUM LETTER PHASE-E SHEUAEQ + +169A5 +BAMUM LETTER PHASE-E MGBEN + +169A6 +BAMUM LETTER PHASE-E MBEE + +169A7 +BAMUM LETTER PHASE-E NZAQ + +169A8 +BAMUM LETTER PHASE-E NKOM + +169A9 +BAMUM LETTER PHASE-E GBET + +169AA +BAMUM LETTER PHASE-E TUM + +169AB +BAMUM LETTER PHASE-E KUET + +169AC +BAMUM LETTER PHASE-E YAP + +169AD +BAMUM LETTER PHASE-E NYI CLEAVER + +169AE +BAMUM LETTER PHASE-E YIT + +169AF +BAMUM LETTER PHASE-E MFEUQ + +169B0 +BAMUM LETTER PHASE-E NDIAQ + +169B1 +BAMUM LETTER PHASE-E PIEEQ + +169B2 +BAMUM LETTER PHASE-E YUEQ + +169B3 +BAMUM LETTER PHASE-E LEUAEM + +169B4 +BAMUM LETTER PHASE-E FUE + +169B5 +BAMUM LETTER PHASE-E GBEUX + +169B6 +BAMUM LETTER PHASE-E NGKUP + +169B7 +BAMUM LETTER PHASE-E KET + +169B8 +BAMUM LETTER PHASE-E MAE + +169B9 +BAMUM LETTER PHASE-E NGKAAMI + +169BA +BAMUM LETTER PHASE-E GHET + +169BB +BAMUM LETTER PHASE-E FA + +169BC +BAMUM LETTER PHASE-E NTUM + +169BD +BAMUM LETTER PHASE-E PEUT + +169BE +BAMUM LETTER PHASE-E YEUM + +169BF +BAMUM LETTER PHASE-E NGGEUAE + +169C0 +BAMUM LETTER PHASE-E NYI BETWEEN + +169C1 +BAMUM LETTER PHASE-E NZUQ + +169C2 +BAMUM LETTER PHASE-E POON + +169C3 +BAMUM LETTER PHASE-E MIEE + +169C4 +BAMUM LETTER PHASE-E FUET + +169C5 +BAMUM LETTER PHASE-E NAE + +169C6 +BAMUM LETTER PHASE-E MUAE + +169C7 +BAMUM LETTER PHASE-E GHEUAE + +169C8 +BAMUM LETTER PHASE-E FU I + +169C9 +BAMUM LETTER PHASE-E MVI + +169CA +BAMUM LETTER PHASE-E PUAQ + +169CB +BAMUM LETTER PHASE-E NGKUM + +169CC +BAMUM LETTER PHASE-E KUT + +169CD +BAMUM LETTER PHASE-E PIET + +169CE +BAMUM LETTER PHASE-E NTAP + +169CF +BAMUM LETTER PHASE-E YEUAET + +169D0 +BAMUM LETTER PHASE-E NGGUP + +169D1 +BAMUM LETTER PHASE-E PA PEOPLE + +169D2 +BAMUM LETTER PHASE-E FU CALL + +169D3 +BAMUM LETTER PHASE-E FOM + +169D4 +BAMUM LETTER PHASE-E NJEE + +169D5 +BAMUM LETTER PHASE-E A + +169D6 +BAMUM LETTER PHASE-E TOQ + +169D7 +BAMUM LETTER PHASE-E O + +169D8 +BAMUM LETTER PHASE-E I + +169D9 +BAMUM LETTER PHASE-E LAQ + +169DA +BAMUM LETTER PHASE-E PA PLURAL + +169DB +BAMUM LETTER PHASE-E TAA + +169DC +BAMUM LETTER PHASE-E TAQ + +169DD +BAMUM LETTER PHASE-E NDAA MY HOUSE + +169DE +BAMUM LETTER PHASE-E SHIQ + +169DF +BAMUM LETTER PHASE-E YEUX + +169E0 +BAMUM LETTER PHASE-E NGUAE + +169E1 +BAMUM LETTER PHASE-E YUAEN + +169E2 +BAMUM LETTER PHASE-E YOQ SWIMMING + +169E3 +BAMUM LETTER PHASE-E YOQ COVER + +169E4 +BAMUM LETTER PHASE-E YUQ + +169E5 +BAMUM LETTER PHASE-E YUN + +169E6 +BAMUM LETTER PHASE-E KEUX + +169E7 +BAMUM LETTER PHASE-E PEUX + +169E8 +BAMUM LETTER PHASE-E NJEE EPOCH + +169E9 +BAMUM LETTER PHASE-E PUE + +169EA +BAMUM LETTER PHASE-E WUE + +169EB +BAMUM LETTER PHASE-E FEE + +169EC +BAMUM LETTER PHASE-E VEE + +169ED +BAMUM LETTER PHASE-E LU + +169EE +BAMUM LETTER PHASE-E MI + +169EF +BAMUM LETTER PHASE-E REUX + +169F0 +BAMUM LETTER PHASE-E RAE + +169F1 +BAMUM LETTER PHASE-E NGUAET + +169F2 +BAMUM LETTER PHASE-E NGA + +169F3 +BAMUM LETTER PHASE-E SHO + +169F4 +BAMUM LETTER PHASE-E SHOQ + +169F5 +BAMUM LETTER PHASE-E FU REMEDY + +169F6 +BAMUM LETTER PHASE-E NA + +169F7 +BAMUM LETTER PHASE-E PI + +169F8 +BAMUM LETTER PHASE-E LOQ + +169F9 +BAMUM LETTER PHASE-E KO + +169FA +BAMUM LETTER PHASE-E MEN + +169FB +BAMUM LETTER PHASE-E MA + +169FC +BAMUM LETTER PHASE-E MAQ + +169FD +BAMUM LETTER PHASE-E TEU + +169FE +BAMUM LETTER PHASE-E KI + +169FF +BAMUM LETTER PHASE-E MON + +16A00 +BAMUM LETTER PHASE-E TEN + +16A01 +BAMUM LETTER PHASE-E FAQ + +16A02 +BAMUM LETTER PHASE-E GHOM + +16A03 +BAMUM LETTER PHASE-F KA + +16A04 +BAMUM LETTER PHASE-F U + +16A05 +BAMUM LETTER PHASE-F KU + +16A06 +BAMUM LETTER PHASE-F EE + +16A07 +BAMUM LETTER PHASE-F REE + +16A08 +BAMUM LETTER PHASE-F TAE + +16A09 +BAMUM LETTER PHASE-F NYI + +16A0A +BAMUM LETTER PHASE-F LA + +16A0B +BAMUM LETTER PHASE-F RII + +16A0C +BAMUM LETTER PHASE-F RIEE + +16A0D +BAMUM LETTER PHASE-F MEEEE + +16A0E +BAMUM LETTER PHASE-F TAA + +16A0F +BAMUM LETTER PHASE-F NDAA + +16A10 +BAMUM LETTER PHASE-F NJAEM + +16A11 +BAMUM LETTER PHASE-F M + +16A12 +BAMUM LETTER PHASE-F SUU + +16A13 +BAMUM LETTER PHASE-F SHII + +16A14 +BAMUM LETTER PHASE-F SI + +16A15 +BAMUM LETTER PHASE-F SEUX + +16A16 +BAMUM LETTER PHASE-F KYEE + +16A17 +BAMUM LETTER PHASE-F KET + +16A18 +BAMUM LETTER PHASE-F NUAE + +16A19 +BAMUM LETTER PHASE-F NU + +16A1A +BAMUM LETTER PHASE-F NJUAE + +16A1B +BAMUM LETTER PHASE-F YOQ + +16A1C +BAMUM LETTER PHASE-F SHU + +16A1D +BAMUM LETTER PHASE-F YA + +16A1E +BAMUM LETTER PHASE-F NSHA + +16A1F +BAMUM LETTER PHASE-F PEUX + +16A20 +BAMUM LETTER PHASE-F NTEE + +16A21 +BAMUM LETTER PHASE-F WUE + +16A22 +BAMUM LETTER PHASE-F PEE + +16A23 +BAMUM LETTER PHASE-F RU + +16A24 +BAMUM LETTER PHASE-F NI + +16A25 +BAMUM LETTER PHASE-F REUX + +16A26 +BAMUM LETTER PHASE-F KEN + +16A27 +BAMUM LETTER PHASE-F NGKWAEN + +16A28 +BAMUM LETTER PHASE-F NGGA + +16A29 +BAMUM LETTER PHASE-F SHO + +16A2A +BAMUM LETTER PHASE-F PUAE + +16A2B +BAMUM LETTER PHASE-F FOM + +16A2C +BAMUM LETTER PHASE-F WA + +16A2D +BAMUM LETTER PHASE-F LI + +16A2E +BAMUM LETTER PHASE-F LOQ + +16A2F +BAMUM LETTER PHASE-F KO + +16A30 +BAMUM LETTER PHASE-F MBEN + +16A31 +BAMUM LETTER PHASE-F REN + +16A32 +BAMUM LETTER PHASE-F MA + +16A33 +BAMUM LETTER PHASE-F MO + +16A34 +BAMUM LETTER PHASE-F MBAA + +16A35 +BAMUM LETTER PHASE-F TET + +16A36 +BAMUM LETTER PHASE-F KPA + +16A37 +BAMUM LETTER PHASE-F SAMBA + +16A38 +BAMUM LETTER PHASE-F VUEQ + +16A40 +MRO LETTER TA + +16A41 +MRO LETTER NGI + +16A42 +MRO LETTER YO + +16A43 +MRO LETTER MIM + +16A44 +MRO LETTER BA + +16A45 +MRO LETTER DA + +16A46 +MRO LETTER A + +16A47 +MRO LETTER PHI + +16A48 +MRO LETTER KHAI + +16A49 +MRO LETTER HAO + +16A4A +MRO LETTER DAI + +16A4B +MRO LETTER CHU + +16A4C +MRO LETTER KEAAE + +16A4D +MRO LETTER OL + +16A4E +MRO LETTER MAEM + +16A4F +MRO LETTER NIN + +16A50 +MRO LETTER PA + +16A51 +MRO LETTER OO + +16A52 +MRO LETTER O + +16A53 +MRO LETTER RO + +16A54 +MRO LETTER SHI + +16A55 +MRO LETTER THEA + +16A56 +MRO LETTER EA + +16A57 +MRO LETTER WA + +16A58 +MRO LETTER E + +16A59 +MRO LETTER KO + +16A5A +MRO LETTER LAN + +16A5B +MRO LETTER LA + +16A5C +MRO LETTER HAI + +16A5D +MRO LETTER RI + +16A5E +MRO LETTER TEK + +16A60 +MRO DIGIT ZERO + +16A61 +MRO DIGIT ONE + +16A62 +MRO DIGIT TWO + +16A63 +MRO DIGIT THREE + +16A64 +MRO DIGIT FOUR + +16A65 +MRO DIGIT FIVE + +16A66 +MRO DIGIT SIX + +16A67 +MRO DIGIT SEVEN + +16A68 +MRO DIGIT EIGHT + +16A69 +MRO DIGIT NINE + +16A6E +MRO DANDA + +16A6F +MRO DOUBLE DANDA + +16A70 +TANGSA LETTER OZ + +16A71 +TANGSA LETTER OC + +16A72 +TANGSA LETTER OQ + +16A73 +TANGSA LETTER OX + +16A74 +TANGSA LETTER AZ + +16A75 +TANGSA LETTER AC + +16A76 +TANGSA LETTER AQ + +16A77 +TANGSA LETTER AX + +16A78 +TANGSA LETTER VZ + +16A79 +TANGSA LETTER VC + +16A7A +TANGSA LETTER VQ + +16A7B +TANGSA LETTER VX + +16A7C +TANGSA LETTER EZ + +16A7D +TANGSA LETTER EC + +16A7E +TANGSA LETTER EQ + +16A7F +TANGSA LETTER EX + +16A80 +TANGSA LETTER IZ + +16A81 +TANGSA LETTER IC + +16A82 +TANGSA LETTER IQ + +16A83 +TANGSA LETTER IX + +16A84 +TANGSA LETTER UZ + +16A85 +TANGSA LETTER UC + +16A86 +TANGSA LETTER UQ + +16A87 +TANGSA LETTER UX + +16A88 +TANGSA LETTER AWZ + +16A89 +TANGSA LETTER AWC + +16A8A +TANGSA LETTER AWQ + +16A8B +TANGSA LETTER AWX + +16A8C +TANGSA LETTER UIZ + +16A8D +TANGSA LETTER UIC + +16A8E +TANGSA LETTER UIQ + +16A8F +TANGSA LETTER UIX + +16A90 +TANGSA LETTER FINAL NG + +16A91 +TANGSA LETTER LONG UEX + +16A92 +TANGSA LETTER SHORT UEZ + +16A93 +TANGSA LETTER SHORT AWX + +16A94 +TANGSA LETTER UEC + +16A95 +TANGSA LETTER UEZ + +16A96 +TANGSA LETTER UEQ + +16A97 +TANGSA LETTER UEX + +16A98 +TANGSA LETTER UIUZ + +16A99 +TANGSA LETTER UIUC + +16A9A +TANGSA LETTER UIUQ + +16A9B +TANGSA LETTER UIUX + +16A9C +TANGSA LETTER MZ + +16A9D +TANGSA LETTER MC + +16A9E +TANGSA LETTER MQ + +16A9F +TANGSA LETTER MX + +16AA0 +TANGSA LETTER KA + +16AA1 +TANGSA LETTER KHA + +16AA2 +TANGSA LETTER GA + +16AA3 +TANGSA LETTER NGA + +16AA4 +TANGSA LETTER SA + +16AA5 +TANGSA LETTER YA + +16AA6 +TANGSA LETTER WA + +16AA7 +TANGSA LETTER PA + +16AA8 +TANGSA LETTER NYA + +16AA9 +TANGSA LETTER PHA + +16AAA +TANGSA LETTER BA + +16AAB +TANGSA LETTER MA + +16AAC +TANGSA LETTER NA + +16AAD +TANGSA LETTER HA + +16AAE +TANGSA LETTER LA + +16AAF +TANGSA LETTER HTA + +16AB0 +TANGSA LETTER TA + +16AB1 +TANGSA LETTER DA + +16AB2 +TANGSA LETTER RA + +16AB3 +TANGSA LETTER NHA + +16AB4 +TANGSA LETTER SHA + +16AB5 +TANGSA LETTER CA + +16AB6 +TANGSA LETTER TSA + +16AB7 +TANGSA LETTER GHA + +16AB8 +TANGSA LETTER HTTA + +16AB9 +TANGSA LETTER THA + +16ABA +TANGSA LETTER XA + +16ABB +TANGSA LETTER FA + +16ABC +TANGSA LETTER DHA + +16ABD +TANGSA LETTER CHA + +16ABE +TANGSA LETTER ZA + +16AC0 +TANGSA DIGIT ZERO + +16AC1 +TANGSA DIGIT ONE + +16AC2 +TANGSA DIGIT TWO + +16AC3 +TANGSA DIGIT THREE + +16AC4 +TANGSA DIGIT FOUR + +16AC5 +TANGSA DIGIT FIVE + +16AC6 +TANGSA DIGIT SIX + +16AC7 +TANGSA DIGIT SEVEN + +16AC8 +TANGSA DIGIT EIGHT + +16AC9 +TANGSA DIGIT NINE + +16AD0 +BASSA VAH LETTER ENNI + +16AD1 +BASSA VAH LETTER KA + +16AD2 +BASSA VAH LETTER SE + +16AD3 +BASSA VAH LETTER FA + +16AD4 +BASSA VAH LETTER MBE + +16AD5 +BASSA VAH LETTER YIE + +16AD6 +BASSA VAH LETTER GAH + +16AD7 +BASSA VAH LETTER DHII + +16AD8 +BASSA VAH LETTER KPAH + +16AD9 +BASSA VAH LETTER JO + +16ADA +BASSA VAH LETTER HWAH + +16ADB +BASSA VAH LETTER WA + +16ADC +BASSA VAH LETTER ZO + +16ADD +BASSA VAH LETTER GBU + +16ADE +BASSA VAH LETTER DO + +16ADF +BASSA VAH LETTER CE + +16AE0 +BASSA VAH LETTER UWU + +16AE1 +BASSA VAH LETTER TO + +16AE2 +BASSA VAH LETTER BA + +16AE3 +BASSA VAH LETTER VU + +16AE4 +BASSA VAH LETTER YEIN + +16AE5 +BASSA VAH LETTER PA + +16AE6 +BASSA VAH LETTER WADDA + +16AE7 +BASSA VAH LETTER A + +16AE8 +BASSA VAH LETTER O + +16AE9 +BASSA VAH LETTER OO + +16AEA +BASSA VAH LETTER U + +16AEB +BASSA VAH LETTER EE + +16AEC +BASSA VAH LETTER E + +16AED +BASSA VAH LETTER I + +16AF0 +BASSA VAH COMBINING HIGH TONE + +16AF1 +BASSA VAH COMBINING LOW TONE + +16AF2 +BASSA VAH COMBINING MID TONE + +16AF3 +BASSA VAH COMBINING LOW-MID TONE + +16AF4 +BASSA VAH COMBINING HIGH-LOW TONE + +16AF5 +BASSA VAH FULL STOP + +16B00 +PAHAWH HMONG VOWEL KEEB + +16B01 +PAHAWH HMONG VOWEL KEEV + +16B02 +PAHAWH HMONG VOWEL KIB + +16B03 +PAHAWH HMONG VOWEL KIV + +16B04 +PAHAWH HMONG VOWEL KAUB + +16B05 +PAHAWH HMONG VOWEL KAUV + +16B06 +PAHAWH HMONG VOWEL KUB + +16B07 +PAHAWH HMONG VOWEL KUV + +16B08 +PAHAWH HMONG VOWEL KEB + +16B09 +PAHAWH HMONG VOWEL KEV + +16B0A +PAHAWH HMONG VOWEL KAIB + +16B0B +PAHAWH HMONG VOWEL KAIV + +16B0C +PAHAWH HMONG VOWEL KOOB + +16B0D +PAHAWH HMONG VOWEL KOOV + +16B0E +PAHAWH HMONG VOWEL KAWB + +16B0F +PAHAWH HMONG VOWEL KAWV + +16B10 +PAHAWH HMONG VOWEL KUAB + +16B11 +PAHAWH HMONG VOWEL KUAV + +16B12 +PAHAWH HMONG VOWEL KOB + +16B13 +PAHAWH HMONG VOWEL KOV + +16B14 +PAHAWH HMONG VOWEL KIAB + +16B15 +PAHAWH HMONG VOWEL KIAV + +16B16 +PAHAWH HMONG VOWEL KAB + +16B17 +PAHAWH HMONG VOWEL KAV + +16B18 +PAHAWH HMONG VOWEL KWB + +16B19 +PAHAWH HMONG VOWEL KWV + +16B1A +PAHAWH HMONG VOWEL KAAB + +16B1B +PAHAWH HMONG VOWEL KAAV + +16B1C +PAHAWH HMONG CONSONANT VAU + +16B1D +PAHAWH HMONG CONSONANT NTSAU + +16B1E +PAHAWH HMONG CONSONANT LAU + +16B1F +PAHAWH HMONG CONSONANT HAU + +16B20 +PAHAWH HMONG CONSONANT NLAU + +16B21 +PAHAWH HMONG CONSONANT RAU + +16B22 +PAHAWH HMONG CONSONANT NKAU + +16B23 +PAHAWH HMONG CONSONANT QHAU + +16B24 +PAHAWH HMONG CONSONANT YAU + +16B25 +PAHAWH HMONG CONSONANT HLAU + +16B26 +PAHAWH HMONG CONSONANT MAU + +16B27 +PAHAWH HMONG CONSONANT CHAU + +16B28 +PAHAWH HMONG CONSONANT NCHAU + +16B29 +PAHAWH HMONG CONSONANT HNAU + +16B2A +PAHAWH HMONG CONSONANT PLHAU + +16B2B +PAHAWH HMONG CONSONANT NTHAU + +16B2C +PAHAWH HMONG CONSONANT NAU + +16B2D +PAHAWH HMONG CONSONANT AU + +16B2E +PAHAWH HMONG CONSONANT XAU + +16B2F +PAHAWH HMONG CONSONANT CAU + +16B30 +PAHAWH HMONG MARK CIM TUB + +16B31 +PAHAWH HMONG MARK CIM SO + +16B32 +PAHAWH HMONG MARK CIM KES + +16B33 +PAHAWH HMONG MARK CIM KHAV + +16B34 +PAHAWH HMONG MARK CIM SUAM + +16B35 +PAHAWH HMONG MARK CIM HOM + +16B36 +PAHAWH HMONG MARK CIM TAUM + +16B37 +PAHAWH HMONG SIGN VOS THOM + +16B38 +PAHAWH HMONG SIGN VOS TSHAB CEEB + +16B39 +PAHAWH HMONG SIGN CIM CHEEM + +16B3A +PAHAWH HMONG SIGN VOS THIAB + +16B3B +PAHAWH HMONG SIGN VOS FEEM + +16B3C +PAHAWH HMONG SIGN XYEEM NTXIV + +16B3D +PAHAWH HMONG SIGN XYEEM RHO + +16B3E +PAHAWH HMONG SIGN XYEEM TOV + +16B3F +PAHAWH HMONG SIGN XYEEM FAIB + +16B40 +PAHAWH HMONG SIGN VOS SEEV + +16B41 +PAHAWH HMONG SIGN MEEJ SUAB + +16B42 +PAHAWH HMONG SIGN VOS NRUA + +16B43 +PAHAWH HMONG SIGN IB YAM + +16B44 +PAHAWH HMONG SIGN XAUS + +16B45 +PAHAWH HMONG SIGN CIM TSOV ROG + +16B50 +PAHAWH HMONG DIGIT ZERO + +16B51 +PAHAWH HMONG DIGIT ONE + +16B52 +PAHAWH HMONG DIGIT TWO + +16B53 +PAHAWH HMONG DIGIT THREE + +16B54 +PAHAWH HMONG DIGIT FOUR + +16B55 +PAHAWH HMONG DIGIT FIVE + +16B56 +PAHAWH HMONG DIGIT SIX + +16B57 +PAHAWH HMONG DIGIT SEVEN + +16B58 +PAHAWH HMONG DIGIT EIGHT + +16B59 +PAHAWH HMONG DIGIT NINE + +16B5B +PAHAWH HMONG NUMBER TENS + +16B5C +PAHAWH HMONG NUMBER HUNDREDS + +16B5D +PAHAWH HMONG NUMBER TEN THOUSANDS + +16B5E +PAHAWH HMONG NUMBER MILLIONS + +16B5F +PAHAWH HMONG NUMBER HUNDRED MILLIONS + +16B60 +PAHAWH HMONG NUMBER TEN BILLIONS + +16B61 +PAHAWH HMONG NUMBER TRILLIONS + +16B63 +PAHAWH HMONG SIGN VOS LUB + +16B64 +PAHAWH HMONG SIGN XYOO + +16B65 +PAHAWH HMONG SIGN HLI + +16B66 +PAHAWH HMONG SIGN THIRD-STAGE HLI + +16B67 +PAHAWH HMONG SIGN ZWJ THAJ + +16B68 +PAHAWH HMONG SIGN HNUB + +16B69 +PAHAWH HMONG SIGN NQIG + +16B6A +PAHAWH HMONG SIGN XIAB + +16B6B +PAHAWH HMONG SIGN NTUJ + +16B6C +PAHAWH HMONG SIGN AV + +16B6D +PAHAWH HMONG SIGN TXHEEJ CEEV + +16B6E +PAHAWH HMONG SIGN MEEJ TSEEB + +16B6F +PAHAWH HMONG SIGN TAU + +16B70 +PAHAWH HMONG SIGN LOS + +16B71 +PAHAWH HMONG SIGN MUS + +16B72 +PAHAWH HMONG SIGN CIM HAIS LUS NTOG NTOG + +16B73 +PAHAWH HMONG SIGN CIM CUAM TSHOOJ + +16B74 +PAHAWH HMONG SIGN CIM TXWV + +16B75 +PAHAWH HMONG SIGN CIM TXWV CHWV + +16B76 +PAHAWH HMONG SIGN CIM PUB DAWB + +16B77 +PAHAWH HMONG SIGN CIM NRES TOS + +16B7D +PAHAWH HMONG CLAN SIGN TSHEEJ + +16B7E +PAHAWH HMONG CLAN SIGN YEEG + +16B7F +PAHAWH HMONG CLAN SIGN LIS + +16B80 +PAHAWH HMONG CLAN SIGN LAUJ + +16B81 +PAHAWH HMONG CLAN SIGN XYOOJ + +16B82 +PAHAWH HMONG CLAN SIGN KOO + +16B83 +PAHAWH HMONG CLAN SIGN HAWJ + +16B84 +PAHAWH HMONG CLAN SIGN MUAS + +16B85 +PAHAWH HMONG CLAN SIGN THOJ + +16B86 +PAHAWH HMONG CLAN SIGN TSAB + +16B87 +PAHAWH HMONG CLAN SIGN PHAB + +16B88 +PAHAWH HMONG CLAN SIGN KHAB + +16B89 +PAHAWH HMONG CLAN SIGN HAM + +16B8A +PAHAWH HMONG CLAN SIGN VAJ + +16B8B +PAHAWH HMONG CLAN SIGN FAJ + +16B8C +PAHAWH HMONG CLAN SIGN YAJ + +16B8D +PAHAWH HMONG CLAN SIGN TSWB + +16B8E +PAHAWH HMONG CLAN SIGN KWM + +16B8F +PAHAWH HMONG CLAN SIGN VWJ + +16D40 +KIRAT RAI SIGN ANUSVARA + +16D41 +KIRAT RAI SIGN TONPI + +16D42 +KIRAT RAI SIGN VISARGA + +16D43 +KIRAT RAI LETTER A + +16D44 +KIRAT RAI LETTER KA + +16D45 +KIRAT RAI LETTER KHA + +16D46 +KIRAT RAI LETTER GA + +16D47 +KIRAT RAI LETTER GHA + +16D48 +KIRAT RAI LETTER NGA + +16D49 +KIRAT RAI LETTER CA + +16D4A +KIRAT RAI LETTER CHA + +16D4B +KIRAT RAI LETTER JA + +16D4C +KIRAT RAI LETTER JHA + +16D4D +KIRAT RAI LETTER NYA + +16D4E +KIRAT RAI LETTER TTA + +16D4F +KIRAT RAI LETTER TTHA + +16D50 +KIRAT RAI LETTER DDA + +16D51 +KIRAT RAI LETTER DDHA + +16D52 +KIRAT RAI LETTER TA + +16D53 +KIRAT RAI LETTER THA + +16D54 +KIRAT RAI LETTER DA + +16D55 +KIRAT RAI LETTER DHA + +16D56 +KIRAT RAI LETTER NA + +16D57 +KIRAT RAI LETTER PA + +16D58 +KIRAT RAI LETTER PHA + +16D59 +KIRAT RAI LETTER BA + +16D5A +KIRAT RAI LETTER BHA + +16D5B +KIRAT RAI LETTER MA + +16D5C +KIRAT RAI LETTER YA + +16D5D +KIRAT RAI LETTER RA + +16D5E +KIRAT RAI LETTER LA + +16D5F +KIRAT RAI LETTER VA + +16D60 +KIRAT RAI LETTER SA + +16D61 +KIRAT RAI LETTER SHA + +16D62 +KIRAT RAI LETTER HA + +16D63 +KIRAT RAI VOWEL SIGN AA + +16D64 +KIRAT RAI VOWEL SIGN I + +16D65 +KIRAT RAI VOWEL SIGN U + +16D66 +KIRAT RAI VOWEL SIGN UE + +16D67 +KIRAT RAI VOWEL SIGN E + +16D68 +KIRAT RAI VOWEL SIGN AI + +16D69 +KIRAT RAI VOWEL SIGN O + +16D6A +KIRAT RAI VOWEL SIGN AU + +16D6B +KIRAT RAI SIGN VIRAMA + +16D6C +KIRAT RAI SIGN SAAT + +16D6D +KIRAT RAI SIGN YUPI + +16D6E +KIRAT RAI DANDA + +16D6F +KIRAT RAI DOUBLE DANDA + +16D70 +KIRAT RAI DIGIT ZERO + +16D71 +KIRAT RAI DIGIT ONE + +16D72 +KIRAT RAI DIGIT TWO + +16D73 +KIRAT RAI DIGIT THREE + +16D74 +KIRAT RAI DIGIT FOUR + +16D75 +KIRAT RAI DIGIT FIVE + +16D76 +KIRAT RAI DIGIT SIX + +16D77 +KIRAT RAI DIGIT SEVEN + +16D78 +KIRAT RAI DIGIT EIGHT + +16D79 +KIRAT RAI DIGIT NINE + +16E40 +MEDEFAIDRIN CAPITAL LETTER M + +16E41 +MEDEFAIDRIN CAPITAL LETTER S + +16E42 +MEDEFAIDRIN CAPITAL LETTER V + +16E43 +MEDEFAIDRIN CAPITAL LETTER W + +16E44 +MEDEFAIDRIN CAPITAL LETTER ATIU + +16E45 +MEDEFAIDRIN CAPITAL LETTER Z + +16E46 +MEDEFAIDRIN CAPITAL LETTER KP + +16E47 +MEDEFAIDRIN CAPITAL LETTER P + +16E48 +MEDEFAIDRIN CAPITAL LETTER T + +16E49 +MEDEFAIDRIN CAPITAL LETTER G + +16E4A +MEDEFAIDRIN CAPITAL LETTER F + +16E4B +MEDEFAIDRIN CAPITAL LETTER I + +16E4C +MEDEFAIDRIN CAPITAL LETTER K + +16E4D +MEDEFAIDRIN CAPITAL LETTER A + +16E4E +MEDEFAIDRIN CAPITAL LETTER J + +16E4F +MEDEFAIDRIN CAPITAL LETTER E + +16E50 +MEDEFAIDRIN CAPITAL LETTER B + +16E51 +MEDEFAIDRIN CAPITAL LETTER C + +16E52 +MEDEFAIDRIN CAPITAL LETTER U + +16E53 +MEDEFAIDRIN CAPITAL LETTER YU + +16E54 +MEDEFAIDRIN CAPITAL LETTER L + +16E55 +MEDEFAIDRIN CAPITAL LETTER Q + +16E56 +MEDEFAIDRIN CAPITAL LETTER H + +16E56 +MEDEFAIDRIN CAPITAL LETTER HP + +16E57 +MEDEFAIDRIN CAPITAL LETTER NG + +16E57 +MEDEFAIDRIN CAPITAL LETTER NY + +16E58 +MEDEFAIDRIN CAPITAL LETTER X + +16E59 +MEDEFAIDRIN CAPITAL LETTER D + +16E5A +MEDEFAIDRIN CAPITAL LETTER OE + +16E5B +MEDEFAIDRIN CAPITAL LETTER N + +16E5C +MEDEFAIDRIN CAPITAL LETTER R + +16E5D +MEDEFAIDRIN CAPITAL LETTER O + +16E5E +MEDEFAIDRIN CAPITAL LETTER AI + +16E5F +MEDEFAIDRIN CAPITAL LETTER Y + +16E60 +MEDEFAIDRIN SMALL LETTER M + +16E61 +MEDEFAIDRIN SMALL LETTER S + +16E62 +MEDEFAIDRIN SMALL LETTER V + +16E63 +MEDEFAIDRIN SMALL LETTER W + +16E64 +MEDEFAIDRIN SMALL LETTER ATIU + +16E65 +MEDEFAIDRIN SMALL LETTER Z + +16E66 +MEDEFAIDRIN SMALL LETTER KP + +16E67 +MEDEFAIDRIN SMALL LETTER P + +16E68 +MEDEFAIDRIN SMALL LETTER T + +16E69 +MEDEFAIDRIN SMALL LETTER G + +16E6A +MEDEFAIDRIN SMALL LETTER F + +16E6B +MEDEFAIDRIN SMALL LETTER I + +16E6C +MEDEFAIDRIN SMALL LETTER K + +16E6D +MEDEFAIDRIN SMALL LETTER A + +16E6E +MEDEFAIDRIN SMALL LETTER J + +16E6F +MEDEFAIDRIN SMALL LETTER E + +16E70 +MEDEFAIDRIN SMALL LETTER B + +16E71 +MEDEFAIDRIN SMALL LETTER C + +16E72 +MEDEFAIDRIN SMALL LETTER U + +16E73 +MEDEFAIDRIN SMALL LETTER YU + +16E74 +MEDEFAIDRIN SMALL LETTER L + +16E75 +MEDEFAIDRIN SMALL LETTER Q + +16E76 +MEDEFAIDRIN SMALL LETTER H + +16E76 +MEDEFAIDRIN SMALL LETTER HP + +16E77 +MEDEFAIDRIN SMALL LETTER NG + +16E77 +MEDEFAIDRIN SMALL LETTER NY + +16E78 +MEDEFAIDRIN SMALL LETTER X + +16E79 +MEDEFAIDRIN SMALL LETTER D + +16E7A +MEDEFAIDRIN SMALL LETTER OE + +16E7B +MEDEFAIDRIN SMALL LETTER N + +16E7C +MEDEFAIDRIN SMALL LETTER R + +16E7D +MEDEFAIDRIN SMALL LETTER O + +16E7E +MEDEFAIDRIN SMALL LETTER AI + +16E7F +MEDEFAIDRIN SMALL LETTER Y + +16E80 +MEDEFAIDRIN DIGIT ZERO + +16E81 +MEDEFAIDRIN DIGIT ONE + +16E82 +MEDEFAIDRIN DIGIT TWO + +16E83 +MEDEFAIDRIN DIGIT THREE + +16E84 +MEDEFAIDRIN DIGIT FOUR + +16E85 +MEDEFAIDRIN DIGIT FIVE + +16E86 +MEDEFAIDRIN DIGIT SIX + +16E87 +MEDEFAIDRIN DIGIT SEVEN + +16E88 +MEDEFAIDRIN DIGIT EIGHT + +16E89 +MEDEFAIDRIN DIGIT NINE + +16E8A +MEDEFAIDRIN NUMBER TEN + +16E8B +MEDEFAIDRIN NUMBER ELEVEN + +16E8C +MEDEFAIDRIN NUMBER TWELVE + +16E8D +MEDEFAIDRIN NUMBER THIRTEEN + +16E8E +MEDEFAIDRIN NUMBER FOURTEEN + +16E8F +MEDEFAIDRIN NUMBER FIFTEEN + +16E90 +MEDEFAIDRIN NUMBER SIXTEEN + +16E91 +MEDEFAIDRIN NUMBER SEVENTEEN + +16E92 +MEDEFAIDRIN NUMBER EIGHTEEN + +16E93 +MEDEFAIDRIN NUMBER NINETEEN + +16E94 +MEDEFAIDRIN DIGIT ONE ALTERNATE FORM + +16E95 +MEDEFAIDRIN DIGIT TWO ALTERNATE FORM + +16E96 +MEDEFAIDRIN DIGIT THREE ALTERNATE FORM + +16E97 +MEDEFAIDRIN COMMA + +16E98 +MEDEFAIDRIN FULL STOP + +16E99 +MEDEFAIDRIN SYMBOL AIVA + +16E9A +MEDEFAIDRIN EXCLAMATION OH + +16EA0 +BERIA ERFE CAPITAL LETTER ARKAB + +16EA1 +BERIA ERFE CAPITAL LETTER BASIGNA + +16EA2 +BERIA ERFE CAPITAL LETTER DARBAI + +16EA3 +BERIA ERFE CAPITAL LETTER EH + +16EA4 +BERIA ERFE CAPITAL LETTER FITKO + +16EA5 +BERIA ERFE CAPITAL LETTER GOWAY + +16EA6 +BERIA ERFE CAPITAL LETTER HIRDEABO + +16EA7 +BERIA ERFE CAPITAL LETTER I + +16EA8 +BERIA ERFE CAPITAL LETTER DJAI + +16EA9 +BERIA ERFE CAPITAL LETTER KOBO + +16EAA +BERIA ERFE CAPITAL LETTER LAKKO + +16EAB +BERIA ERFE CAPITAL LETTER MERI + +16EAC +BERIA ERFE CAPITAL LETTER NINI + +16EAD +BERIA ERFE CAPITAL LETTER GNA + +16EAE +BERIA ERFE CAPITAL LETTER NGAY + +16EAF +BERIA ERFE CAPITAL LETTER OI + +16EB0 +BERIA ERFE CAPITAL LETTER PI + +16EB1 +BERIA ERFE CAPITAL LETTER ERIGO + +16EB2 +BERIA ERFE CAPITAL LETTER ERIGO TAMURA + +16EB3 +BERIA ERFE CAPITAL LETTER SERI + +16EB4 +BERIA ERFE CAPITAL LETTER SHEP + +16EB5 +BERIA ERFE CAPITAL LETTER TATASOUE + +16EB6 +BERIA ERFE CAPITAL LETTER UI + +16EB7 +BERIA ERFE CAPITAL LETTER WASSE + +16EB8 +BERIA ERFE CAPITAL LETTER AY + +16EBB +BERIA ERFE SMALL LETTER ARKAB + +16EBC +BERIA ERFE SMALL LETTER BASIGNA + +16EBD +BERIA ERFE SMALL LETTER DARBAI + +16EBE +BERIA ERFE SMALL LETTER EH + +16EBF +BERIA ERFE SMALL LETTER FITKO + +16EC0 +BERIA ERFE SMALL LETTER GOWAY + +16EC1 +BERIA ERFE SMALL LETTER HIRDEABO + +16EC2 +BERIA ERFE SMALL LETTER I + +16EC3 +BERIA ERFE SMALL LETTER DJAI + +16EC4 +BERIA ERFE SMALL LETTER KOBO + +16EC5 +BERIA ERFE SMALL LETTER LAKKO + +16EC6 +BERIA ERFE SMALL LETTER MERI + +16EC7 +BERIA ERFE SMALL LETTER NINI + +16EC8 +BERIA ERFE SMALL LETTER GNA + +16EC9 +BERIA ERFE SMALL LETTER NGAY + +16ECA +BERIA ERFE SMALL LETTER OI + +16ECB +BERIA ERFE SMALL LETTER PI + +16ECC +BERIA ERFE SMALL LETTER ERIGO + +16ECD +BERIA ERFE SMALL LETTER ERIGO TAMURA + +16ECE +BERIA ERFE SMALL LETTER SERI + +16ECF +BERIA ERFE SMALL LETTER SHEP + +16ED0 +BERIA ERFE SMALL LETTER TATASOUE + +16ED1 +BERIA ERFE SMALL LETTER UI + +16ED2 +BERIA ERFE SMALL LETTER WASSE + +16ED3 +BERIA ERFE SMALL LETTER AY + +16F00 +MIAO LETTER PA + +16F01 +MIAO LETTER BA + +16F02 +MIAO LETTER YI PA + +16F03 +MIAO LETTER PLA + +16F04 +MIAO LETTER MA + +16F05 +MIAO LETTER MHA + +16F06 +MIAO LETTER ARCHAIC MA + +16F07 +MIAO LETTER FA + +16F08 +MIAO LETTER VA + +16F09 +MIAO LETTER VFA + +16F0A +MIAO LETTER TA + +16F0B +MIAO LETTER DA + +16F0C +MIAO LETTER YI TTA + +16F0D +MIAO LETTER YI TA + +16F0E +MIAO LETTER TTA + +16F0F +MIAO LETTER DDA + +16F10 +MIAO LETTER NA + +16F11 +MIAO LETTER NHA + +16F12 +MIAO LETTER YI NNA + +16F13 +MIAO LETTER ARCHAIC NA + +16F14 +MIAO LETTER NNA + +16F15 +MIAO LETTER NNHA + +16F16 +MIAO LETTER LA + +16F17 +MIAO LETTER LYA + +16F18 +MIAO LETTER LHA + +16F19 +MIAO LETTER LHYA + +16F1A +MIAO LETTER TLHA + +16F1B +MIAO LETTER DLHA + +16F1C +MIAO LETTER TLHYA + +16F1D +MIAO LETTER DLHYA + +16F1E +MIAO LETTER KA + +16F1F +MIAO LETTER GA + +16F20 +MIAO LETTER YI KA + +16F21 +MIAO LETTER QA + +16F22 +MIAO LETTER QGA + +16F23 +MIAO LETTER NGA + +16F24 +MIAO LETTER NGHA + +16F25 +MIAO LETTER ARCHAIC NGA + +16F26 +MIAO LETTER HA + +16F27 +MIAO LETTER XA + +16F28 +MIAO LETTER GHA + +16F29 +MIAO LETTER GHHA + +16F2A +MIAO LETTER TSSA + +16F2B +MIAO LETTER DZZA + +16F2C +MIAO LETTER NYA + +16F2D +MIAO LETTER NYHA + +16F2E +MIAO LETTER TSHA + +16F2F +MIAO LETTER DZHA + +16F30 +MIAO LETTER YI TSHA + +16F31 +MIAO LETTER YI DZHA + +16F32 +MIAO LETTER REFORMED TSHA + +16F33 +MIAO LETTER SHA + +16F34 +MIAO LETTER SSA + +16F35 +MIAO LETTER ZHA + +16F36 +MIAO LETTER ZSHA + +16F37 +MIAO LETTER TSA + +16F38 +MIAO LETTER DZA + +16F39 +MIAO LETTER YI TSA + +16F3A +MIAO LETTER SA + +16F3B +MIAO LETTER ZA + +16F3C +MIAO LETTER ZSA + +16F3D +MIAO LETTER ZZA + +16F3E +MIAO LETTER ZZSA + +16F3F +MIAO LETTER ARCHAIC ZZA + +16F40 +MIAO LETTER ZZYA + +16F41 +MIAO LETTER ZZSYA + +16F42 +MIAO LETTER WA + +16F43 +MIAO LETTER AH + +16F44 +MIAO LETTER HHA + +16F45 +MIAO LETTER BRI + +16F46 +MIAO LETTER SYI + +16F47 +MIAO LETTER DZYI + +16F48 +MIAO LETTER TE + +16F49 +MIAO LETTER TSE + +16F4A +MIAO LETTER RTE + +16F4F +MIAO SIGN CONSONANT MODIFIER BAR + +16F50 +MIAO LETTER NASALIZATION + +16F51 +MIAO SIGN ASPIRATION + +16F52 +MIAO SIGN REFORMED VOICING + +16F53 +MIAO SIGN REFORMED ASPIRATION + +16F54 +MIAO VOWEL SIGN A + +16F55 +MIAO VOWEL SIGN AA + +16F56 +MIAO VOWEL SIGN AHH + +16F57 +MIAO VOWEL SIGN AN + +16F58 +MIAO VOWEL SIGN ANG + +16F59 +MIAO VOWEL SIGN O + +16F5A +MIAO VOWEL SIGN OO + +16F5B +MIAO VOWEL SIGN WO + +16F5C +MIAO VOWEL SIGN W + +16F5D +MIAO VOWEL SIGN E + +16F5E +MIAO VOWEL SIGN EN + +16F5F +MIAO VOWEL SIGN ENG + +16F60 +MIAO VOWEL SIGN OEY + +16F61 +MIAO VOWEL SIGN I + +16F62 +MIAO VOWEL SIGN IA + +16F63 +MIAO VOWEL SIGN IAN + +16F64 +MIAO VOWEL SIGN IANG + +16F65 +MIAO VOWEL SIGN IO + +16F66 +MIAO VOWEL SIGN IE + +16F67 +MIAO VOWEL SIGN II + +16F68 +MIAO VOWEL SIGN IU + +16F69 +MIAO VOWEL SIGN ING + +16F6A +MIAO VOWEL SIGN U + +16F6B +MIAO VOWEL SIGN UA + +16F6C +MIAO VOWEL SIGN UAN + +16F6D +MIAO VOWEL SIGN UANG + +16F6E +MIAO VOWEL SIGN UU + +16F6F +MIAO VOWEL SIGN UEI + +16F70 +MIAO VOWEL SIGN UNG + +16F71 +MIAO VOWEL SIGN Y + +16F72 +MIAO VOWEL SIGN YI + +16F73 +MIAO VOWEL SIGN AE + +16F74 +MIAO VOWEL SIGN AEE + +16F75 +MIAO VOWEL SIGN ERR + +16F76 +MIAO VOWEL SIGN ROUNDED ERR + +16F77 +MIAO VOWEL SIGN ER + +16F78 +MIAO VOWEL SIGN ROUNDED ER + +16F79 +MIAO VOWEL SIGN AI + +16F7A +MIAO VOWEL SIGN EI + +16F7B +MIAO VOWEL SIGN AU + +16F7C +MIAO VOWEL SIGN OU + +16F7D +MIAO VOWEL SIGN N + +16F7E +MIAO VOWEL SIGN NG + +16F7F +MIAO VOWEL SIGN UOG + +16F80 +MIAO VOWEL SIGN YUI + +16F81 +MIAO VOWEL SIGN OG + +16F82 +MIAO VOWEL SIGN OER + +16F83 +MIAO VOWEL SIGN VW + +16F84 +MIAO VOWEL SIGN IG + +16F85 +MIAO VOWEL SIGN EA + +16F86 +MIAO VOWEL SIGN IONG + +16F87 +MIAO VOWEL SIGN UI + +16F8F +MIAO TONE RIGHT + +16F90 +MIAO TONE TOP RIGHT + +16F91 +MIAO TONE ABOVE + +16F92 +MIAO TONE BELOW + +16F93 +MIAO LETTER TONE-2 + +16F94 +MIAO LETTER TONE-3 + +16F95 +MIAO LETTER TONE-4 + +16F96 +MIAO LETTER TONE-5 + +16F97 +MIAO LETTER TONE-6 + +16F98 +MIAO LETTER TONE-7 + +16F99 +MIAO LETTER TONE-8 + +16F9A +MIAO LETTER REFORMED TONE-1 + +16F9B +MIAO LETTER REFORMED TONE-2 + +16F9C +MIAO LETTER REFORMED TONE-4 + +16F9D +MIAO LETTER REFORMED TONE-5 + +16F9E +MIAO LETTER REFORMED TONE-6 + +16F9F +MIAO LETTER REFORMED TONE-8 + +16FE0 +TANGUT ITERATION MARK + +16FE1 +NUSHU ITERATION MARK + +16FE2 +OLD CHINESE HOOK MARK + +16FE3 +OLD CHINESE ITERATION MARK + +16FE4 +KHITAN SMALL SCRIPT FILLER + +16FF0 +VIETNAMESE ALTERNATE READING MARK CA + +16FF1 +VIETNAMESE ALTERNATE READING MARK NHAY + +16FF2 +CHINESE SMALL SIMPLIFIED ER + +16FF3 +CHINESE SMALL TRADITIONAL ER + +16FF4 +YANGQIN SIGN SLOW ONE BEAT + +16FF5 +YANGQIN SIGN SLOW THREE HALF BEATS + +16FF6 +YANGQIN SIGN SLOW TWO BEATS + +18800 +TANGUT COMPONENT-001 + +18801 +TANGUT COMPONENT-002 + +18802 +TANGUT COMPONENT-003 + +18803 +TANGUT COMPONENT-004 + +18804 +TANGUT COMPONENT-005 + +18805 +TANGUT COMPONENT-006 + +18806 +TANGUT COMPONENT-007 + +18807 +TANGUT COMPONENT-008 + +18808 +TANGUT COMPONENT-009 + +18809 +TANGUT COMPONENT-010 + +1880A +TANGUT COMPONENT-011 + +1880B +TANGUT COMPONENT-012 + +1880C +TANGUT COMPONENT-013 + +1880D +TANGUT COMPONENT-014 + +1880E +TANGUT COMPONENT-015 + +1880F +TANGUT COMPONENT-016 + +18810 +TANGUT COMPONENT-017 + +18811 +TANGUT COMPONENT-018 + +18812 +TANGUT COMPONENT-019 + +18813 +TANGUT COMPONENT-020 + +18814 +TANGUT COMPONENT-021 + +18815 +TANGUT COMPONENT-022 + +18816 +TANGUT COMPONENT-023 + +18817 +TANGUT COMPONENT-024 + +18818 +TANGUT COMPONENT-025 + +18819 +TANGUT COMPONENT-026 + +1881A +TANGUT COMPONENT-027 + +1881B +TANGUT COMPONENT-028 + +1881C +TANGUT COMPONENT-029 + +1881D +TANGUT COMPONENT-030 + +1881E +TANGUT COMPONENT-031 + +1881F +TANGUT COMPONENT-032 + +18820 +TANGUT COMPONENT-033 + +18821 +TANGUT COMPONENT-034 + +18822 +TANGUT COMPONENT-035 + +18823 +TANGUT COMPONENT-036 + +18824 +TANGUT COMPONENT-037 + +18825 +TANGUT COMPONENT-038 + +18826 +TANGUT COMPONENT-039 + +18827 +TANGUT COMPONENT-040 + +18828 +TANGUT COMPONENT-041 + +18829 +TANGUT COMPONENT-042 + +1882A +TANGUT COMPONENT-043 + +1882B +TANGUT COMPONENT-044 + +1882C +TANGUT COMPONENT-045 + +1882D +TANGUT COMPONENT-046 + +1882E +TANGUT COMPONENT-047 + +1882F +TANGUT COMPONENT-048 + +18830 +TANGUT COMPONENT-049 + +18831 +TANGUT COMPONENT-050 + +18832 +TANGUT COMPONENT-051 + +18833 +TANGUT COMPONENT-052 + +18834 +TANGUT COMPONENT-053 + +18835 +TANGUT COMPONENT-054 + +18836 +TANGUT COMPONENT-055 + +18837 +TANGUT COMPONENT-056 + +18838 +TANGUT COMPONENT-057 + +18839 +TANGUT COMPONENT-058 + +1883A +TANGUT COMPONENT-059 + +1883B +TANGUT COMPONENT-060 + +1883C +TANGUT COMPONENT-061 + +1883D +TANGUT COMPONENT-062 + +1883E +TANGUT COMPONENT-063 + +1883F +TANGUT COMPONENT-064 + +18840 +TANGUT COMPONENT-065 + +18841 +TANGUT COMPONENT-066 + +18842 +TANGUT COMPONENT-067 + +18843 +TANGUT COMPONENT-068 + +18844 +TANGUT COMPONENT-069 + +18845 +TANGUT COMPONENT-070 + +18846 +TANGUT COMPONENT-071 + +18847 +TANGUT COMPONENT-072 + +18848 +TANGUT COMPONENT-073 + +18849 +TANGUT COMPONENT-074 + +1884A +TANGUT COMPONENT-075 + +1884B +TANGUT COMPONENT-076 + +1884C +TANGUT COMPONENT-077 + +1884D +TANGUT COMPONENT-078 + +1884E +TANGUT COMPONENT-079 + +1884F +TANGUT COMPONENT-080 + +18850 +TANGUT COMPONENT-081 + +18851 +TANGUT COMPONENT-082 + +18852 +TANGUT COMPONENT-083 + +18853 +TANGUT COMPONENT-084 + +18854 +TANGUT COMPONENT-085 + +18855 +TANGUT COMPONENT-086 + +18856 +TANGUT COMPONENT-087 + +18857 +TANGUT COMPONENT-088 + +18858 +TANGUT COMPONENT-089 + +18859 +TANGUT COMPONENT-090 + +1885A +TANGUT COMPONENT-091 + +1885B +TANGUT COMPONENT-092 + +1885C +TANGUT COMPONENT-093 + +1885D +TANGUT COMPONENT-094 + +1885E +TANGUT COMPONENT-095 + +1885F +TANGUT COMPONENT-096 + +18860 +TANGUT COMPONENT-097 + +18861 +TANGUT COMPONENT-098 + +18862 +TANGUT COMPONENT-099 + +18863 +TANGUT COMPONENT-100 + +18864 +TANGUT COMPONENT-101 + +18865 +TANGUT COMPONENT-102 + +18866 +TANGUT COMPONENT-103 + +18867 +TANGUT COMPONENT-104 + +18868 +TANGUT COMPONENT-105 + +18869 +TANGUT COMPONENT-106 + +1886A +TANGUT COMPONENT-107 + +1886B +TANGUT COMPONENT-108 + +1886C +TANGUT COMPONENT-109 + +1886D +TANGUT COMPONENT-110 + +1886E +TANGUT COMPONENT-111 + +1886F +TANGUT COMPONENT-112 + +18870 +TANGUT COMPONENT-113 + +18871 +TANGUT COMPONENT-114 + +18872 +TANGUT COMPONENT-115 + +18873 +TANGUT COMPONENT-116 + +18874 +TANGUT COMPONENT-117 + +18875 +TANGUT COMPONENT-118 + +18876 +TANGUT COMPONENT-119 + +18877 +TANGUT COMPONENT-120 + +18878 +TANGUT COMPONENT-121 + +18879 +TANGUT COMPONENT-122 + +1887A +TANGUT COMPONENT-123 + +1887B +TANGUT COMPONENT-124 + +1887C +TANGUT COMPONENT-125 + +1887D +TANGUT COMPONENT-126 + +1887E +TANGUT COMPONENT-127 + +1887F +TANGUT COMPONENT-128 + +18880 +TANGUT COMPONENT-129 + +18881 +TANGUT COMPONENT-130 + +18882 +TANGUT COMPONENT-131 + +18883 +TANGUT COMPONENT-132 + +18884 +TANGUT COMPONENT-133 + +18885 +TANGUT COMPONENT-134 + +18886 +TANGUT COMPONENT-135 + +18887 +TANGUT COMPONENT-136 + +18888 +TANGUT COMPONENT-137 + +18889 +TANGUT COMPONENT-138 + +1888A +TANGUT COMPONENT-139 + +1888B +TANGUT COMPONENT-140 + +1888C +TANGUT COMPONENT-141 + +1888D +TANGUT COMPONENT-142 + +1888E +TANGUT COMPONENT-143 + +1888F +TANGUT COMPONENT-144 + +18890 +TANGUT COMPONENT-145 + +18891 +TANGUT COMPONENT-146 + +18892 +TANGUT COMPONENT-147 + +18893 +TANGUT COMPONENT-148 + +18894 +TANGUT COMPONENT-149 + +18895 +TANGUT COMPONENT-150 + +18896 +TANGUT COMPONENT-151 + +18897 +TANGUT COMPONENT-152 + +18898 +TANGUT COMPONENT-153 + +18899 +TANGUT COMPONENT-154 + +1889A +TANGUT COMPONENT-155 + +1889B +TANGUT COMPONENT-156 + +1889C +TANGUT COMPONENT-157 + +1889D +TANGUT COMPONENT-158 + +1889E +TANGUT COMPONENT-159 + +1889F +TANGUT COMPONENT-160 + +188A0 +TANGUT COMPONENT-161 + +188A1 +TANGUT COMPONENT-162 + +188A2 +TANGUT COMPONENT-163 + +188A3 +TANGUT COMPONENT-164 + +188A4 +TANGUT COMPONENT-165 + +188A5 +TANGUT COMPONENT-166 + +188A6 +TANGUT COMPONENT-167 + +188A7 +TANGUT COMPONENT-168 + +188A8 +TANGUT COMPONENT-169 + +188A9 +TANGUT COMPONENT-170 + +188AA +TANGUT COMPONENT-171 + +188AB +TANGUT COMPONENT-172 + +188AC +TANGUT COMPONENT-173 + +188AD +TANGUT COMPONENT-174 + +188AE +TANGUT COMPONENT-175 + +188AF +TANGUT COMPONENT-176 + +188B0 +TANGUT COMPONENT-177 + +188B1 +TANGUT COMPONENT-178 + +188B2 +TANGUT COMPONENT-179 + +188B3 +TANGUT COMPONENT-180 + +188B4 +TANGUT COMPONENT-181 + +188B5 +TANGUT COMPONENT-182 + +188B6 +TANGUT COMPONENT-183 + +188B7 +TANGUT COMPONENT-184 + +188B8 +TANGUT COMPONENT-185 + +188B9 +TANGUT COMPONENT-186 + +188BA +TANGUT COMPONENT-187 + +188BB +TANGUT COMPONENT-188 + +188BC +TANGUT COMPONENT-189 + +188BD +TANGUT COMPONENT-190 + +188BE +TANGUT COMPONENT-191 + +188BF +TANGUT COMPONENT-192 + +188C0 +TANGUT COMPONENT-193 + +188C1 +TANGUT COMPONENT-194 + +188C2 +TANGUT COMPONENT-195 + +188C3 +TANGUT COMPONENT-196 + +188C4 +TANGUT COMPONENT-197 + +188C5 +TANGUT COMPONENT-198 + +188C6 +TANGUT COMPONENT-199 + +188C7 +TANGUT COMPONENT-200 + +188C8 +TANGUT COMPONENT-201 + +188C9 +TANGUT COMPONENT-202 + +188CA +TANGUT COMPONENT-203 + +188CB +TANGUT COMPONENT-204 + +188CC +TANGUT COMPONENT-205 + +188CD +TANGUT COMPONENT-206 + +188CE +TANGUT COMPONENT-207 + +188CF +TANGUT COMPONENT-208 + +188D0 +TANGUT COMPONENT-209 + +188D1 +TANGUT COMPONENT-210 + +188D2 +TANGUT COMPONENT-211 + +188D3 +TANGUT COMPONENT-212 + +188D4 +TANGUT COMPONENT-213 + +188D5 +TANGUT COMPONENT-214 + +188D6 +TANGUT COMPONENT-215 + +188D7 +TANGUT COMPONENT-216 + +188D8 +TANGUT COMPONENT-217 + +188D9 +TANGUT COMPONENT-218 + +188DA +TANGUT COMPONENT-219 + +188DB +TANGUT COMPONENT-220 + +188DC +TANGUT COMPONENT-221 + +188DD +TANGUT COMPONENT-222 + +188DE +TANGUT COMPONENT-223 + +188DF +TANGUT COMPONENT-224 + +188E0 +TANGUT COMPONENT-225 + +188E1 +TANGUT COMPONENT-226 + +188E2 +TANGUT COMPONENT-227 + +188E3 +TANGUT COMPONENT-228 + +188E4 +TANGUT COMPONENT-229 + +188E5 +TANGUT COMPONENT-230 + +188E6 +TANGUT COMPONENT-231 + +188E7 +TANGUT COMPONENT-232 + +188E8 +TANGUT COMPONENT-233 + +188E9 +TANGUT COMPONENT-234 + +188EA +TANGUT COMPONENT-235 + +188EB +TANGUT COMPONENT-236 + +188EC +TANGUT COMPONENT-237 + +188ED +TANGUT COMPONENT-238 + +188EE +TANGUT COMPONENT-239 + +188EF +TANGUT COMPONENT-240 + +188F0 +TANGUT COMPONENT-241 + +188F1 +TANGUT COMPONENT-242 + +188F2 +TANGUT COMPONENT-243 + +188F3 +TANGUT COMPONENT-244 + +188F4 +TANGUT COMPONENT-245 + +188F5 +TANGUT COMPONENT-246 + +188F6 +TANGUT COMPONENT-247 + +188F7 +TANGUT COMPONENT-248 + +188F8 +TANGUT COMPONENT-249 + +188F9 +TANGUT COMPONENT-250 + +188FA +TANGUT COMPONENT-251 + +188FB +TANGUT COMPONENT-252 + +188FC +TANGUT COMPONENT-253 + +188FD +TANGUT COMPONENT-254 + +188FE +TANGUT COMPONENT-255 + +188FF +TANGUT COMPONENT-256 + +18900 +TANGUT COMPONENT-257 + +18901 +TANGUT COMPONENT-258 + +18902 +TANGUT COMPONENT-259 + +18903 +TANGUT COMPONENT-260 + +18904 +TANGUT COMPONENT-261 + +18905 +TANGUT COMPONENT-262 + +18906 +TANGUT COMPONENT-263 + +18907 +TANGUT COMPONENT-264 + +18908 +TANGUT COMPONENT-265 + +18909 +TANGUT COMPONENT-266 + +1890A +TANGUT COMPONENT-267 + +1890B +TANGUT COMPONENT-268 + +1890C +TANGUT COMPONENT-269 + +1890D +TANGUT COMPONENT-270 + +1890E +TANGUT COMPONENT-271 + +1890F +TANGUT COMPONENT-272 + +18910 +TANGUT COMPONENT-273 + +18911 +TANGUT COMPONENT-274 + +18912 +TANGUT COMPONENT-275 + +18913 +TANGUT COMPONENT-276 + +18914 +TANGUT COMPONENT-277 + +18915 +TANGUT COMPONENT-278 + +18916 +TANGUT COMPONENT-279 + +18917 +TANGUT COMPONENT-280 + +18918 +TANGUT COMPONENT-281 + +18919 +TANGUT COMPONENT-282 + +1891A +TANGUT COMPONENT-283 + +1891B +TANGUT COMPONENT-284 + +1891C +TANGUT COMPONENT-285 + +1891D +TANGUT COMPONENT-286 + +1891E +TANGUT COMPONENT-287 + +1891F +TANGUT COMPONENT-288 + +18920 +TANGUT COMPONENT-289 + +18921 +TANGUT COMPONENT-290 + +18922 +TANGUT COMPONENT-291 + +18923 +TANGUT COMPONENT-292 + +18924 +TANGUT COMPONENT-293 + +18925 +TANGUT COMPONENT-294 + +18926 +TANGUT COMPONENT-295 + +18927 +TANGUT COMPONENT-296 + +18928 +TANGUT COMPONENT-297 + +18929 +TANGUT COMPONENT-298 + +1892A +TANGUT COMPONENT-299 + +1892B +TANGUT COMPONENT-300 + +1892C +TANGUT COMPONENT-301 + +1892D +TANGUT COMPONENT-302 + +1892E +TANGUT COMPONENT-303 + +1892F +TANGUT COMPONENT-304 + +18930 +TANGUT COMPONENT-305 + +18931 +TANGUT COMPONENT-306 + +18932 +TANGUT COMPONENT-307 + +18933 +TANGUT COMPONENT-308 + +18934 +TANGUT COMPONENT-309 + +18935 +TANGUT COMPONENT-310 + +18936 +TANGUT COMPONENT-311 + +18937 +TANGUT COMPONENT-312 + +18938 +TANGUT COMPONENT-313 + +18939 +TANGUT COMPONENT-314 + +1893A +TANGUT COMPONENT-315 + +1893B +TANGUT COMPONENT-316 + +1893C +TANGUT COMPONENT-317 + +1893D +TANGUT COMPONENT-318 + +1893E +TANGUT COMPONENT-319 + +1893F +TANGUT COMPONENT-320 + +18940 +TANGUT COMPONENT-321 + +18941 +TANGUT COMPONENT-322 + +18942 +TANGUT COMPONENT-323 + +18943 +TANGUT COMPONENT-324 + +18944 +TANGUT COMPONENT-325 + +18945 +TANGUT COMPONENT-326 + +18946 +TANGUT COMPONENT-327 + +18947 +TANGUT COMPONENT-328 + +18948 +TANGUT COMPONENT-329 + +18949 +TANGUT COMPONENT-330 + +1894A +TANGUT COMPONENT-331 + +1894B +TANGUT COMPONENT-332 + +1894C +TANGUT COMPONENT-333 + +1894D +TANGUT COMPONENT-334 + +1894E +TANGUT COMPONENT-335 + +1894F +TANGUT COMPONENT-336 + +18950 +TANGUT COMPONENT-337 + +18951 +TANGUT COMPONENT-338 + +18952 +TANGUT COMPONENT-339 + +18953 +TANGUT COMPONENT-340 + +18954 +TANGUT COMPONENT-341 + +18955 +TANGUT COMPONENT-342 + +18956 +TANGUT COMPONENT-343 + +18957 +TANGUT COMPONENT-344 + +18958 +TANGUT COMPONENT-345 + +18959 +TANGUT COMPONENT-346 + +1895A +TANGUT COMPONENT-347 + +1895B +TANGUT COMPONENT-348 + +1895C +TANGUT COMPONENT-349 + +1895D +TANGUT COMPONENT-350 + +1895E +TANGUT COMPONENT-351 + +1895F +TANGUT COMPONENT-352 + +18960 +TANGUT COMPONENT-353 + +18961 +TANGUT COMPONENT-354 + +18962 +TANGUT COMPONENT-355 + +18963 +TANGUT COMPONENT-356 + +18964 +TANGUT COMPONENT-357 + +18965 +TANGUT COMPONENT-358 + +18966 +TANGUT COMPONENT-359 + +18967 +TANGUT COMPONENT-360 + +18968 +TANGUT COMPONENT-361 + +18969 +TANGUT COMPONENT-362 + +1896A +TANGUT COMPONENT-363 + +1896B +TANGUT COMPONENT-364 + +1896C +TANGUT COMPONENT-365 + +1896D +TANGUT COMPONENT-366 + +1896E +TANGUT COMPONENT-367 + +1896F +TANGUT COMPONENT-368 + +18970 +TANGUT COMPONENT-369 + +18971 +TANGUT COMPONENT-370 + +18972 +TANGUT COMPONENT-371 + +18973 +TANGUT COMPONENT-372 + +18974 +TANGUT COMPONENT-373 + +18975 +TANGUT COMPONENT-374 + +18976 +TANGUT COMPONENT-375 + +18977 +TANGUT COMPONENT-376 + +18978 +TANGUT COMPONENT-377 + +18979 +TANGUT COMPONENT-378 + +1897A +TANGUT COMPONENT-379 + +1897B +TANGUT COMPONENT-380 + +1897C +TANGUT COMPONENT-381 + +1897D +TANGUT COMPONENT-382 + +1897E +TANGUT COMPONENT-383 + +1897F +TANGUT COMPONENT-384 + +18980 +TANGUT COMPONENT-385 + +18981 +TANGUT COMPONENT-386 + +18982 +TANGUT COMPONENT-387 + +18983 +TANGUT COMPONENT-388 + +18984 +TANGUT COMPONENT-389 + +18985 +TANGUT COMPONENT-390 + +18986 +TANGUT COMPONENT-391 + +18987 +TANGUT COMPONENT-392 + +18988 +TANGUT COMPONENT-393 + +18989 +TANGUT COMPONENT-394 + +1898A +TANGUT COMPONENT-395 + +1898B +TANGUT COMPONENT-396 + +1898C +TANGUT COMPONENT-397 + +1898D +TANGUT COMPONENT-398 + +1898E +TANGUT COMPONENT-399 + +1898F +TANGUT COMPONENT-400 + +18990 +TANGUT COMPONENT-401 + +18991 +TANGUT COMPONENT-402 + +18992 +TANGUT COMPONENT-403 + +18993 +TANGUT COMPONENT-404 + +18994 +TANGUT COMPONENT-405 + +18995 +TANGUT COMPONENT-406 + +18996 +TANGUT COMPONENT-407 + +18997 +TANGUT COMPONENT-408 + +18998 +TANGUT COMPONENT-409 + +18999 +TANGUT COMPONENT-410 + +1899A +TANGUT COMPONENT-411 + +1899B +TANGUT COMPONENT-412 + +1899C +TANGUT COMPONENT-413 + +1899D +TANGUT COMPONENT-414 + +1899E +TANGUT COMPONENT-415 + +1899F +TANGUT COMPONENT-416 + +189A0 +TANGUT COMPONENT-417 + +189A1 +TANGUT COMPONENT-418 + +189A2 +TANGUT COMPONENT-419 + +189A3 +TANGUT COMPONENT-420 + +189A4 +TANGUT COMPONENT-421 + +189A5 +TANGUT COMPONENT-422 + +189A6 +TANGUT COMPONENT-423 + +189A7 +TANGUT COMPONENT-424 + +189A8 +TANGUT COMPONENT-425 + +189A9 +TANGUT COMPONENT-426 + +189AA +TANGUT COMPONENT-427 + +189AB +TANGUT COMPONENT-428 + +189AC +TANGUT COMPONENT-429 + +189AD +TANGUT COMPONENT-430 + +189AE +TANGUT COMPONENT-431 + +189AF +TANGUT COMPONENT-432 + +189B0 +TANGUT COMPONENT-433 + +189B1 +TANGUT COMPONENT-434 + +189B2 +TANGUT COMPONENT-435 + +189B3 +TANGUT COMPONENT-436 + +189B4 +TANGUT COMPONENT-437 + +189B5 +TANGUT COMPONENT-438 + +189B6 +TANGUT COMPONENT-439 + +189B7 +TANGUT COMPONENT-440 + +189B8 +TANGUT COMPONENT-441 + +189B9 +TANGUT COMPONENT-442 + +189BA +TANGUT COMPONENT-443 + +189BB +TANGUT COMPONENT-444 + +189BC +TANGUT COMPONENT-445 + +189BD +TANGUT COMPONENT-446 + +189BE +TANGUT COMPONENT-447 + +189BF +TANGUT COMPONENT-448 + +189C0 +TANGUT COMPONENT-449 + +189C1 +TANGUT COMPONENT-450 + +189C2 +TANGUT COMPONENT-451 + +189C3 +TANGUT COMPONENT-452 + +189C4 +TANGUT COMPONENT-453 + +189C5 +TANGUT COMPONENT-454 + +189C6 +TANGUT COMPONENT-455 + +189C7 +TANGUT COMPONENT-456 + +189C8 +TANGUT COMPONENT-457 + +189C9 +TANGUT COMPONENT-458 + +189CA +TANGUT COMPONENT-459 + +189CB +TANGUT COMPONENT-460 + +189CC +TANGUT COMPONENT-461 + +189CD +TANGUT COMPONENT-462 + +189CE +TANGUT COMPONENT-463 + +189CF +TANGUT COMPONENT-464 + +189D0 +TANGUT COMPONENT-465 + +189D1 +TANGUT COMPONENT-466 + +189D2 +TANGUT COMPONENT-467 + +189D3 +TANGUT COMPONENT-468 + +189D4 +TANGUT COMPONENT-469 + +189D5 +TANGUT COMPONENT-470 + +189D6 +TANGUT COMPONENT-471 + +189D7 +TANGUT COMPONENT-472 + +189D8 +TANGUT COMPONENT-473 + +189D9 +TANGUT COMPONENT-474 + +189DA +TANGUT COMPONENT-475 + +189DB +TANGUT COMPONENT-476 + +189DC +TANGUT COMPONENT-477 + +189DD +TANGUT COMPONENT-478 + +189DE +TANGUT COMPONENT-479 + +189DF +TANGUT COMPONENT-480 + +189E0 +TANGUT COMPONENT-481 + +189E1 +TANGUT COMPONENT-482 + +189E2 +TANGUT COMPONENT-483 + +189E3 +TANGUT COMPONENT-484 + +189E4 +TANGUT COMPONENT-485 + +189E5 +TANGUT COMPONENT-486 + +189E6 +TANGUT COMPONENT-487 + +189E7 +TANGUT COMPONENT-488 + +189E8 +TANGUT COMPONENT-489 + +189E9 +TANGUT COMPONENT-490 + +189EA +TANGUT COMPONENT-491 + +189EB +TANGUT COMPONENT-492 + +189EC +TANGUT COMPONENT-493 + +189ED +TANGUT COMPONENT-494 + +189EE +TANGUT COMPONENT-495 + +189EF +TANGUT COMPONENT-496 + +189F0 +TANGUT COMPONENT-497 + +189F1 +TANGUT COMPONENT-498 + +189F2 +TANGUT COMPONENT-499 + +189F3 +TANGUT COMPONENT-500 + +189F4 +TANGUT COMPONENT-501 + +189F5 +TANGUT COMPONENT-502 + +189F6 +TANGUT COMPONENT-503 + +189F7 +TANGUT COMPONENT-504 + +189F8 +TANGUT COMPONENT-505 + +189F9 +TANGUT COMPONENT-506 + +189FA +TANGUT COMPONENT-507 + +189FB +TANGUT COMPONENT-508 + +189FC +TANGUT COMPONENT-509 + +189FD +TANGUT COMPONENT-510 + +189FE +TANGUT COMPONENT-511 + +189FF +TANGUT COMPONENT-512 + +18A00 +TANGUT COMPONENT-513 + +18A01 +TANGUT COMPONENT-514 + +18A02 +TANGUT COMPONENT-515 + +18A03 +TANGUT COMPONENT-516 + +18A04 +TANGUT COMPONENT-517 + +18A05 +TANGUT COMPONENT-518 + +18A06 +TANGUT COMPONENT-519 + +18A07 +TANGUT COMPONENT-520 + +18A08 +TANGUT COMPONENT-521 + +18A09 +TANGUT COMPONENT-522 + +18A0A +TANGUT COMPONENT-523 + +18A0B +TANGUT COMPONENT-524 + +18A0C +TANGUT COMPONENT-525 + +18A0D +TANGUT COMPONENT-526 + +18A0E +TANGUT COMPONENT-527 + +18A0F +TANGUT COMPONENT-528 + +18A10 +TANGUT COMPONENT-529 + +18A11 +TANGUT COMPONENT-530 + +18A12 +TANGUT COMPONENT-531 + +18A13 +TANGUT COMPONENT-532 + +18A14 +TANGUT COMPONENT-533 + +18A15 +TANGUT COMPONENT-534 + +18A16 +TANGUT COMPONENT-535 + +18A17 +TANGUT COMPONENT-536 + +18A18 +TANGUT COMPONENT-537 + +18A19 +TANGUT COMPONENT-538 + +18A1A +TANGUT COMPONENT-539 + +18A1B +TANGUT COMPONENT-540 + +18A1C +TANGUT COMPONENT-541 + +18A1D +TANGUT COMPONENT-542 + +18A1E +TANGUT COMPONENT-543 + +18A1F +TANGUT COMPONENT-544 + +18A20 +TANGUT COMPONENT-545 + +18A21 +TANGUT COMPONENT-546 + +18A22 +TANGUT COMPONENT-547 + +18A23 +TANGUT COMPONENT-548 + +18A24 +TANGUT COMPONENT-549 + +18A25 +TANGUT COMPONENT-550 + +18A26 +TANGUT COMPONENT-551 + +18A27 +TANGUT COMPONENT-552 + +18A28 +TANGUT COMPONENT-553 + +18A29 +TANGUT COMPONENT-554 + +18A2A +TANGUT COMPONENT-555 + +18A2B +TANGUT COMPONENT-556 + +18A2C +TANGUT COMPONENT-557 + +18A2D +TANGUT COMPONENT-558 + +18A2E +TANGUT COMPONENT-559 + +18A2F +TANGUT COMPONENT-560 + +18A30 +TANGUT COMPONENT-561 + +18A31 +TANGUT COMPONENT-562 + +18A32 +TANGUT COMPONENT-563 + +18A33 +TANGUT COMPONENT-564 + +18A34 +TANGUT COMPONENT-565 + +18A35 +TANGUT COMPONENT-566 + +18A36 +TANGUT COMPONENT-567 + +18A37 +TANGUT COMPONENT-568 + +18A38 +TANGUT COMPONENT-569 + +18A39 +TANGUT COMPONENT-570 + +18A3A +TANGUT COMPONENT-571 + +18A3B +TANGUT COMPONENT-572 + +18A3C +TANGUT COMPONENT-573 + +18A3D +TANGUT COMPONENT-574 + +18A3E +TANGUT COMPONENT-575 + +18A3F +TANGUT COMPONENT-576 + +18A40 +TANGUT COMPONENT-577 + +18A41 +TANGUT COMPONENT-578 + +18A42 +TANGUT COMPONENT-579 + +18A43 +TANGUT COMPONENT-580 + +18A44 +TANGUT COMPONENT-581 + +18A45 +TANGUT COMPONENT-582 + +18A46 +TANGUT COMPONENT-583 + +18A47 +TANGUT COMPONENT-584 + +18A48 +TANGUT COMPONENT-585 + +18A49 +TANGUT COMPONENT-586 + +18A4A +TANGUT COMPONENT-587 + +18A4B +TANGUT COMPONENT-588 + +18A4C +TANGUT COMPONENT-589 + +18A4D +TANGUT COMPONENT-590 + +18A4E +TANGUT COMPONENT-591 + +18A4F +TANGUT COMPONENT-592 + +18A50 +TANGUT COMPONENT-593 + +18A51 +TANGUT COMPONENT-594 + +18A52 +TANGUT COMPONENT-595 + +18A53 +TANGUT COMPONENT-596 + +18A54 +TANGUT COMPONENT-597 + +18A55 +TANGUT COMPONENT-598 + +18A56 +TANGUT COMPONENT-599 + +18A57 +TANGUT COMPONENT-600 + +18A58 +TANGUT COMPONENT-601 + +18A59 +TANGUT COMPONENT-602 + +18A5A +TANGUT COMPONENT-603 + +18A5B +TANGUT COMPONENT-604 + +18A5C +TANGUT COMPONENT-605 + +18A5D +TANGUT COMPONENT-606 + +18A5E +TANGUT COMPONENT-607 + +18A5F +TANGUT COMPONENT-608 + +18A60 +TANGUT COMPONENT-609 + +18A61 +TANGUT COMPONENT-610 + +18A62 +TANGUT COMPONENT-611 + +18A63 +TANGUT COMPONENT-612 + +18A64 +TANGUT COMPONENT-613 + +18A65 +TANGUT COMPONENT-614 + +18A66 +TANGUT COMPONENT-615 + +18A67 +TANGUT COMPONENT-616 + +18A68 +TANGUT COMPONENT-617 + +18A69 +TANGUT COMPONENT-618 + +18A6A +TANGUT COMPONENT-619 + +18A6B +TANGUT COMPONENT-620 + +18A6C +TANGUT COMPONENT-621 + +18A6D +TANGUT COMPONENT-622 + +18A6E +TANGUT COMPONENT-623 + +18A6F +TANGUT COMPONENT-624 + +18A70 +TANGUT COMPONENT-625 + +18A71 +TANGUT COMPONENT-626 + +18A72 +TANGUT COMPONENT-627 + +18A73 +TANGUT COMPONENT-628 + +18A74 +TANGUT COMPONENT-629 + +18A75 +TANGUT COMPONENT-630 + +18A76 +TANGUT COMPONENT-631 + +18A77 +TANGUT COMPONENT-632 + +18A78 +TANGUT COMPONENT-633 + +18A79 +TANGUT COMPONENT-634 + +18A7A +TANGUT COMPONENT-635 + +18A7B +TANGUT COMPONENT-636 + +18A7C +TANGUT COMPONENT-637 + +18A7D +TANGUT COMPONENT-638 + +18A7E +TANGUT COMPONENT-639 + +18A7F +TANGUT COMPONENT-640 + +18A80 +TANGUT COMPONENT-641 + +18A81 +TANGUT COMPONENT-642 + +18A82 +TANGUT COMPONENT-643 + +18A83 +TANGUT COMPONENT-644 + +18A84 +TANGUT COMPONENT-645 + +18A85 +TANGUT COMPONENT-646 + +18A86 +TANGUT COMPONENT-647 + +18A87 +TANGUT COMPONENT-648 + +18A88 +TANGUT COMPONENT-649 + +18A89 +TANGUT COMPONENT-650 + +18A8A +TANGUT COMPONENT-651 + +18A8B +TANGUT COMPONENT-652 + +18A8C +TANGUT COMPONENT-653 + +18A8D +TANGUT COMPONENT-654 + +18A8E +TANGUT COMPONENT-655 + +18A8F +TANGUT COMPONENT-656 + +18A90 +TANGUT COMPONENT-657 + +18A91 +TANGUT COMPONENT-658 + +18A92 +TANGUT COMPONENT-659 + +18A93 +TANGUT COMPONENT-660 + +18A94 +TANGUT COMPONENT-661 + +18A95 +TANGUT COMPONENT-662 + +18A96 +TANGUT COMPONENT-663 + +18A97 +TANGUT COMPONENT-664 + +18A98 +TANGUT COMPONENT-665 + +18A99 +TANGUT COMPONENT-666 + +18A9A +TANGUT COMPONENT-667 + +18A9B +TANGUT COMPONENT-668 + +18A9C +TANGUT COMPONENT-669 + +18A9D +TANGUT COMPONENT-670 + +18A9E +TANGUT COMPONENT-671 + +18A9F +TANGUT COMPONENT-672 + +18AA0 +TANGUT COMPONENT-673 + +18AA1 +TANGUT COMPONENT-674 + +18AA2 +TANGUT COMPONENT-675 + +18AA3 +TANGUT COMPONENT-676 + +18AA4 +TANGUT COMPONENT-677 + +18AA5 +TANGUT COMPONENT-678 + +18AA6 +TANGUT COMPONENT-679 + +18AA7 +TANGUT COMPONENT-680 + +18AA8 +TANGUT COMPONENT-681 + +18AA9 +TANGUT COMPONENT-682 + +18AAA +TANGUT COMPONENT-683 + +18AAB +TANGUT COMPONENT-684 + +18AAC +TANGUT COMPONENT-685 + +18AAD +TANGUT COMPONENT-686 + +18AAE +TANGUT COMPONENT-687 + +18AAF +TANGUT COMPONENT-688 + +18AB0 +TANGUT COMPONENT-689 + +18AB1 +TANGUT COMPONENT-690 + +18AB2 +TANGUT COMPONENT-691 + +18AB3 +TANGUT COMPONENT-692 + +18AB4 +TANGUT COMPONENT-693 + +18AB5 +TANGUT COMPONENT-694 + +18AB6 +TANGUT COMPONENT-695 + +18AB7 +TANGUT COMPONENT-696 + +18AB8 +TANGUT COMPONENT-697 + +18AB9 +TANGUT COMPONENT-698 + +18ABA +TANGUT COMPONENT-699 + +18ABB +TANGUT COMPONENT-700 + +18ABC +TANGUT COMPONENT-701 + +18ABD +TANGUT COMPONENT-702 + +18ABE +TANGUT COMPONENT-703 + +18ABF +TANGUT COMPONENT-704 + +18AC0 +TANGUT COMPONENT-705 + +18AC1 +TANGUT COMPONENT-706 + +18AC2 +TANGUT COMPONENT-707 + +18AC3 +TANGUT COMPONENT-708 + +18AC4 +TANGUT COMPONENT-709 + +18AC5 +TANGUT COMPONENT-710 + +18AC6 +TANGUT COMPONENT-711 + +18AC7 +TANGUT COMPONENT-712 + +18AC8 +TANGUT COMPONENT-713 + +18AC9 +TANGUT COMPONENT-714 + +18ACA +TANGUT COMPONENT-715 + +18ACB +TANGUT COMPONENT-716 + +18ACC +TANGUT COMPONENT-717 + +18ACD +TANGUT COMPONENT-718 + +18ACE +TANGUT COMPONENT-719 + +18ACF +TANGUT COMPONENT-720 + +18AD0 +TANGUT COMPONENT-721 + +18AD1 +TANGUT COMPONENT-722 + +18AD2 +TANGUT COMPONENT-723 + +18AD3 +TANGUT COMPONENT-724 + +18AD4 +TANGUT COMPONENT-725 + +18AD5 +TANGUT COMPONENT-726 + +18AD6 +TANGUT COMPONENT-727 + +18AD7 +TANGUT COMPONENT-728 + +18AD8 +TANGUT COMPONENT-729 + +18AD9 +TANGUT COMPONENT-730 + +18ADA +TANGUT COMPONENT-731 + +18ADB +TANGUT COMPONENT-732 + +18ADC +TANGUT COMPONENT-733 + +18ADD +TANGUT COMPONENT-734 + +18ADE +TANGUT COMPONENT-735 + +18ADF +TANGUT COMPONENT-736 + +18AE0 +TANGUT COMPONENT-737 + +18AE1 +TANGUT COMPONENT-738 + +18AE2 +TANGUT COMPONENT-739 + +18AE3 +TANGUT COMPONENT-740 + +18AE4 +TANGUT COMPONENT-741 + +18AE5 +TANGUT COMPONENT-742 + +18AE6 +TANGUT COMPONENT-743 + +18AE7 +TANGUT COMPONENT-744 + +18AE8 +TANGUT COMPONENT-745 + +18AE9 +TANGUT COMPONENT-746 + +18AEA +TANGUT COMPONENT-747 + +18AEB +TANGUT COMPONENT-748 + +18AEC +TANGUT COMPONENT-749 + +18AED +TANGUT COMPONENT-750 + +18AEE +TANGUT COMPONENT-751 + +18AEF +TANGUT COMPONENT-752 + +18AF0 +TANGUT COMPONENT-753 + +18AF1 +TANGUT COMPONENT-754 + +18AF2 +TANGUT COMPONENT-755 + +18AF3 +TANGUT COMPONENT-756 + +18AF4 +TANGUT COMPONENT-757 + +18AF5 +TANGUT COMPONENT-758 + +18AF6 +TANGUT COMPONENT-759 + +18AF7 +TANGUT COMPONENT-760 + +18AF8 +TANGUT COMPONENT-761 + +18AF9 +TANGUT COMPONENT-762 + +18AFA +TANGUT COMPONENT-763 + +18AFB +TANGUT COMPONENT-764 + +18AFC +TANGUT COMPONENT-765 + +18AFD +TANGUT COMPONENT-766 + +18AFE +TANGUT COMPONENT-767 + +18AFF +TANGUT COMPONENT-768 + +18D80 +TANGUT COMPONENT-769 + +18D81 +TANGUT COMPONENT-770 + +18D82 +TANGUT COMPONENT-771 + +18D83 +TANGUT COMPONENT-772 + +18D84 +TANGUT COMPONENT-773 + +18D85 +TANGUT COMPONENT-774 + +18D86 +TANGUT COMPONENT-775 + +18D87 +TANGUT COMPONENT-776 + +18D88 +TANGUT COMPONENT-777 + +18D89 +TANGUT COMPONENT-778 + +18D8A +TANGUT COMPONENT-779 + +18D8B +TANGUT COMPONENT-780 + +18D8C +TANGUT COMPONENT-781 + +18D8D +TANGUT COMPONENT-782 + +18D8E +TANGUT COMPONENT-783 + +18D8F +TANGUT COMPONENT-784 + +18D90 +TANGUT COMPONENT-785 + +18D91 +TANGUT COMPONENT-786 + +18D92 +TANGUT COMPONENT-787 + +18D93 +TANGUT COMPONENT-788 + +18D94 +TANGUT COMPONENT-789 + +18D95 +TANGUT COMPONENT-790 + +18D96 +TANGUT COMPONENT-791 + +18D97 +TANGUT COMPONENT-792 + +18D98 +TANGUT COMPONENT-793 + +18D99 +TANGUT COMPONENT-794 + +18D9A +TANGUT COMPONENT-795 + +18D9B +TANGUT COMPONENT-796 + +18D9C +TANGUT COMPONENT-797 + +18D9D +TANGUT COMPONENT-798 + +18D9E +TANGUT COMPONENT-799 + +18D9F +TANGUT COMPONENT-800 + +18DA0 +TANGUT COMPONENT-801 + +18DA1 +TANGUT COMPONENT-802 + +18DA2 +TANGUT COMPONENT-803 + +18DA3 +TANGUT COMPONENT-804 + +18DA4 +TANGUT COMPONENT-805 + +18DA5 +TANGUT COMPONENT-806 + +18DA6 +TANGUT COMPONENT-807 + +18DA7 +TANGUT COMPONENT-808 + +18DA8 +TANGUT COMPONENT-809 + +18DA9 +TANGUT COMPONENT-810 + +18DAA +TANGUT COMPONENT-811 + +18DAB +TANGUT COMPONENT-812 + +18DAC +TANGUT COMPONENT-813 + +18DAD +TANGUT COMPONENT-814 + +18DAE +TANGUT COMPONENT-815 + +18DAF +TANGUT COMPONENT-816 + +18DB0 +TANGUT COMPONENT-817 + +18DB1 +TANGUT COMPONENT-818 + +18DB2 +TANGUT COMPONENT-819 + +18DB3 +TANGUT COMPONENT-820 + +18DB4 +TANGUT COMPONENT-821 + +18DB5 +TANGUT COMPONENT-822 + +18DB6 +TANGUT COMPONENT-823 + +18DB7 +TANGUT COMPONENT-824 + +18DB8 +TANGUT COMPONENT-825 + +18DB9 +TANGUT COMPONENT-826 + +18DBA +TANGUT COMPONENT-827 + +18DBB +TANGUT COMPONENT-828 + +18DBC +TANGUT COMPONENT-829 + +18DBD +TANGUT COMPONENT-830 + +18DBE +TANGUT COMPONENT-831 + +18DBF +TANGUT COMPONENT-832 + +18DC0 +TANGUT COMPONENT-833 + +18DC1 +TANGUT COMPONENT-834 + +18DC2 +TANGUT COMPONENT-835 + +18DC3 +TANGUT COMPONENT-836 + +18DC4 +TANGUT COMPONENT-837 + +18DC5 +TANGUT COMPONENT-838 + +18DC6 +TANGUT COMPONENT-839 + +18DC7 +TANGUT COMPONENT-840 + +18DC8 +TANGUT COMPONENT-841 + +18DC9 +TANGUT COMPONENT-842 + +18DCA +TANGUT COMPONENT-843 + +18DCB +TANGUT COMPONENT-844 + +18DCC +TANGUT COMPONENT-845 + +18DCD +TANGUT COMPONENT-846 + +18DCE +TANGUT COMPONENT-847 + +18DCF +TANGUT COMPONENT-848 + +18DD0 +TANGUT COMPONENT-849 + +18DD1 +TANGUT COMPONENT-850 + +18DD2 +TANGUT COMPONENT-851 + +18DD3 +TANGUT COMPONENT-852 + +18DD4 +TANGUT COMPONENT-853 + +18DD5 +TANGUT COMPONENT-854 + +18DD6 +TANGUT COMPONENT-855 + +18DD7 +TANGUT COMPONENT-856 + +18DD8 +TANGUT COMPONENT-857 + +18DD9 +TANGUT COMPONENT-858 + +18DDA +TANGUT COMPONENT-859 + +18DDB +TANGUT COMPONENT-860 + +18DDC +TANGUT COMPONENT-861 + +18DDD +TANGUT COMPONENT-862 + +18DDE +TANGUT COMPONENT-863 + +18DDF +TANGUT COMPONENT-864 + +18DE0 +TANGUT COMPONENT-865 + +18DE1 +TANGUT COMPONENT-866 + +18DE2 +TANGUT COMPONENT-867 + +18DE3 +TANGUT COMPONENT-868 + +18DE4 +TANGUT COMPONENT-869 + +18DE5 +TANGUT COMPONENT-870 + +18DE6 +TANGUT COMPONENT-871 + +18DE7 +TANGUT COMPONENT-872 + +18DE8 +TANGUT COMPONENT-873 + +18DE9 +TANGUT COMPONENT-874 + +18DEA +TANGUT COMPONENT-875 + +18DEB +TANGUT COMPONENT-876 + +18DEC +TANGUT COMPONENT-877 + +18DED +TANGUT COMPONENT-878 + +18DEE +TANGUT COMPONENT-879 + +18DEF +TANGUT COMPONENT-880 + +18DF0 +TANGUT COMPONENT-881 + +18DF1 +TANGUT COMPONENT-882 + +18DF2 +TANGUT COMPONENT-883 + +1AFF0 +KATAKANA LETTER MINNAN TONE-2 + +1AFF1 +KATAKANA LETTER MINNAN TONE-3 + +1AFF2 +KATAKANA LETTER MINNAN TONE-4 + +1AFF3 +KATAKANA LETTER MINNAN TONE-5 + +1AFF5 +KATAKANA LETTER MINNAN TONE-7 + +1AFF6 +KATAKANA LETTER MINNAN TONE-8 + +1AFF7 +KATAKANA LETTER MINNAN NASALIZED TONE-1 + +1AFF8 +KATAKANA LETTER MINNAN NASALIZED TONE-2 + +1AFF9 +KATAKANA LETTER MINNAN NASALIZED TONE-3 + +1AFFA +KATAKANA LETTER MINNAN NASALIZED TONE-4 + +1AFFB +KATAKANA LETTER MINNAN NASALIZED TONE-5 + +1AFFD +KATAKANA LETTER MINNAN NASALIZED TONE-7 + +1AFFE +KATAKANA LETTER MINNAN NASALIZED TONE-8 + +1B000 +KATAKANA LETTER ARCHAIC E + +1B001 +HENTAIGANA LETTER E-1 + +1B001 +HIRAGANA LETTER ARCHAIC YE + +1B002 +HENTAIGANA LETTER A-1 + +1B003 +HENTAIGANA LETTER A-2 + +1B004 +HENTAIGANA LETTER A-3 + +1B005 +HENTAIGANA LETTER A-WO + +1B006 +HENTAIGANA LETTER I-1 + +1B007 +HENTAIGANA LETTER I-2 + +1B008 +HENTAIGANA LETTER I-3 + +1B009 +HENTAIGANA LETTER I-4 + +1B00A +HENTAIGANA LETTER U-1 + +1B00B +HENTAIGANA LETTER U-2 + +1B00C +HENTAIGANA LETTER U-3 + +1B00D +HENTAIGANA LETTER U-4 + +1B00E +HENTAIGANA LETTER U-5 + +1B00F +HENTAIGANA LETTER E-2 + +1B010 +HENTAIGANA LETTER E-3 + +1B011 +HENTAIGANA LETTER E-4 + +1B012 +HENTAIGANA LETTER E-5 + +1B013 +HENTAIGANA LETTER E-6 + +1B014 +HENTAIGANA LETTER O-1 + +1B015 +HENTAIGANA LETTER O-2 + +1B016 +HENTAIGANA LETTER O-3 + +1B017 +HENTAIGANA LETTER KA-1 + +1B018 +HENTAIGANA LETTER KA-2 + +1B019 +HENTAIGANA LETTER KA-3 + +1B01A +HENTAIGANA LETTER KA-4 + +1B01B +HENTAIGANA LETTER KA-5 + +1B01C +HENTAIGANA LETTER KA-6 + +1B01D +HENTAIGANA LETTER KA-7 + +1B01E +HENTAIGANA LETTER KA-8 + +1B01F +HENTAIGANA LETTER KA-9 + +1B020 +HENTAIGANA LETTER KA-10 + +1B021 +HENTAIGANA LETTER KA-11 + +1B022 +HENTAIGANA LETTER KA-KE + +1B023 +HENTAIGANA LETTER KI-1 + +1B024 +HENTAIGANA LETTER KI-2 + +1B025 +HENTAIGANA LETTER KI-3 + +1B026 +HENTAIGANA LETTER KI-4 + +1B027 +HENTAIGANA LETTER KI-5 + +1B028 +HENTAIGANA LETTER KI-6 + +1B029 +HENTAIGANA LETTER KI-7 + +1B02A +HENTAIGANA LETTER KI-8 + +1B02B +HENTAIGANA LETTER KU-1 + +1B02C +HENTAIGANA LETTER KU-2 + +1B02D +HENTAIGANA LETTER KU-3 + +1B02E +HENTAIGANA LETTER KU-4 + +1B02F +HENTAIGANA LETTER KU-5 + +1B030 +HENTAIGANA LETTER KU-6 + +1B031 +HENTAIGANA LETTER KU-7 + +1B032 +HENTAIGANA LETTER KE-1 + +1B033 +HENTAIGANA LETTER KE-2 + +1B034 +HENTAIGANA LETTER KE-3 + +1B035 +HENTAIGANA LETTER KE-4 + +1B036 +HENTAIGANA LETTER KE-5 + +1B037 +HENTAIGANA LETTER KE-6 + +1B038 +HENTAIGANA LETTER KO-1 + +1B039 +HENTAIGANA LETTER KO-2 + +1B03A +HENTAIGANA LETTER KO-3 + +1B03B +HENTAIGANA LETTER KO-KI + +1B03C +HENTAIGANA LETTER SA-1 + +1B03D +HENTAIGANA LETTER SA-2 + +1B03E +HENTAIGANA LETTER SA-3 + +1B03F +HENTAIGANA LETTER SA-4 + +1B040 +HENTAIGANA LETTER SA-5 + +1B041 +HENTAIGANA LETTER SA-6 + +1B042 +HENTAIGANA LETTER SA-7 + +1B043 +HENTAIGANA LETTER SA-8 + +1B044 +HENTAIGANA LETTER SI-1 + +1B045 +HENTAIGANA LETTER SI-2 + +1B046 +HENTAIGANA LETTER SI-3 + +1B047 +HENTAIGANA LETTER SI-4 + +1B048 +HENTAIGANA LETTER SI-5 + +1B049 +HENTAIGANA LETTER SI-6 + +1B04A +HENTAIGANA LETTER SU-1 + +1B04B +HENTAIGANA LETTER SU-2 + +1B04C +HENTAIGANA LETTER SU-3 + +1B04D +HENTAIGANA LETTER SU-4 + +1B04E +HENTAIGANA LETTER SU-5 + +1B04F +HENTAIGANA LETTER SU-6 + +1B050 +HENTAIGANA LETTER SU-7 + +1B051 +HENTAIGANA LETTER SU-8 + +1B052 +HENTAIGANA LETTER SE-1 + +1B053 +HENTAIGANA LETTER SE-2 + +1B054 +HENTAIGANA LETTER SE-3 + +1B055 +HENTAIGANA LETTER SE-4 + +1B056 +HENTAIGANA LETTER SE-5 + +1B057 +HENTAIGANA LETTER SO-1 + +1B058 +HENTAIGANA LETTER SO-2 + +1B059 +HENTAIGANA LETTER SO-3 + +1B05A +HENTAIGANA LETTER SO-4 + +1B05B +HENTAIGANA LETTER SO-5 + +1B05C +HENTAIGANA LETTER SO-6 + +1B05D +HENTAIGANA LETTER SO-7 + +1B05E +HENTAIGANA LETTER TA-1 + +1B05F +HENTAIGANA LETTER TA-2 + +1B060 +HENTAIGANA LETTER TA-3 + +1B061 +HENTAIGANA LETTER TA-4 + +1B062 +HENTAIGANA LETTER TI-1 + +1B063 +HENTAIGANA LETTER TI-2 + +1B064 +HENTAIGANA LETTER TI-3 + +1B065 +HENTAIGANA LETTER TI-4 + +1B066 +HENTAIGANA LETTER TI-5 + +1B067 +HENTAIGANA LETTER TI-6 + +1B068 +HENTAIGANA LETTER TI-7 + +1B069 +HENTAIGANA LETTER TU-1 + +1B06A +HENTAIGANA LETTER TU-2 + +1B06B +HENTAIGANA LETTER TU-3 + +1B06C +HENTAIGANA LETTER TU-4 + +1B06D +HENTAIGANA LETTER TU-TO + +1B06E +HENTAIGANA LETTER TE-1 + +1B06F +HENTAIGANA LETTER TE-2 + +1B070 +HENTAIGANA LETTER TE-3 + +1B071 +HENTAIGANA LETTER TE-4 + +1B072 +HENTAIGANA LETTER TE-5 + +1B073 +HENTAIGANA LETTER TE-6 + +1B074 +HENTAIGANA LETTER TE-7 + +1B075 +HENTAIGANA LETTER TE-8 + +1B076 +HENTAIGANA LETTER TE-9 + +1B077 +HENTAIGANA LETTER TO-1 + +1B078 +HENTAIGANA LETTER TO-2 + +1B079 +HENTAIGANA LETTER TO-3 + +1B07A +HENTAIGANA LETTER TO-4 + +1B07B +HENTAIGANA LETTER TO-5 + +1B07C +HENTAIGANA LETTER TO-6 + +1B07D +HENTAIGANA LETTER TO-RA + +1B07E +HENTAIGANA LETTER NA-1 + +1B07F +HENTAIGANA LETTER NA-2 + +1B080 +HENTAIGANA LETTER NA-3 + +1B081 +HENTAIGANA LETTER NA-4 + +1B082 +HENTAIGANA LETTER NA-5 + +1B083 +HENTAIGANA LETTER NA-6 + +1B084 +HENTAIGANA LETTER NA-7 + +1B085 +HENTAIGANA LETTER NA-8 + +1B086 +HENTAIGANA LETTER NA-9 + +1B087 +HENTAIGANA LETTER NI-1 + +1B088 +HENTAIGANA LETTER NI-2 + +1B089 +HENTAIGANA LETTER NI-3 + +1B08A +HENTAIGANA LETTER NI-4 + +1B08B +HENTAIGANA LETTER NI-5 + +1B08C +HENTAIGANA LETTER NI-6 + +1B08D +HENTAIGANA LETTER NI-7 + +1B08E +HENTAIGANA LETTER NI-TE + +1B08F +HENTAIGANA LETTER NU-1 + +1B090 +HENTAIGANA LETTER NU-2 + +1B091 +HENTAIGANA LETTER NU-3 + +1B092 +HENTAIGANA LETTER NE-1 + +1B093 +HENTAIGANA LETTER NE-2 + +1B094 +HENTAIGANA LETTER NE-3 + +1B095 +HENTAIGANA LETTER NE-4 + +1B096 +HENTAIGANA LETTER NE-5 + +1B097 +HENTAIGANA LETTER NE-6 + +1B098 +HENTAIGANA LETTER NE-KO + +1B099 +HENTAIGANA LETTER NO-1 + +1B09A +HENTAIGANA LETTER NO-2 + +1B09B +HENTAIGANA LETTER NO-3 + +1B09C +HENTAIGANA LETTER NO-4 + +1B09D +HENTAIGANA LETTER NO-5 + +1B09E +HENTAIGANA LETTER HA-1 + +1B09F +HENTAIGANA LETTER HA-2 + +1B0A0 +HENTAIGANA LETTER HA-3 + +1B0A1 +HENTAIGANA LETTER HA-4 + +1B0A2 +HENTAIGANA LETTER HA-5 + +1B0A3 +HENTAIGANA LETTER HA-6 + +1B0A4 +HENTAIGANA LETTER HA-7 + +1B0A5 +HENTAIGANA LETTER HA-8 + +1B0A6 +HENTAIGANA LETTER HA-9 + +1B0A7 +HENTAIGANA LETTER HA-10 + +1B0A8 +HENTAIGANA LETTER HA-11 + +1B0A9 +HENTAIGANA LETTER HI-1 + +1B0AA +HENTAIGANA LETTER HI-2 + +1B0AB +HENTAIGANA LETTER HI-3 + +1B0AC +HENTAIGANA LETTER HI-4 + +1B0AD +HENTAIGANA LETTER HI-5 + +1B0AE +HENTAIGANA LETTER HI-6 + +1B0AF +HENTAIGANA LETTER HI-7 + +1B0B0 +HENTAIGANA LETTER HU-1 + +1B0B1 +HENTAIGANA LETTER HU-2 + +1B0B2 +HENTAIGANA LETTER HU-3 + +1B0B3 +HENTAIGANA LETTER HE-1 + +1B0B4 +HENTAIGANA LETTER HE-2 + +1B0B5 +HENTAIGANA LETTER HE-3 + +1B0B6 +HENTAIGANA LETTER HE-4 + +1B0B7 +HENTAIGANA LETTER HE-5 + +1B0B8 +HENTAIGANA LETTER HE-6 + +1B0B9 +HENTAIGANA LETTER HE-7 + +1B0BA +HENTAIGANA LETTER HO-1 + +1B0BB +HENTAIGANA LETTER HO-2 + +1B0BC +HENTAIGANA LETTER HO-3 + +1B0BD +HENTAIGANA LETTER HO-4 + +1B0BE +HENTAIGANA LETTER HO-5 + +1B0BF +HENTAIGANA LETTER HO-6 + +1B0C0 +HENTAIGANA LETTER HO-7 + +1B0C1 +HENTAIGANA LETTER HO-8 + +1B0C2 +HENTAIGANA LETTER MA-1 + +1B0C3 +HENTAIGANA LETTER MA-2 + +1B0C4 +HENTAIGANA LETTER MA-3 + +1B0C5 +HENTAIGANA LETTER MA-4 + +1B0C6 +HENTAIGANA LETTER MA-5 + +1B0C7 +HENTAIGANA LETTER MA-6 + +1B0C8 +HENTAIGANA LETTER MA-7 + +1B0C9 +HENTAIGANA LETTER MI-1 + +1B0CA +HENTAIGANA LETTER MI-2 + +1B0CB +HENTAIGANA LETTER MI-3 + +1B0CC +HENTAIGANA LETTER MI-4 + +1B0CD +HENTAIGANA LETTER MI-5 + +1B0CE +HENTAIGANA LETTER MI-6 + +1B0CF +HENTAIGANA LETTER MI-7 + +1B0D0 +HENTAIGANA LETTER MU-1 + +1B0D1 +HENTAIGANA LETTER MU-2 + +1B0D2 +HENTAIGANA LETTER MU-3 + +1B0D3 +HENTAIGANA LETTER MU-4 + +1B0D4 +HENTAIGANA LETTER ME-1 + +1B0D5 +HENTAIGANA LETTER ME-2 + +1B0D6 +HENTAIGANA LETTER ME-MA + +1B0D7 +HENTAIGANA LETTER MO-1 + +1B0D8 +HENTAIGANA LETTER MO-2 + +1B0D9 +HENTAIGANA LETTER MO-3 + +1B0DA +HENTAIGANA LETTER MO-4 + +1B0DB +HENTAIGANA LETTER MO-5 + +1B0DC +HENTAIGANA LETTER MO-6 + +1B0DD +HENTAIGANA LETTER YA-1 + +1B0DE +HENTAIGANA LETTER YA-2 + +1B0DF +HENTAIGANA LETTER YA-3 + +1B0E0 +HENTAIGANA LETTER YA-4 + +1B0E1 +HENTAIGANA LETTER YA-5 + +1B0E2 +HENTAIGANA LETTER YA-YO + +1B0E3 +HENTAIGANA LETTER YU-1 + +1B0E4 +HENTAIGANA LETTER YU-2 + +1B0E5 +HENTAIGANA LETTER YU-3 + +1B0E6 +HENTAIGANA LETTER YU-4 + +1B0E7 +HENTAIGANA LETTER YO-1 + +1B0E8 +HENTAIGANA LETTER YO-2 + +1B0E9 +HENTAIGANA LETTER YO-3 + +1B0EA +HENTAIGANA LETTER YO-4 + +1B0EB +HENTAIGANA LETTER YO-5 + +1B0EC +HENTAIGANA LETTER YO-6 + +1B0ED +HENTAIGANA LETTER RA-1 + +1B0EE +HENTAIGANA LETTER RA-2 + +1B0EF +HENTAIGANA LETTER RA-3 + +1B0F0 +HENTAIGANA LETTER RA-4 + +1B0F1 +HENTAIGANA LETTER RI-1 + +1B0F2 +HENTAIGANA LETTER RI-2 + +1B0F3 +HENTAIGANA LETTER RI-3 + +1B0F4 +HENTAIGANA LETTER RI-4 + +1B0F5 +HENTAIGANA LETTER RI-5 + +1B0F6 +HENTAIGANA LETTER RI-6 + +1B0F7 +HENTAIGANA LETTER RI-7 + +1B0F8 +HENTAIGANA LETTER RU-1 + +1B0F9 +HENTAIGANA LETTER RU-2 + +1B0FA +HENTAIGANA LETTER RU-3 + +1B0FB +HENTAIGANA LETTER RU-4 + +1B0FC +HENTAIGANA LETTER RU-5 + +1B0FD +HENTAIGANA LETTER RU-6 + +1B0FE +HENTAIGANA LETTER RE-1 + +1B0FF +HENTAIGANA LETTER RE-2 + +1B100 +HENTAIGANA LETTER RE-3 + +1B101 +HENTAIGANA LETTER RE-4 + +1B102 +HENTAIGANA LETTER RO-1 + +1B103 +HENTAIGANA LETTER RO-2 + +1B104 +HENTAIGANA LETTER RO-3 + +1B105 +HENTAIGANA LETTER RO-4 + +1B106 +HENTAIGANA LETTER RO-5 + +1B107 +HENTAIGANA LETTER RO-6 + +1B108 +HENTAIGANA LETTER WA-1 + +1B109 +HENTAIGANA LETTER WA-2 + +1B10A +HENTAIGANA LETTER WA-3 + +1B10B +HENTAIGANA LETTER WA-4 + +1B10C +HENTAIGANA LETTER WA-5 + +1B10D +HENTAIGANA LETTER WI-1 + +1B10E +HENTAIGANA LETTER WI-2 + +1B10F +HENTAIGANA LETTER WI-3 + +1B110 +HENTAIGANA LETTER WI-4 + +1B111 +HENTAIGANA LETTER WI-5 + +1B112 +HENTAIGANA LETTER WE-1 + +1B113 +HENTAIGANA LETTER WE-2 + +1B114 +HENTAIGANA LETTER WE-3 + +1B115 +HENTAIGANA LETTER WE-4 + +1B116 +HENTAIGANA LETTER WO-1 + +1B117 +HENTAIGANA LETTER WO-2 + +1B118 +HENTAIGANA LETTER WO-3 + +1B119 +HENTAIGANA LETTER WO-4 + +1B11A +HENTAIGANA LETTER WO-5 + +1B11B +HENTAIGANA LETTER WO-6 + +1B11C +HENTAIGANA LETTER WO-7 + +1B11D +HENTAIGANA LETTER N-MU-MO-1 + +1B11E +HENTAIGANA LETTER N-MU-MO-2 + +1B11F +HIRAGANA LETTER ARCHAIC WU + +1B120 +KATAKANA LETTER ARCHAIC YI + +1B121 +KATAKANA LETTER ARCHAIC YE + +1B122 +KATAKANA LETTER ARCHAIC WU + +1B132 +HIRAGANA LETTER SMALL KO + +1B150 +HIRAGANA LETTER SMALL WI + +1B151 +HIRAGANA LETTER SMALL WE + +1B152 +HIRAGANA LETTER SMALL WO + +1B155 +KATAKANA LETTER SMALL KO + +1B164 +KATAKANA LETTER SMALL WI + +1B165 +KATAKANA LETTER SMALL WE + +1B166 +KATAKANA LETTER SMALL WO + +1B167 +KATAKANA LETTER SMALL N + +1BC00 +DUPLOYAN LETTER H + +1BC01 +DUPLOYAN LETTER X + +1BC02 +DUPLOYAN LETTER P + +1BC03 +DUPLOYAN LETTER T + +1BC04 +DUPLOYAN LETTER F + +1BC05 +DUPLOYAN LETTER K + +1BC06 +DUPLOYAN LETTER L + +1BC07 +DUPLOYAN LETTER B + +1BC08 +DUPLOYAN LETTER D + +1BC09 +DUPLOYAN LETTER V + +1BC0A +DUPLOYAN LETTER G + +1BC0B +DUPLOYAN LETTER R + +1BC0C +DUPLOYAN LETTER P N + +1BC0D +DUPLOYAN LETTER D S + +1BC0E +DUPLOYAN LETTER F N + +1BC0F +DUPLOYAN LETTER K M + +1BC10 +DUPLOYAN LETTER R S + +1BC11 +DUPLOYAN LETTER TH + +1BC12 +DUPLOYAN LETTER SLOAN DH + +1BC13 +DUPLOYAN LETTER DH + +1BC14 +DUPLOYAN LETTER KK + +1BC15 +DUPLOYAN LETTER SLOAN J + +1BC16 +DUPLOYAN LETTER HL + +1BC17 +DUPLOYAN LETTER LH + +1BC18 +DUPLOYAN LETTER RH + +1BC19 +DUPLOYAN LETTER M + +1BC1A +DUPLOYAN LETTER N + +1BC1B +DUPLOYAN LETTER J + +1BC1C +DUPLOYAN LETTER S + +1BC1D +DUPLOYAN LETTER M N + +1BC1E +DUPLOYAN LETTER N M + +1BC1F +DUPLOYAN LETTER J M + +1BC20 +DUPLOYAN LETTER S J + +1BC21 +DUPLOYAN LETTER M WITH DOT + +1BC22 +DUPLOYAN LETTER N WITH DOT + +1BC23 +DUPLOYAN LETTER J WITH DOT + +1BC24 +DUPLOYAN LETTER J WITH DOTS INSIDE AND ABOVE + +1BC25 +DUPLOYAN LETTER S WITH DOT + +1BC26 +DUPLOYAN LETTER S WITH DOT BELOW + +1BC27 +DUPLOYAN LETTER M S + +1BC28 +DUPLOYAN LETTER N S + +1BC29 +DUPLOYAN LETTER J S + +1BC2A +DUPLOYAN LETTER S S + +1BC2B +DUPLOYAN LETTER M N S + +1BC2C +DUPLOYAN LETTER N M S + +1BC2D +DUPLOYAN LETTER J M S + +1BC2E +DUPLOYAN LETTER S J S + +1BC2F +DUPLOYAN LETTER J S WITH DOT + +1BC30 +DUPLOYAN LETTER J N + +1BC31 +DUPLOYAN LETTER J N S + +1BC32 +DUPLOYAN LETTER S T + +1BC33 +DUPLOYAN LETTER S T R + +1BC34 +DUPLOYAN LETTER S P + +1BC35 +DUPLOYAN LETTER S P R + +1BC36 +DUPLOYAN LETTER T S + +1BC37 +DUPLOYAN LETTER T R S + +1BC38 +DUPLOYAN LETTER W + +1BC39 +DUPLOYAN LETTER WH + +1BC3A +DUPLOYAN LETTER W R + +1BC3B +DUPLOYAN LETTER S N + +1BC3C +DUPLOYAN LETTER S M + +1BC3D +DUPLOYAN LETTER K R S + +1BC3E +DUPLOYAN LETTER G R S + +1BC3F +DUPLOYAN LETTER S K + +1BC40 +DUPLOYAN LETTER S K R + +1BC41 +DUPLOYAN LETTER A + +1BC42 +DUPLOYAN LETTER SLOAN OW + +1BC43 +DUPLOYAN LETTER OA + +1BC44 +DUPLOYAN LETTER O + +1BC45 +DUPLOYAN LETTER AOU + +1BC46 +DUPLOYAN LETTER I + +1BC47 +DUPLOYAN LETTER E + +1BC48 +DUPLOYAN LETTER IE + +1BC49 +DUPLOYAN LETTER SHORT I + +1BC4A +DUPLOYAN LETTER UI + +1BC4B +DUPLOYAN LETTER EE + +1BC4C +DUPLOYAN LETTER SLOAN EH + +1BC4D +DUPLOYAN LETTER ROMANIAN I + +1BC4E +DUPLOYAN LETTER SLOAN EE + +1BC4F +DUPLOYAN LETTER LONG I + +1BC50 +DUPLOYAN LETTER YE + +1BC51 +DUPLOYAN LETTER U + +1BC52 +DUPLOYAN LETTER EU + +1BC53 +DUPLOYAN LETTER XW + +1BC54 +DUPLOYAN LETTER U N + +1BC55 +DUPLOYAN LETTER LONG U + +1BC56 +DUPLOYAN LETTER ROMANIAN U + +1BC57 +DUPLOYAN LETTER UH + +1BC58 +DUPLOYAN LETTER SLOAN U + +1BC59 +DUPLOYAN LETTER OOH + +1BC5A +DUPLOYAN LETTER OW + +1BC5B +DUPLOYAN LETTER OU + +1BC5C +DUPLOYAN LETTER WA + +1BC5D +DUPLOYAN LETTER WO + +1BC5E +DUPLOYAN LETTER WI + +1BC5F +DUPLOYAN LETTER WEI + +1BC60 +DUPLOYAN LETTER WOW + +1BC61 +DUPLOYAN LETTER NASAL U + +1BC62 +DUPLOYAN LETTER NASAL O + +1BC63 +DUPLOYAN LETTER NASAL I + +1BC64 +DUPLOYAN LETTER NASAL A + +1BC65 +DUPLOYAN LETTER PERNIN AN + +1BC66 +DUPLOYAN LETTER PERNIN AM + +1BC67 +DUPLOYAN LETTER SLOAN EN + +1BC68 +DUPLOYAN LETTER SLOAN AN + +1BC69 +DUPLOYAN LETTER SLOAN ON + +1BC6A +DUPLOYAN LETTER VOCALIC M + +1BC70 +DUPLOYAN AFFIX LEFT HORIZONTAL SECANT + +1BC71 +DUPLOYAN AFFIX MID HORIZONTAL SECANT + +1BC72 +DUPLOYAN AFFIX RIGHT HORIZONTAL SECANT + +1BC73 +DUPLOYAN AFFIX LOW VERTICAL SECANT + +1BC74 +DUPLOYAN AFFIX MID VERTICAL SECANT + +1BC75 +DUPLOYAN AFFIX HIGH VERTICAL SECANT + +1BC76 +DUPLOYAN AFFIX ATTACHED SECANT + +1BC77 +DUPLOYAN AFFIX ATTACHED LEFT-TO-RIGHT SECANT + +1BC78 +DUPLOYAN AFFIX ATTACHED TANGENT + +1BC79 +DUPLOYAN AFFIX ATTACHED TAIL + +1BC7A +DUPLOYAN AFFIX ATTACHED E HOOK + +1BC7B +DUPLOYAN AFFIX ATTACHED I HOOK + +1BC7C +DUPLOYAN AFFIX ATTACHED TANGENT HOOK + +1BC80 +DUPLOYAN AFFIX HIGH ACUTE + +1BC81 +DUPLOYAN AFFIX HIGH TIGHT ACUTE + +1BC82 +DUPLOYAN AFFIX HIGH GRAVE + +1BC83 +DUPLOYAN AFFIX HIGH LONG GRAVE + +1BC84 +DUPLOYAN AFFIX HIGH DOT + +1BC85 +DUPLOYAN AFFIX HIGH CIRCLE + +1BC86 +DUPLOYAN AFFIX HIGH LINE + +1BC87 +DUPLOYAN AFFIX HIGH WAVE + +1BC88 +DUPLOYAN AFFIX HIGH VERTICAL + +1BC90 +DUPLOYAN AFFIX LOW ACUTE + +1BC91 +DUPLOYAN AFFIX LOW TIGHT ACUTE + +1BC92 +DUPLOYAN AFFIX LOW GRAVE + +1BC93 +DUPLOYAN AFFIX LOW LONG GRAVE + +1BC94 +DUPLOYAN AFFIX LOW DOT + +1BC95 +DUPLOYAN AFFIX LOW CIRCLE + +1BC96 +DUPLOYAN AFFIX LOW LINE + +1BC97 +DUPLOYAN AFFIX LOW WAVE + +1BC98 +DUPLOYAN AFFIX LOW VERTICAL + +1BC99 +DUPLOYAN AFFIX LOW ARROW + +1BC9C +DUPLOYAN SIGN O WITH CROSS + +1BC9D +DUPLOYAN THICK LETTER SELECTOR + +1BC9E +DUPLOYAN DOUBLE MARK + +1BC9F +DUPLOYAN PUNCTUATION CHINOOK FULL STOP + +1BCA0 +SHORTHAND FORMAT LETTER OVERLAP + +1BCA1 +SHORTHAND FORMAT CONTINUING OVERLAP + +1BCA2 +SHORTHAND FORMAT DOWN STEP + +1BCA3 +SHORTHAND FORMAT UP STEP + +1CC00 +UP-POINTING GO-KART + +1CC01 +RIGHT-POINTING GO-KART + +1CC02 +LEFT-POINTING STICK FIGURE + +1CC03 +RIGHT-POINTING STICK FIGURE + +1CC04 +DOWN-POINTING STICK FIGURE + +1CC05 +LOWER HORIZONTAL RULER SEGMENT + +1CC06 +RIGHT VERTICAL RULER SEGMENT + +1CC07 +LOWER RIGHT RULER SEGMENT + +1CC08 +ANTENNA + +1CC09 +HORIZONTAL RESISTOR SEGMENT + +1CC0A +VERTICAL RESISTOR SEGMENT + +1CC0B +LEFT THIRD INDUCTOR + +1CC0C +MIDDLE THIRD INDUCTOR + +1CC0D +RIGHT THIRD INDUCTOR + +1CC0E +LEFT-POINTING DIODE + +1CC0F +RIGHT-POINTING DIODE + +1CC10 +NPN TRANSISTOR + +1CC11 +PNP TRANSISTOR + +1CC12 +RECEPTACLE + +1CC13 +HORIZONTAL CAPACITOR + +1CC14 +VERTICAL CAPACITOR + +1CC15 +LOGIC GATE OR + +1CC16 +LOGIC GATE AND + +1CC17 +LOGIC GATE INVERTED INPUTS + +1CC18 +LOGIC GATE INVERTED OUTPUT + +1CC19 +LOGIC GATE BUFFER + +1CC1A +LOGIC GATE BUFFER WITH INVERTED INPUT + +1CC1B +BOX DRAWINGS LIGHT HORIZONTAL AND UPPER RIGHT + +1CC1C +BOX DRAWINGS LIGHT HORIZONTAL AND LOWER RIGHT + +1CC1D +BOX DRAWINGS LIGHT TOP AND UPPER LEFT + +1CC1E +BOX DRAWINGS LIGHT BOTTOM AND LOWER LEFT + +1CC1F +BOX DRAWINGS DOUBLE DIAGONAL UPPER RIGHT TO LOWER LEFT + +1CC20 +BOX DRAWINGS DOUBLE DIAGONAL UPPER LEFT TO LOWER RIGHT + +1CC21 +SEPARATED BLOCK QUADRANT-1 + +1CC22 +SEPARATED BLOCK QUADRANT-2 + +1CC23 +SEPARATED BLOCK QUADRANT-12 + +1CC24 +SEPARATED BLOCK QUADRANT-3 + +1CC25 +SEPARATED BLOCK QUADRANT-13 + +1CC26 +SEPARATED BLOCK QUADRANT-23 + +1CC27 +SEPARATED BLOCK QUADRANT-123 + +1CC28 +SEPARATED BLOCK QUADRANT-4 + +1CC29 +SEPARATED BLOCK QUADRANT-14 + +1CC2A +SEPARATED BLOCK QUADRANT-24 + +1CC2B +SEPARATED BLOCK QUADRANT-124 + +1CC2C +SEPARATED BLOCK QUADRANT-34 + +1CC2D +SEPARATED BLOCK QUADRANT-134 + +1CC2E +SEPARATED BLOCK QUADRANT-234 + +1CC2F +SEPARATED BLOCK QUADRANT-1234 + +1CC30 +UPPER LEFT TWELFTH CIRCLE + +1CC31 +UPPER CENTRE LEFT TWELFTH CIRCLE + +1CC32 +UPPER CENTRE RIGHT TWELFTH CIRCLE + +1CC33 +UPPER RIGHT TWELFTH CIRCLE + +1CC34 +UPPER MIDDLE LEFT TWELFTH CIRCLE + +1CC35 +UPPER LEFT QUARTER CIRCLE + +1CC36 +UPPER RIGHT QUARTER CIRCLE + +1CC37 +UPPER MIDDLE RIGHT TWELFTH CIRCLE + +1CC38 +LOWER MIDDLE LEFT TWELFTH CIRCLE + +1CC39 +LOWER LEFT QUARTER CIRCLE + +1CC3A +LOWER RIGHT QUARTER CIRCLE + +1CC3B +LOWER MIDDLE RIGHT TWELFTH CIRCLE + +1CC3C +LOWER LEFT TWELFTH CIRCLE + +1CC3D +LOWER CENTRE LEFT TWELFTH CIRCLE + +1CC3E +LOWER CENTRE RIGHT TWELFTH CIRCLE + +1CC3F +LOWER RIGHT TWELFTH CIRCLE + +1CC40 +SPARSE HORIZONTAL FILL + +1CC41 +SPARSE VERTICAL FILL + +1CC42 +ORTHOGONAL CROSSHATCH FILL + +1CC43 +DIAGONAL CROSSHATCH FILL + +1CC44 +DENSE VERTICAL FILL + +1CC45 +DENSE HORIZONTAL FILL + +1CC46 +SPECKLE FILL FRAME-1 + +1CC47 +SPECKLE FILL FRAME-2 + +1CC48 +LEFT-FACING BASSINET + +1CC49 +RIGHT-FACING BASSINET + +1CC4A +FLYING SAUCER WITH BEAMS + +1CC4B +FLYING SAUCER WITHOUT BEAMS + +1CC4C +ALIEN MONSTER OPEN JAWS + +1CC4D +ALIEN MONSTER CLOSED JAWS + +1CC4E +ALIEN SQUID OPEN TENTACLES + +1CC4F +ALIEN SQUID CLOSED TENTACLES + +1CC50 +ALIEN CRAB STEPPING RIGHT + +1CC51 +ALIEN CRAB STEPPING LEFT + +1CC52 +ALIEN SPIDER CROUCHING + +1CC53 +ALIEN SPIDER SPREAD + +1CC54 +ALIEN MONSTER STEP-1 + +1CC55 +ALIEN MONSTER STEP-2 + +1CC56 +LEFT-POINTING ROCKET SHIP + +1CC57 +UP-POINTING ROCKET SHIP + +1CC58 +RIGHT-POINTING ROCKET SHIP + +1CC59 +DOWN-POINTING ROCKET SHIP + +1CC5A +TOP HALF LEFT-FACING ROBOT + +1CC5B +TOP HALF FORWARD-FACING ROBOT + +1CC5C +TOP HALF RIGHT-FACING ROBOT + +1CC5D +BOTTOM HALF LEFT-FACING ROBOT + +1CC5E +BOTTOM HALF FORWARD-FACING ROBOT + +1CC5F +BOTTOM HALF RIGHT-FACING ROBOT + +1CC60 +LEFT-POINTING ATOMIC BOMB + +1CC61 +UP-POINTING ATOMIC BOMB + +1CC62 +RIGHT-POINTING ATOMIC BOMB + +1CC63 +DOWN-POINTING ATOMIC BOMB + +1CC64 +MUSHROOM CLOUD + +1CC65 +LEFT-POINTING RIFLE + +1CC66 +UP-POINTING RIFLE + +1CC67 +RIGHT-POINTING RIFLE + +1CC68 +DOWN-POINTING RIFLE + +1CC69 +EIGHT RAYS INWARD + +1CC6A +EIGHT RAYS OUTWARD + +1CC6B +BLACK LARGE CIRCLE MINUS LEFT QUARTER SECTION + +1CC6C +BLACK LARGE CIRCLE MINUS UPPER QUARTER SECTION + +1CC6D +BLACK LARGE CIRCLE MINUS RIGHT QUARTER SECTION + +1CC6E +BLACK LARGE CIRCLE MINUS LOWER QUARTER SECTION + +1CC6F +BLACK NEUTRAL FACE + +1CC70 +LEFT-FACING SNAKE HEAD WITH OPEN MOUTH + +1CC71 +UP-FACING SNAKE HEAD WITH OPEN MOUTH + +1CC72 +RIGHT-FACING SNAKE HEAD WITH OPEN MOUTH + +1CC73 +DOWN-FACING SNAKE HEAD WITH OPEN MOUTH + +1CC74 +LEFT-FACING SNAKE HEAD WITH CLOSED MOUTH + +1CC75 +UP-FACING SNAKE HEAD WITH CLOSED MOUTH + +1CC76 +RIGHT-FACING SNAKE HEAD WITH CLOSED MOUTH + +1CC77 +DOWN-FACING SNAKE HEAD WITH CLOSED MOUTH + +1CC78 +LEFT-POINTING ENERGY WAVE + +1CC79 +UP-POINTING ENERGY WAVE + +1CC7A +RIGHT-POINTING ENERGY WAVE + +1CC7B +DOWN-POINTING ENERGY WAVE + +1CC7C +SQUARE SPIRAL FROM TOP LEFT + +1CC7D +SQUARE SPIRAL FROM TOP RIGHT + +1CC7E +SQUARE SPIRAL FROM BOTTOM RIGHT + +1CC7F +SQUARE SPIRAL FROM BOTTOM LEFT + +1CC80 +STRIPED LEFT-POINTING TRIANGLE + +1CC81 +STRIPED UP-POINTING TRIANGLE + +1CC82 +STRIPED RIGHT-POINTING TRIANGLE + +1CC83 +STRIPED DOWN-POINTING TRIANGLE + +1CC84 +VERTICAL LADDER + +1CC85 +HORIZONTAL LADDER + +1CC86 +WHITE LOWER LEFT POINTER + +1CC87 +WHITE LOWER RIGHT POINTER + +1CC88 +TWO RINGS ALIGNED HORIZONTALLY + +1CC89 +SQUARE FOUR CORNER SALTIRES + +1CC8A +SQUARE FOUR CORNER DIAGONALS + +1CC8B +SQUARE FOUR CORNER BLACK TRIANGLES + +1CC8C +SQUARE APERTURE + +1CC8D +INVERSE BLACK DIAMOND + +1CC8E +LEFT AND UPPER ONE EIGHTH BLOCK CONTAINING BLACK SMALL SQUARE + +1CC8F +INVERSE BLACK SMALL SQUARE + +1CC90 +VERTICAL LINE WITH FOUR TICK MARKS + +1CC91 +HORIZONTAL LINE WITH FOUR TICK MARKS + +1CC92 +LEFT-FACING FISH + +1CC93 +RIGHT-FACING FISH + +1CC94 +LEFT-FACING FISH WITH OPEN MOUTH + +1CC95 +RIGHT-FACING FISH WITH OPEN MOUTH + +1CC96 +FLAPPING BIRD + +1CC97 +LEFT-POINTING RACING CAR + +1CC98 +UP-POINTING RACING CAR + +1CC99 +RIGHT-POINTING RACING CAR + +1CC9A +DOWN-POINTING RACING CAR + +1CC9B +HORIZONTAL RACING CAR + +1CC9C +VERTICAL RACING CAR + +1CC9D +VERTICAL GO-KART + +1CC9E +LEFT-POINTING TANK + +1CC9F +RIGHT-POINTING TANK + +1CCA0 +LEFT-POINTING ROCKET BOOSTER + +1CCA1 +RIGHT-POINTING ROCKET BOOSTER + +1CCA2 +LEFT-POINTING ROLLER COASTER CAR + +1CCA3 +RIGHT-POINTING ROLLER COASTER CAR + +1CCA4 +LEFT HALF FLYING SAUCER + +1CCA5 +RIGHT HALF FLYING SAUCER + +1CCA6 +UPPER LEFT QUADRANT FACE WITH OPEN EYES + +1CCA7 +UPPER RIGHT QUADRANT FACE WITH OPEN EYES + +1CCA8 +UPPER LEFT QUADRANT FACE WITH CLOSED EYES + +1CCA9 +UPPER RIGHT QUADRANT FACE WITH CLOSED EYES + +1CCAA +LOWER LEFT QUADRANT SMILING FACE + +1CCAB +LOWER RIGHT QUADRANT SMILING FACE + +1CCAC +LOWER LEFT QUADRANT NEUTRAL FACE + +1CCAD +LOWER RIGHT QUADRANT NEUTRAL FACE + +1CCAE +LOWER LEFT QUADRANT FACE WITH OPEN MOUTH + +1CCAF +LOWER RIGHT QUADRANT FACE WITH OPEN MOUTH + +1CCB0 +LOWER LEFT QUADRANT FROWNING FACE + +1CCB1 +LOWER RIGHT QUADRANT FROWNING FACE + +1CCB2 +UPPER LEFT QUADRANT TELEVISION + +1CCB3 +UPPER RIGHT QUADRANT TELEVISION + +1CCB4 +LOWER LEFT QUADRANT TELEVISION + +1CCB5 +LOWER RIGHT QUADRANT TELEVISION + +1CCB6 +UPPER LEFT QUADRANT MICROCOMPUTER + +1CCB7 +UPPER RIGHT QUADRANT MICROCOMPUTER + +1CCB8 +LOWER LEFT QUADRANT MICROCOMPUTER + +1CCB9 +LOWER RIGHT QUADRANT MICROCOMPUTER + +1CCBA +UPPER LEFT QUADRANT CHESS KING + +1CCBB +UPPER RIGHT QUADRANT CHESS KING + +1CCBC +LOWER LEFT QUADRANT CHESS KING + +1CCBD +LOWER RIGHT QUADRANT CHESS KING + +1CCBE +UPPER LEFT QUADRANT CHESS QUEEN + +1CCBF +UPPER RIGHT QUADRANT CHESS QUEEN + +1CCC0 +LOWER LEFT QUADRANT CHESS QUEEN + +1CCC1 +LOWER RIGHT QUADRANT CHESS QUEEN + +1CCC2 +UPPER LEFT QUADRANT CHESS ROOK + +1CCC3 +UPPER RIGHT QUADRANT CHESS ROOK + +1CCC4 +LOWER LEFT QUADRANT CHESS ROOK + +1CCC5 +LOWER RIGHT QUADRANT CHESS ROOK + +1CCC6 +UPPER LEFT QUADRANT CHESS BISHOP + +1CCC7 +UPPER RIGHT QUADRANT CHESS BISHOP + +1CCC8 +LOWER LEFT QUADRANT CHESS BISHOP + +1CCC9 +LOWER RIGHT QUADRANT CHESS BISHOP + +1CCCA +UPPER LEFT QUADRANT CHESS KNIGHT + +1CCCB +UPPER RIGHT QUADRANT CHESS KNIGHT + +1CCCC +LOWER LEFT QUADRANT CHESS KNIGHT + +1CCCD +LOWER RIGHT QUADRANT CHESS KNIGHT + +1CCCE +UPPER LEFT QUADRANT CHESS PAWN + +1CCCF +UPPER RIGHT QUADRANT CHESS PAWN + +1CCD0 +LOWER LEFT QUADRANT CHESS PAWN + +1CCD1 +LOWER RIGHT QUADRANT CHESS PAWN + +1CCD2 +UPPER LEFT QUADRANT STANDING KNIGHT + +1CCD3 +UPPER RIGHT QUADRANT STANDING KNIGHT + +1CCD4 +LOWER LEFT QUADRANT STANDING KNIGHT + +1CCD5 +LOWER RIGHT QUADRANT STANDING KNIGHT + +1CCD6 +OUTLINED LATIN CAPITAL LETTER A + +1CCD7 +OUTLINED LATIN CAPITAL LETTER B + +1CCD8 +OUTLINED LATIN CAPITAL LETTER C + +1CCD9 +OUTLINED LATIN CAPITAL LETTER D + +1CCDA +OUTLINED LATIN CAPITAL LETTER E + +1CCDB +OUTLINED LATIN CAPITAL LETTER F + +1CCDC +OUTLINED LATIN CAPITAL LETTER G + +1CCDD +OUTLINED LATIN CAPITAL LETTER H + +1CCDE +OUTLINED LATIN CAPITAL LETTER I + +1CCDF +OUTLINED LATIN CAPITAL LETTER J + +1CCE0 +OUTLINED LATIN CAPITAL LETTER K + +1CCE1 +OUTLINED LATIN CAPITAL LETTER L + +1CCE2 +OUTLINED LATIN CAPITAL LETTER M + +1CCE3 +OUTLINED LATIN CAPITAL LETTER N + +1CCE4 +OUTLINED LATIN CAPITAL LETTER O + +1CCE5 +OUTLINED LATIN CAPITAL LETTER P + +1CCE6 +OUTLINED LATIN CAPITAL LETTER Q + +1CCE7 +OUTLINED LATIN CAPITAL LETTER R + +1CCE8 +OUTLINED LATIN CAPITAL LETTER S + +1CCE9 +OUTLINED LATIN CAPITAL LETTER T + +1CCEA +OUTLINED LATIN CAPITAL LETTER U + +1CCEB +OUTLINED LATIN CAPITAL LETTER V + +1CCEC +OUTLINED LATIN CAPITAL LETTER W + +1CCED +OUTLINED LATIN CAPITAL LETTER X + +1CCEE +OUTLINED LATIN CAPITAL LETTER Y + +1CCEF +OUTLINED LATIN CAPITAL LETTER Z + +1CCF0 +OUTLINED DIGIT ZERO + +1CCF1 +OUTLINED DIGIT ONE + +1CCF2 +OUTLINED DIGIT TWO + +1CCF3 +OUTLINED DIGIT THREE + +1CCF4 +OUTLINED DIGIT FOUR + +1CCF5 +OUTLINED DIGIT FIVE + +1CCF6 +OUTLINED DIGIT SIX + +1CCF7 +OUTLINED DIGIT SEVEN + +1CCF8 +OUTLINED DIGIT EIGHT + +1CCF9 +OUTLINED DIGIT NINE + +1CCFA +SNAKE SYMBOL + +1CCFB +FLYING SAUCER SYMBOL + +1CCFC +NOSE SYMBOL + +1CD00 +BLOCK OCTANT-3 + +1CD01 +BLOCK OCTANT-23 + +1CD02 +BLOCK OCTANT-123 + +1CD03 +BLOCK OCTANT-4 + +1CD04 +BLOCK OCTANT-14 + +1CD05 +BLOCK OCTANT-124 + +1CD06 +BLOCK OCTANT-34 + +1CD07 +BLOCK OCTANT-134 + +1CD08 +BLOCK OCTANT-234 + +1CD09 +BLOCK OCTANT-5 + +1CD0A +BLOCK OCTANT-15 + +1CD0B +BLOCK OCTANT-25 + +1CD0C +BLOCK OCTANT-125 + +1CD0D +BLOCK OCTANT-135 + +1CD0E +BLOCK OCTANT-235 + +1CD0F +BLOCK OCTANT-1235 + +1CD10 +BLOCK OCTANT-45 + +1CD11 +BLOCK OCTANT-145 + +1CD12 +BLOCK OCTANT-245 + +1CD13 +BLOCK OCTANT-1245 + +1CD14 +BLOCK OCTANT-345 + +1CD15 +BLOCK OCTANT-1345 + +1CD16 +BLOCK OCTANT-2345 + +1CD17 +BLOCK OCTANT-12345 + +1CD18 +BLOCK OCTANT-6 + +1CD19 +BLOCK OCTANT-16 + +1CD1A +BLOCK OCTANT-26 + +1CD1B +BLOCK OCTANT-126 + +1CD1C +BLOCK OCTANT-36 + +1CD1D +BLOCK OCTANT-136 + +1CD1E +BLOCK OCTANT-236 + +1CD1F +BLOCK OCTANT-1236 + +1CD20 +BLOCK OCTANT-146 + +1CD21 +BLOCK OCTANT-246 + +1CD22 +BLOCK OCTANT-1246 + +1CD23 +BLOCK OCTANT-346 + +1CD24 +BLOCK OCTANT-1346 + +1CD25 +BLOCK OCTANT-2346 + +1CD26 +BLOCK OCTANT-12346 + +1CD27 +BLOCK OCTANT-56 + +1CD28 +BLOCK OCTANT-156 + +1CD29 +BLOCK OCTANT-256 + +1CD2A +BLOCK OCTANT-1256 + +1CD2B +BLOCK OCTANT-356 + +1CD2C +BLOCK OCTANT-1356 + +1CD2D +BLOCK OCTANT-2356 + +1CD2E +BLOCK OCTANT-12356 + +1CD2F +BLOCK OCTANT-456 + +1CD30 +BLOCK OCTANT-1456 + +1CD31 +BLOCK OCTANT-2456 + +1CD32 +BLOCK OCTANT-12456 + +1CD33 +BLOCK OCTANT-3456 + +1CD34 +BLOCK OCTANT-13456 + +1CD35 +BLOCK OCTANT-23456 + +1CD36 +BLOCK OCTANT-17 + +1CD37 +BLOCK OCTANT-27 + +1CD38 +BLOCK OCTANT-127 + +1CD39 +BLOCK OCTANT-37 + +1CD3A +BLOCK OCTANT-137 + +1CD3B +BLOCK OCTANT-237 + +1CD3C +BLOCK OCTANT-1237 + +1CD3D +BLOCK OCTANT-47 + +1CD3E +BLOCK OCTANT-147 + +1CD3F +BLOCK OCTANT-247 + +1CD40 +BLOCK OCTANT-1247 + +1CD41 +BLOCK OCTANT-347 + +1CD42 +BLOCK OCTANT-1347 + +1CD43 +BLOCK OCTANT-2347 + +1CD44 +BLOCK OCTANT-12347 + +1CD45 +BLOCK OCTANT-157 + +1CD46 +BLOCK OCTANT-257 + +1CD47 +BLOCK OCTANT-1257 + +1CD48 +BLOCK OCTANT-357 + +1CD49 +BLOCK OCTANT-2357 + +1CD4A +BLOCK OCTANT-12357 + +1CD4B +BLOCK OCTANT-457 + +1CD4C +BLOCK OCTANT-1457 + +1CD4D +BLOCK OCTANT-12457 + +1CD4E +BLOCK OCTANT-3457 + +1CD4F +BLOCK OCTANT-13457 + +1CD50 +BLOCK OCTANT-23457 + +1CD51 +BLOCK OCTANT-67 + +1CD52 +BLOCK OCTANT-167 + +1CD53 +BLOCK OCTANT-267 + +1CD54 +BLOCK OCTANT-1267 + +1CD55 +BLOCK OCTANT-367 + +1CD56 +BLOCK OCTANT-1367 + +1CD57 +BLOCK OCTANT-2367 + +1CD58 +BLOCK OCTANT-12367 + +1CD59 +BLOCK OCTANT-467 + +1CD5A +BLOCK OCTANT-1467 + +1CD5B +BLOCK OCTANT-2467 + +1CD5C +BLOCK OCTANT-12467 + +1CD5D +BLOCK OCTANT-3467 + +1CD5E +BLOCK OCTANT-13467 + +1CD5F +BLOCK OCTANT-23467 + +1CD60 +BLOCK OCTANT-123467 + +1CD61 +BLOCK OCTANT-567 + +1CD62 +BLOCK OCTANT-1567 + +1CD63 +BLOCK OCTANT-2567 + +1CD64 +BLOCK OCTANT-12567 + +1CD65 +BLOCK OCTANT-3567 + +1CD66 +BLOCK OCTANT-13567 + +1CD67 +BLOCK OCTANT-23567 + +1CD68 +BLOCK OCTANT-123567 + +1CD69 +BLOCK OCTANT-4567 + +1CD6A +BLOCK OCTANT-14567 + +1CD6B +BLOCK OCTANT-24567 + +1CD6C +BLOCK OCTANT-124567 + +1CD6D +BLOCK OCTANT-34567 + +1CD6E +BLOCK OCTANT-134567 + +1CD6F +BLOCK OCTANT-234567 + +1CD70 +BLOCK OCTANT-1234567 + +1CD71 +BLOCK OCTANT-18 + +1CD72 +BLOCK OCTANT-28 + +1CD73 +BLOCK OCTANT-128 + +1CD74 +BLOCK OCTANT-38 + +1CD75 +BLOCK OCTANT-138 + +1CD76 +BLOCK OCTANT-238 + +1CD77 +BLOCK OCTANT-1238 + +1CD78 +BLOCK OCTANT-48 + +1CD79 +BLOCK OCTANT-148 + +1CD7A +BLOCK OCTANT-248 + +1CD7B +BLOCK OCTANT-1248 + +1CD7C +BLOCK OCTANT-348 + +1CD7D +BLOCK OCTANT-1348 + +1CD7E +BLOCK OCTANT-2348 + +1CD7F +BLOCK OCTANT-12348 + +1CD80 +BLOCK OCTANT-58 + +1CD81 +BLOCK OCTANT-158 + +1CD82 +BLOCK OCTANT-258 + +1CD83 +BLOCK OCTANT-1258 + +1CD84 +BLOCK OCTANT-358 + +1CD85 +BLOCK OCTANT-1358 + +1CD86 +BLOCK OCTANT-2358 + +1CD87 +BLOCK OCTANT-12358 + +1CD88 +BLOCK OCTANT-458 + +1CD89 +BLOCK OCTANT-1458 + +1CD8A +BLOCK OCTANT-2458 + +1CD8B +BLOCK OCTANT-12458 + +1CD8C +BLOCK OCTANT-3458 + +1CD8D +BLOCK OCTANT-13458 + +1CD8E +BLOCK OCTANT-23458 + +1CD8F +BLOCK OCTANT-123458 + +1CD90 +BLOCK OCTANT-168 + +1CD91 +BLOCK OCTANT-268 + +1CD92 +BLOCK OCTANT-1268 + +1CD93 +BLOCK OCTANT-368 + +1CD94 +BLOCK OCTANT-2368 + +1CD95 +BLOCK OCTANT-12368 + +1CD96 +BLOCK OCTANT-468 + +1CD97 +BLOCK OCTANT-1468 + +1CD98 +BLOCK OCTANT-12468 + +1CD99 +BLOCK OCTANT-3468 + +1CD9A +BLOCK OCTANT-13468 + +1CD9B +BLOCK OCTANT-23468 + +1CD9C +BLOCK OCTANT-568 + +1CD9D +BLOCK OCTANT-1568 + +1CD9E +BLOCK OCTANT-2568 + +1CD9F +BLOCK OCTANT-12568 + +1CDA0 +BLOCK OCTANT-3568 + +1CDA1 +BLOCK OCTANT-13568 + +1CDA2 +BLOCK OCTANT-23568 + +1CDA3 +BLOCK OCTANT-123568 + +1CDA4 +BLOCK OCTANT-4568 + +1CDA5 +BLOCK OCTANT-14568 + +1CDA6 +BLOCK OCTANT-24568 + +1CDA7 +BLOCK OCTANT-124568 + +1CDA8 +BLOCK OCTANT-34568 + +1CDA9 +BLOCK OCTANT-134568 + +1CDAA +BLOCK OCTANT-234568 + +1CDAB +BLOCK OCTANT-1234568 + +1CDAC +BLOCK OCTANT-178 + +1CDAD +BLOCK OCTANT-278 + +1CDAE +BLOCK OCTANT-1278 + +1CDAF +BLOCK OCTANT-378 + +1CDB0 +BLOCK OCTANT-1378 + +1CDB1 +BLOCK OCTANT-2378 + +1CDB2 +BLOCK OCTANT-12378 + +1CDB3 +BLOCK OCTANT-478 + +1CDB4 +BLOCK OCTANT-1478 + +1CDB5 +BLOCK OCTANT-2478 + +1CDB6 +BLOCK OCTANT-12478 + +1CDB7 +BLOCK OCTANT-3478 + +1CDB8 +BLOCK OCTANT-13478 + +1CDB9 +BLOCK OCTANT-23478 + +1CDBA +BLOCK OCTANT-123478 + +1CDBB +BLOCK OCTANT-578 + +1CDBC +BLOCK OCTANT-1578 + +1CDBD +BLOCK OCTANT-2578 + +1CDBE +BLOCK OCTANT-12578 + +1CDBF +BLOCK OCTANT-3578 + +1CDC0 +BLOCK OCTANT-13578 + +1CDC1 +BLOCK OCTANT-23578 + +1CDC2 +BLOCK OCTANT-123578 + +1CDC3 +BLOCK OCTANT-4578 + +1CDC4 +BLOCK OCTANT-14578 + +1CDC5 +BLOCK OCTANT-24578 + +1CDC6 +BLOCK OCTANT-124578 + +1CDC7 +BLOCK OCTANT-34578 + +1CDC8 +BLOCK OCTANT-134578 + +1CDC9 +BLOCK OCTANT-234578 + +1CDCA +BLOCK OCTANT-1234578 + +1CDCB +BLOCK OCTANT-678 + +1CDCC +BLOCK OCTANT-1678 + +1CDCD +BLOCK OCTANT-2678 + +1CDCE +BLOCK OCTANT-12678 + +1CDCF +BLOCK OCTANT-3678 + +1CDD0 +BLOCK OCTANT-13678 + +1CDD1 +BLOCK OCTANT-23678 + +1CDD2 +BLOCK OCTANT-123678 + +1CDD3 +BLOCK OCTANT-4678 + +1CDD4 +BLOCK OCTANT-14678 + +1CDD5 +BLOCK OCTANT-24678 + +1CDD6 +BLOCK OCTANT-124678 + +1CDD7 +BLOCK OCTANT-34678 + +1CDD8 +BLOCK OCTANT-134678 + +1CDD9 +BLOCK OCTANT-234678 + +1CDDA +BLOCK OCTANT-1234678 + +1CDDB +BLOCK OCTANT-15678 + +1CDDC +BLOCK OCTANT-25678 + +1CDDD +BLOCK OCTANT-125678 + +1CDDE +BLOCK OCTANT-35678 + +1CDDF +BLOCK OCTANT-235678 + +1CDE0 +BLOCK OCTANT-1235678 + +1CDE1 +BLOCK OCTANT-45678 + +1CDE2 +BLOCK OCTANT-145678 + +1CDE3 +BLOCK OCTANT-1245678 + +1CDE4 +BLOCK OCTANT-1345678 + +1CDE5 +BLOCK OCTANT-2345678 + +1CDE6 +TOP HALF STANDING PERSON + +1CDE7 +BOTTOM HALF STANDING PERSON + +1CDE8 +TOP HALF RIGHT-FACING RUNNER FRAME-1 + +1CDE9 +BOTTOM HALF RIGHT-FACING RUNNER FRAME-1 + +1CDEA +TOP HALF RIGHT-FACING RUNNER FRAME-2 + +1CDEB +BOTTOM HALF RIGHT-FACING RUNNER FRAME-2 + +1CDEC +TOP HALF LEFT-FACING RUNNER FRAME-1 + +1CDED +BOTTOM HALF LEFT-FACING RUNNER FRAME-1 + +1CDEE +TOP HALF LEFT-FACING RUNNER FRAME-2 + +1CDEF +BOTTOM HALF LEFT-FACING RUNNER FRAME-2 + +1CDF0 +TOP HALF FORWARD-FACING RUNNER + +1CDF1 +BOTTOM HALF FORWARD-FACING RUNNER FRAME-1 + +1CDF2 +BOTTOM HALF FORWARD-FACING RUNNER FRAME-2 + +1CDF3 +BOTTOM HALF FORWARD-FACING RUNNER FRAME-3 + +1CDF4 +BOTTOM HALF FORWARD-FACING RUNNER FRAME-4 + +1CDF5 +MOON LANDER + +1CDF6 +TOP HALF FLAILING ROBOT FRAME-1 + +1CDF7 +TOP HALF FLAILING ROBOT FRAME-2 + +1CDF8 +DOWN-POINTING AIRPLANE + +1CDF9 +LEFT-POINTING AIRPLANE + +1CDFA +SMALL UP-POINTING AIRPLANE + +1CDFB +UP-POINTING FROG + +1CDFC +DOWN-POINTING FROG + +1CDFD +EXPLOSION FRAME-1 + +1CDFE +EXPLOSION FRAME-2 + +1CDFF +EXPLOSION FRAME-3 + +1CE00 +RIGHT HALF AND LEFT HALF WHITE CIRCLE + +1CE01 +LOWER HALF AND UPPER HALF WHITE CIRCLE + +1CE02 +EXPLOSION AT HORIZON + +1CE03 +UPPER HALF HEAVY WHITE SQUARE + +1CE04 +LOWER HALF HEAVY WHITE SQUARE + +1CE05 +HEAVY WHITE SQUARE CONTAINING BLACK VERY SMALL SQUARE + +1CE06 +WHITE VERTICAL RECTANGLE WITH HORIZONTAL BAR + +1CE07 +TOP LEFT BLACK LEFT-POINTING SMALL TRIANGLE + +1CE08 +FUNNEL + +1CE09 +BOX DRAWINGS DOUBLE DIAGONAL LOWER LEFT TO MIDDLE CENTRE TO LOWER RIGHT + +1CE0A +BOX DRAWINGS DOUBLE DIAGONAL UPPER LEFT TO MIDDLE CENTRE TO UPPER RIGHT + +1CE0B +LEFT HALF WHITE ELLIPSE + +1CE0C +RIGHT HALF WHITE ELLIPSE + +1CE0D +LEFT HALF TRIPLE DASH HORIZONTAL + +1CE0E +RIGHT HALF TRIPLE DASH HORIZONTAL + +1CE0F +HORIZONTAL LINE WITH TICK MARK + +1CE10 +LEFT HALF HORIZONTAL LINE WITH THREE TICK MARKS + +1CE11 +RIGHT HALF HORIZONTAL LINE WITH THREE TICK MARKS + +1CE12 +HORIZONTAL LINE WITH THREE TICK MARKS + +1CE13 +LOWER HALF VERTICAL LINE WITH THREE TICK MARKS + +1CE14 +UPPER HALF VERTICAL LINE WITH THREE TICK MARKS + +1CE15 +VERTICAL LINE WITH THREE TICK MARKS + +1CE16 +BOX DRAWINGS LIGHT VERTICAL AND TOP RIGHT + +1CE17 +BOX DRAWINGS LIGHT VERTICAL AND BOTTOM RIGHT + +1CE18 +BOX DRAWINGS LIGHT VERTICAL AND TOP LEFT + +1CE19 +BOX DRAWINGS LIGHT VERTICAL AND BOTTOM LEFT + +1CE1A +LARGE TYPE PIECE UPPER LEFT ARC + +1CE1B +LARGE TYPE PIECE UPPER LEFT CORNER + +1CE1C +LARGE TYPE PIECE UPPER TERMINAL + +1CE1D +LARGE TYPE PIECE UPPER LEFT CROTCH + +1CE1E +LARGE TYPE PIECE LEFT ARM + +1CE1F +LARGE TYPE PIECE CROSSBAR + +1CE20 +LARGE TYPE PIECE CROSSBAR WITH LOWER STEM + +1CE21 +LARGE TYPE PIECE UPPER HALF VERTEX OF M + +1CE22 +LARGE TYPE PIECE DIAGONAL LOWER LEFT + +1CE23 +LARGE TYPE PIECE SHORT UPPER TERMINAL + +1CE24 +LARGE TYPE PIECE UPPER RIGHT ARC + +1CE25 +LARGE TYPE PIECE RIGHT ARM + +1CE26 +LARGE TYPE PIECE UPPER RIGHT CROTCH + +1CE27 +LARGE TYPE PIECE UPPER RIGHT CORNER + +1CE28 +LARGE TYPE PIECE STEM WITH RIGHT CROSSBAR + +1CE29 +LARGE TYPE PIECE STEM + +1CE2A +LARGE TYPE PIECE DIAGONAL UPPER RIGHT AND LOWER RIGHT + +1CE2B +LARGE TYPE PIECE DIAGONAL UPPER RIGHT + +1CE2C +LARGE TYPE PIECE DIAGONAL LOWER RIGHT + +1CE2D +LARGE TYPE PIECE SHORT LOWER TERMINAL + +1CE2E +LARGE TYPE PIECE LOWER LEFT AND UPPER LEFT ARC + +1CE2F +LARGE TYPE PIECE CENTRE OF K + +1CE30 +LARGE TYPE PIECE LOWER HALF VERTEX OF M + +1CE31 +LARGE TYPE PIECE UPPER HALF VERTEX OF W + +1CE32 +LARGE TYPE PIECE CENTRE OF X + +1CE33 +LARGE TYPE PIECE CENTRE OF Y + +1CE34 +LARGE TYPE PIECE CENTRE OF Z WITH CROSSBAR + +1CE35 +LARGE TYPE PIECE RAISED UPPER LEFT ARC + +1CE36 +LARGE TYPE PIECE STEM WITH LEFT CROSSBAR + +1CE37 +LARGE TYPE PIECE LOWER RIGHT AND UPPER RIGHT ARC + +1CE38 +LARGE TYPE PIECE DIAGONAL UPPER LEFT AND LOWER LEFT + +1CE39 +LARGE TYPE PIECE STEM WITH LEFT JOINT + +1CE3A +LARGE TYPE PIECE STEM WITH CROSSBAR + +1CE3B +LARGE TYPE PIECE DIAGONAL UPPER LEFT + +1CE3C +LARGE TYPE PIECE LOWER TERMINAL + +1CE3D +LARGE TYPE PIECE LOWER LEFT CORNER + +1CE3E +LARGE TYPE PIECE LOWER LEFT ARC + +1CE3F +LARGE TYPE PIECE LOWER LEFT CROTCH + +1CE40 +LARGE TYPE PIECE CROSSBAR WITH UPPER STEM + +1CE41 +LARGE TYPE PIECE VERTEX OF V + +1CE42 +LARGE TYPE PIECE LOWER HALF VERTEX OF W + +1CE43 +LARGE TYPE PIECE LOWER RIGHT ARC + +1CE44 +LARGE TYPE PIECE LOWER RIGHT CORNER + +1CE45 +LARGE TYPE PIECE LOWER RIGHT ARC WITH TAIL + +1CE46 +LARGE TYPE PIECE LOWER RIGHT CROTCH + +1CE47 +LARGE TYPE PIECE STEM-45 + +1CE48 +LARGE TYPE PIECE STEM-2345 + +1CE49 +LARGE TYPE PIECE STEM-4 + +1CE4A +LARGE TYPE PIECE STEM-34 + +1CE4B +LARGE TYPE PIECE STEM-234 + +1CE4C +LARGE TYPE PIECE STEM-1234 + +1CE4D +LARGE TYPE PIECE STEM-3 + +1CE4E +LARGE TYPE PIECE STEM-23 + +1CE4F +LARGE TYPE PIECE STEM-2 + +1CE50 +LARGE TYPE PIECE STEM-12 + +1CE51 +SEPARATED BLOCK SEXTANT-1 + +1CE52 +SEPARATED BLOCK SEXTANT-2 + +1CE53 +SEPARATED BLOCK SEXTANT-12 + +1CE54 +SEPARATED BLOCK SEXTANT-3 + +1CE55 +SEPARATED BLOCK SEXTANT-13 + +1CE56 +SEPARATED BLOCK SEXTANT-23 + +1CE57 +SEPARATED BLOCK SEXTANT-123 + +1CE58 +SEPARATED BLOCK SEXTANT-4 + +1CE59 +SEPARATED BLOCK SEXTANT-14 + +1CE5A +SEPARATED BLOCK SEXTANT-24 + +1CE5B +SEPARATED BLOCK SEXTANT-124 + +1CE5C +SEPARATED BLOCK SEXTANT-34 + +1CE5D +SEPARATED BLOCK SEXTANT-134 + +1CE5E +SEPARATED BLOCK SEXTANT-234 + +1CE5F +SEPARATED BLOCK SEXTANT-1234 + +1CE60 +SEPARATED BLOCK SEXTANT-5 + +1CE61 +SEPARATED BLOCK SEXTANT-15 + +1CE62 +SEPARATED BLOCK SEXTANT-25 + +1CE63 +SEPARATED BLOCK SEXTANT-125 + +1CE64 +SEPARATED BLOCK SEXTANT-35 + +1CE65 +SEPARATED BLOCK SEXTANT-135 + +1CE66 +SEPARATED BLOCK SEXTANT-235 + +1CE67 +SEPARATED BLOCK SEXTANT-1235 + +1CE68 +SEPARATED BLOCK SEXTANT-45 + +1CE69 +SEPARATED BLOCK SEXTANT-145 + +1CE6A +SEPARATED BLOCK SEXTANT-245 + +1CE6B +SEPARATED BLOCK SEXTANT-1245 + +1CE6C +SEPARATED BLOCK SEXTANT-345 + +1CE6D +SEPARATED BLOCK SEXTANT-1345 + +1CE6E +SEPARATED BLOCK SEXTANT-2345 + +1CE6F +SEPARATED BLOCK SEXTANT-12345 + +1CE70 +SEPARATED BLOCK SEXTANT-6 + +1CE71 +SEPARATED BLOCK SEXTANT-16 + +1CE72 +SEPARATED BLOCK SEXTANT-26 + +1CE73 +SEPARATED BLOCK SEXTANT-126 + +1CE74 +SEPARATED BLOCK SEXTANT-36 + +1CE75 +SEPARATED BLOCK SEXTANT-136 + +1CE76 +SEPARATED BLOCK SEXTANT-236 + +1CE77 +SEPARATED BLOCK SEXTANT-1236 + +1CE78 +SEPARATED BLOCK SEXTANT-46 + +1CE79 +SEPARATED BLOCK SEXTANT-146 + +1CE7A +SEPARATED BLOCK SEXTANT-246 + +1CE7B +SEPARATED BLOCK SEXTANT-1246 + +1CE7C +SEPARATED BLOCK SEXTANT-346 + +1CE7D +SEPARATED BLOCK SEXTANT-1346 + +1CE7E +SEPARATED BLOCK SEXTANT-2346 + +1CE7F +SEPARATED BLOCK SEXTANT-12346 + +1CE80 +SEPARATED BLOCK SEXTANT-56 + +1CE81 +SEPARATED BLOCK SEXTANT-156 + +1CE82 +SEPARATED BLOCK SEXTANT-256 + +1CE83 +SEPARATED BLOCK SEXTANT-1256 + +1CE84 +SEPARATED BLOCK SEXTANT-356 + +1CE85 +SEPARATED BLOCK SEXTANT-1356 + +1CE86 +SEPARATED BLOCK SEXTANT-2356 + +1CE87 +SEPARATED BLOCK SEXTANT-12356 + +1CE88 +SEPARATED BLOCK SEXTANT-456 + +1CE89 +SEPARATED BLOCK SEXTANT-1456 + +1CE8A +SEPARATED BLOCK SEXTANT-2456 + +1CE8B +SEPARATED BLOCK SEXTANT-12456 + +1CE8C +SEPARATED BLOCK SEXTANT-3456 + +1CE8D +SEPARATED BLOCK SEXTANT-13456 + +1CE8E +SEPARATED BLOCK SEXTANT-23456 + +1CE8F +SEPARATED BLOCK SEXTANT-123456 + +1CE90 +UPPER LEFT ONE SIXTEENTH BLOCK + +1CE91 +UPPER CENTRE LEFT ONE SIXTEENTH BLOCK + +1CE92 +UPPER CENTRE RIGHT ONE SIXTEENTH BLOCK + +1CE93 +UPPER RIGHT ONE SIXTEENTH BLOCK + +1CE94 +UPPER MIDDLE LEFT ONE SIXTEENTH BLOCK + +1CE95 +UPPER MIDDLE CENTRE LEFT ONE SIXTEENTH BLOCK + +1CE96 +UPPER MIDDLE CENTRE RIGHT ONE SIXTEENTH BLOCK + +1CE97 +UPPER MIDDLE RIGHT ONE SIXTEENTH BLOCK + +1CE98 +LOWER MIDDLE LEFT ONE SIXTEENTH BLOCK + +1CE99 +LOWER MIDDLE CENTRE LEFT ONE SIXTEENTH BLOCK + +1CE9A +LOWER MIDDLE CENTRE RIGHT ONE SIXTEENTH BLOCK + +1CE9B +LOWER MIDDLE RIGHT ONE SIXTEENTH BLOCK + +1CE9C +LOWER LEFT ONE SIXTEENTH BLOCK + +1CE9D +LOWER CENTRE LEFT ONE SIXTEENTH BLOCK + +1CE9E +LOWER CENTRE RIGHT ONE SIXTEENTH BLOCK + +1CE9F +LOWER RIGHT ONE SIXTEENTH BLOCK + +1CEA0 +RIGHT HALF LOWER ONE QUARTER BLOCK + +1CEA1 +RIGHT THREE QUARTERS LOWER ONE QUARTER BLOCK + +1CEA2 +LEFT THREE QUARTERS LOWER ONE QUARTER BLOCK + +1CEA3 +LEFT HALF LOWER ONE QUARTER BLOCK + +1CEA4 +LOWER HALF LEFT ONE QUARTER BLOCK + +1CEA5 +LOWER THREE QUARTERS LEFT ONE QUARTER BLOCK + +1CEA6 +UPPER THREE QUARTERS LEFT ONE QUARTER BLOCK + +1CEA7 +UPPER HALF LEFT ONE QUARTER BLOCK + +1CEA8 +LEFT HALF UPPER ONE QUARTER BLOCK + +1CEA9 +LEFT THREE QUARTERS UPPER ONE QUARTER BLOCK + +1CEAA +RIGHT THREE QUARTERS UPPER ONE QUARTER BLOCK + +1CEAB +RIGHT HALF UPPER ONE QUARTER BLOCK + +1CEAC +UPPER HALF RIGHT ONE QUARTER BLOCK + +1CEAD +UPPER THREE QUARTERS RIGHT ONE QUARTER BLOCK + +1CEAE +LOWER THREE QUARTERS RIGHT ONE QUARTER BLOCK + +1CEAF +LOWER HALF RIGHT ONE QUARTER BLOCK + +1CEB0 +HORIZONTAL ZIGZAG LINE + +1CEB1 +KEYHOLE + +1CEB2 +OLD PERSONAL COMPUTER WITH MONITOR IN PORTRAIT ORIENTATION + +1CEB3 +BLACK RIGHT TRIANGLE CARET + +1CEBA +FRAGILE SYMBOL + +1CEBB +OFFICE BUILDING SYMBOL + +1CEBC +TREE SYMBOL + +1CEBD +APPLE SYMBOL + +1CEBE +CHERRY SYMBOL + +1CEBF +STRAWBERRY SYMBOL + +1CEC0 +HEBE + +1CEC1 +IRIS + +1CEC2 +FLORA + +1CEC3 +METIS + +1CEC4 +PARTHENOPE + +1CEC5 +VICTORIA + +1CEC6 +EGERIA + +1CEC7 +IRENE + +1CEC8 +EUNOMIA + +1CEC9 +PSYCHE + +1CECA +THETIS + +1CECB +MELPOMENE + +1CECC +FORTUNA + +1CECD +ASTRONOMICAL SYMBOL FOR ASTEROID PROSERPINA + +1CECE +BELLONA + +1CECF +AMPHITRITE + +1CED0 +LEUKOTHEA + +1CEE0 +GEOMANTIC FIGURE POPULUS + +1CEE1 +GEOMANTIC FIGURE TRISTITIA + +1CEE2 +GEOMANTIC FIGURE ALBUS + +1CEE3 +GEOMANTIC FIGURE FORTUNA MAJOR + +1CEE4 +GEOMANTIC FIGURE RUBEUS + +1CEE5 +GEOMANTIC FIGURE ACQUISITIO + +1CEE6 +GEOMANTIC FIGURE CONJUNCTIO + +1CEE7 +GEOMANTIC FIGURE CAPUT DRACONIS + +1CEE8 +GEOMANTIC FIGURE LAETITIA + +1CEE9 +GEOMANTIC FIGURE CARCER + +1CEEA +GEOMANTIC FIGURE AMISSIO + +1CEEB +GEOMANTIC FIGURE PUELLA + +1CEEC +GEOMANTIC FIGURE FORTUNA MINOR + +1CEED +GEOMANTIC FIGURE PUER + +1CEEE +GEOMANTIC FIGURE CAUDA DRACONIS + +1CEEF +GEOMANTIC FIGURE VIA + +1CEF0 +MEDIUM SMALL WHITE CIRCLE WITH HORIZONTAL BAR + +1CF00 +ZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON LEFT + +1CF01 +ZNAMENNY COMBINING MARK NIZKO S KRYZHEM ON LEFT + +1CF02 +ZNAMENNY COMBINING MARK TSATA ON LEFT + +1CF03 +ZNAMENNY COMBINING MARK GORAZDO NIZKO ON LEFT + +1CF04 +ZNAMENNY COMBINING MARK NIZKO ON LEFT + +1CF05 +ZNAMENNY COMBINING MARK SREDNE ON LEFT + +1CF06 +ZNAMENNY COMBINING MARK MALO POVYSHE ON LEFT + +1CF07 +ZNAMENNY COMBINING MARK POVYSHE ON LEFT + +1CF08 +ZNAMENNY COMBINING MARK VYSOKO ON LEFT + +1CF09 +ZNAMENNY COMBINING MARK MALO POVYSHE S KHOKHLOM ON LEFT + +1CF0A +ZNAMENNY COMBINING MARK POVYSHE S KHOKHLOM ON LEFT + +1CF0B +ZNAMENNY COMBINING MARK VYSOKO S KHOKHLOM ON LEFT + +1CF0C +ZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON RIGHT + +1CF0D +ZNAMENNY COMBINING MARK NIZKO S KRYZHEM ON RIGHT + +1CF0E +ZNAMENNY COMBINING MARK TSATA ON RIGHT + +1CF0F +ZNAMENNY COMBINING MARK GORAZDO NIZKO ON RIGHT + +1CF10 +ZNAMENNY COMBINING MARK NIZKO ON RIGHT + +1CF11 +ZNAMENNY COMBINING MARK SREDNE ON RIGHT + +1CF12 +ZNAMENNY COMBINING MARK MALO POVYSHE ON RIGHT + +1CF13 +ZNAMENNY COMBINING MARK POVYSHE ON RIGHT + +1CF14 +ZNAMENNY COMBINING MARK VYSOKO ON RIGHT + +1CF15 +ZNAMENNY COMBINING MARK MALO POVYSHE S KHOKHLOM ON RIGHT + +1CF16 +ZNAMENNY COMBINING MARK POVYSHE S KHOKHLOM ON RIGHT + +1CF17 +ZNAMENNY COMBINING MARK VYSOKO S KHOKHLOM ON RIGHT + +1CF18 +ZNAMENNY COMBINING MARK TSATA S KRYZHEM + +1CF19 +ZNAMENNY COMBINING MARK MALO POVYSHE S KRYZHEM + +1CF1A +ZNAMENNY COMBINING MARK STRANNO MALO POVYSHE + +1CF1B +ZNAMENNY COMBINING MARK POVYSHE S KRYZHEM + +1CF1C +ZNAMENNY COMBINING MARK POVYSHE STRANNO + +1CF1D +ZNAMENNY COMBINING MARK VYSOKO S KRYZHEM + +1CF1E +ZNAMENNY COMBINING MARK MALO POVYSHE STRANNO + +1CF1F +ZNAMENNY COMBINING MARK GORAZDO VYSOKO + +1CF20 +ZNAMENNY COMBINING MARK ZELO + +1CF21 +ZNAMENNY COMBINING MARK ON + +1CF22 +ZNAMENNY COMBINING MARK RAVNO + +1CF23 +ZNAMENNY COMBINING MARK TIKHAYA + +1CF24 +ZNAMENNY COMBINING MARK BORZAYA + +1CF25 +ZNAMENNY COMBINING MARK UDARKA + +1CF26 +ZNAMENNY COMBINING MARK PODVERTKA + +1CF27 +ZNAMENNY COMBINING MARK LOMKA + +1CF28 +ZNAMENNY COMBINING MARK KUPNAYA + +1CF29 +ZNAMENNY COMBINING MARK KACHKA + +1CF2A +ZNAMENNY COMBINING MARK ZEVOK + +1CF2B +ZNAMENNY COMBINING MARK SKOBA + +1CF2C +ZNAMENNY COMBINING MARK RAZSEKA + +1CF2D +ZNAMENNY COMBINING MARK KRYZH ON LEFT + +1CF30 +ZNAMENNY COMBINING TONAL RANGE MARK MRACHNO + +1CF31 +ZNAMENNY COMBINING TONAL RANGE MARK SVETLO + +1CF32 +ZNAMENNY COMBINING TONAL RANGE MARK TRESVETLO + +1CF33 +ZNAMENNY COMBINING MARK ZADERZHKA + +1CF34 +ZNAMENNY COMBINING MARK DEMESTVENNY ZADERZHKA + +1CF35 +ZNAMENNY COMBINING MARK OTSECHKA + +1CF36 +ZNAMENNY COMBINING MARK PODCHASHIE + +1CF37 +ZNAMENNY COMBINING MARK PODCHASHIE WITH VERTICAL STROKE + +1CF38 +ZNAMENNY COMBINING MARK CHASHKA + +1CF39 +ZNAMENNY COMBINING MARK CHASHKA POLNAYA + +1CF3A +ZNAMENNY COMBINING MARK OBLACHKO + +1CF3B +ZNAMENNY COMBINING MARK SOROCHYA NOZHKA + +1CF3C +ZNAMENNY COMBINING MARK TOCHKA + +1CF3D +ZNAMENNY COMBINING MARK DVOETOCHIE + +1CF3E +ZNAMENNY COMBINING ATTACHING VERTICAL OMET + +1CF3F +ZNAMENNY COMBINING MARK CURVED OMET + +1CF40 +ZNAMENNY COMBINING MARK KRYZH + +1CF41 +ZNAMENNY COMBINING LOWER TONAL RANGE INDICATOR + +1CF42 +ZNAMENNY PRIZNAK MODIFIER LEVEL-2 + +1CF43 +ZNAMENNY PRIZNAK MODIFIER LEVEL-3 + +1CF44 +ZNAMENNY PRIZNAK MODIFIER DIRECTION FLIP + +1CF45 +ZNAMENNY PRIZNAK MODIFIER KRYZH + +1CF46 +ZNAMENNY PRIZNAK MODIFIER ROG + +1CF50 +ZNAMENNY NEUME KRYUK + +1CF51 +ZNAMENNY NEUME KRYUK TIKHY + +1CF52 +ZNAMENNY NEUME PARAKLIT + +1CF53 +ZNAMENNY NEUME DVA V CHELNU + +1CF54 +ZNAMENNY NEUME KLYUCH + +1CF55 +ZNAMENNY NEUME ZANOZHEK + +1CF56 +ZNAMENNY NEUME STOPITSA + +1CF57 +ZNAMENNY NEUME STOPITSA S OCHKOM + +1CF58 +ZNAMENNY NEUME PEREVODKA + +1CF59 +ZNAMENNY NEUME PEREVODKA NEPOSTOYANNAYA + +1CF5A +ZNAMENNY NEUME STOPITSA WITH SOROCHYA NOZHKA + +1CF5B +ZNAMENNY NEUME CHELYUSTKA + +1CF5C +ZNAMENNY NEUME PALKA + +1CF5D +ZNAMENNY NEUME ZAPYATAYA + +1CF5E +ZNAMENNY NEUME GOLUBCHIK BORZY + +1CF5F +ZNAMENNY NEUME GOLUBCHIK TIKHY + +1CF60 +ZNAMENNY NEUME GOLUBCHIK MRACHNY + +1CF61 +ZNAMENNY NEUME GOLUBCHIK SVETLY + +1CF62 +ZNAMENNY NEUME GOLUBCHIK TRESVETLY + +1CF63 +ZNAMENNY NEUME VRAKHIYA PROSTAYA + +1CF64 +ZNAMENNY NEUME VRAKHIYA MRACHNAYA + +1CF65 +ZNAMENNY NEUME VRAKHIYA SVETLAYA + +1CF66 +ZNAMENNY NEUME VRAKHIYA TRESVETLAYA + +1CF67 +ZNAMENNY NEUME VRAKHIYA KLYUCHEVAYA PROSTAYA + +1CF68 +ZNAMENNY NEUME VRAKHIYA KLYUCHEVAYA MRACHNAYA + +1CF69 +ZNAMENNY NEUME VRAKHIYA KLYUCHEVAYA SVETLAYA + +1CF6A +ZNAMENNY NEUME VRAKHIYA KLYUCHEVAYA TRESVETLAYA + +1CF6B +ZNAMENNY NEUME DOUBLE ZAPYATAYA + +1CF6C +ZNAMENNY NEUME REVERSED CHELYUSTKA + +1CF6D +ZNAMENNY NEUME DERBITSA + +1CF6E +ZNAMENNY NEUME KHAMILO + +1CF6F +ZNAMENNY NEUME CHASHKA + +1CF70 +ZNAMENNY NEUME PODCHASHIE + +1CF71 +ZNAMENNY NEUME SKAMEYTSA MRACHNAYA + +1CF72 +ZNAMENNY NEUME SKAMEYTSA SVETLAYA + +1CF73 +ZNAMENNY NEUME SKAMEYTSA TRESVETLAYA + +1CF74 +ZNAMENNY NEUME SKAMEYTSA TIKHAYA + +1CF75 +ZNAMENNY NEUME DEMESTVENNY KLYUCH + +1CF76 +ZNAMENNY NEUME SKAMEYTSA KLYUCHEVAYA SVETLAYA + +1CF77 +ZNAMENNY NEUME SKAMEYTSA KLYUCHENEPOSTOYANNAYA + +1CF78 +ZNAMENNY NEUME SKAMEYTSA KLYUCHEVAYA TIKHAYA + +1CF79 +ZNAMENNY NEUME SKAMEYTSA DVOECHELNAYA PROSTAYA + +1CF7A +ZNAMENNY NEUME SKAMEYTSA DVOECHELNAYA SVETLAYA + +1CF7B +ZNAMENNY NEUME SKAMEYTSA DVOECHELNAYA NEPOSTOYANNAYA + +1CF7C +ZNAMENNY NEUME SKAMEYTSA DVOECHELNAYA KLYUCHEVAYA + +1CF7D +ZNAMENNY NEUME SLOZHITIE + +1CF7E +ZNAMENNY NEUME SLOZHITIE S ZAPYATOY + +1CF7F +ZNAMENNY NEUME SLOZHITIE ZAKRYTOE + +1CF80 +ZNAMENNY NEUME SLOZHITIE S KRYZHEM + +1CF81 +ZNAMENNY NEUME KRYZH + +1CF82 +ZNAMENNY NEUME ROG + +1CF83 +ZNAMENNY NEUME FITA + +1CF84 +ZNAMENNY NEUME KOBYLA + +1CF85 +ZNAMENNY NEUME ZMEYTSA + +1CF86 +ZNAMENNY NEUME STATYA + +1CF87 +ZNAMENNY NEUME STATYA S ZAPYATOY + +1CF88 +ZNAMENNY NEUME STATYA S KRYZHEM + +1CF89 +ZNAMENNY NEUME STATYA S ZAPYATOY I KRYZHEM + +1CF8A +ZNAMENNY NEUME STATYA S KRYZHEM I ZAPYATOY + +1CF8B +ZNAMENNY NEUME STATYA ZAKRYTAYA + +1CF8C +ZNAMENNY NEUME STATYA ZAKRYTAYA S ZAPYATOY + +1CF8D +ZNAMENNY NEUME STATYA S ROGOM + +1CF8E +ZNAMENNY NEUME STATYA S DVUMYA ZAPYATYMI + +1CF8F +ZNAMENNY NEUME STATYA S ZAPYATOY I PODCHASHIEM + +1CF90 +ZNAMENNY NEUME POLKULIZMY + +1CF91 +ZNAMENNY NEUME STATYA NEPOSTOYANNAYA + +1CF92 +ZNAMENNY NEUME STRELA PROSTAYA + +1CF93 +ZNAMENNY NEUME STRELA MRACHNOTIKHAYA + +1CF94 +ZNAMENNY NEUME STRELA KRYZHEVAYA + +1CF95 +ZNAMENNY NEUME STRELA POLUPOVODNAYA + +1CF96 +ZNAMENNY NEUME STRELA POVODNAYA + +1CF97 +ZNAMENNY NEUME STRELA NEPOSTOYANNAYA + +1CF98 +ZNAMENNY NEUME STRELA KLYUCHEPOVODNAYA + +1CF99 +ZNAMENNY NEUME STRELA KLYUCHENEPOSTOYANNAYA + +1CF9A +ZNAMENNY NEUME STRELA TIKHAYA PUTNAYA + +1CF9B +ZNAMENNY NEUME STRELA DVOECHELNAYA + +1CF9C +ZNAMENNY NEUME STRELA DVOECHELNOKRYZHEVAYA + +1CF9D +ZNAMENNY NEUME STRELA DVOECHELNOPOVODNAYA + +1CF9E +ZNAMENNY NEUME STRELA DVOECHELNAYA KLYUCHEVAYA + +1CF9F +ZNAMENNY NEUME STRELA DVOECHELNOPOVODNAYA KLYUCHEVAYA + +1CFA0 +ZNAMENNY NEUME STRELA GROMNAYA WITH SINGLE ZAPYATAYA + +1CFA1 +ZNAMENNY NEUME STRELA GROMOPOVODNAYA WITH SINGLE ZAPYATAYA + +1CFA2 +ZNAMENNY NEUME STRELA GROMNAYA + +1CFA3 +ZNAMENNY NEUME STRELA GROMOPOVODNAYA + +1CFA4 +ZNAMENNY NEUME STRELA GROMOPOVODNAYA WITH DOUBLE ZAPYATAYA + +1CFA5 +ZNAMENNY NEUME STRELA GROMOKRYZHEVAYA + +1CFA6 +ZNAMENNY NEUME STRELA GROMOKRYZHEVAYA POVODNAYA + +1CFA7 +ZNAMENNY NEUME MECHIK + +1CFA8 +ZNAMENNY NEUME MECHIK POVODNY + +1CFA9 +ZNAMENNY NEUME MECHIK KLYUCHEVOY + +1CFAA +ZNAMENNY NEUME MECHIK KLYUCHEPOVODNY + +1CFAB +ZNAMENNY NEUME MECHIK KLYUCHENEPOSTOYANNY + +1CFAC +ZNAMENNY NEUME STRELA TRYASOGLASNAYA + +1CFAD +ZNAMENNY NEUME STRELA TRYASOPOVODNAYA + +1CFAE +ZNAMENNY NEUME STRELA TRYASOSTRELNAYA + +1CFAF +ZNAMENNY NEUME OSOKA + +1CFB0 +ZNAMENNY NEUME OSOKA SVETLAYA + +1CFB1 +ZNAMENNY NEUME OSOKA TRESVETLAYA + +1CFB2 +ZNAMENNY NEUME OSOKA KRYUKOVAYA SVETLAYA + +1CFB3 +ZNAMENNY NEUME OSOKA KLYUCHEVAYA SVETLAYA + +1CFB4 +ZNAMENNY NEUME OSOKA KLYUCHEVAYA NEPOSTOYANNAYA + +1CFB5 +ZNAMENNY NEUME STRELA KRYUKOVAYA + +1CFB6 +ZNAMENNY NEUME STRELA KRYUKOVAYA POVODNAYA + +1CFB7 +ZNAMENNY NEUME STRELA KRYUKOVAYA GROMNAYA WITH SINGLE ZAPYATAYA + +1CFB8 +ZNAMENNY NEUME STRELA KRYUKOVAYA GROMOPOVODNAYA WITH SINGLE ZAPYATAYA + +1CFB9 +ZNAMENNY NEUME STRELA KRYUKOVAYA GROMNAYA + +1CFBA +ZNAMENNY NEUME STRELA KRYUKOVAYA GROMOPOVODNAYA + +1CFBB +ZNAMENNY NEUME STRELA KRYUKOVAYA GROMOPOVODNAYA WITH DOUBLE ZAPYATAYA + +1CFBC +ZNAMENNY NEUME STRELA KRYUKOVAYA GROMOKRYZHEVAYA + +1CFBD +ZNAMENNY NEUME STRELA KRYUKOVAYA GROMOKRYZHEVAYA POVODNAYA + +1CFBE +ZNAMENNY NEUME STRELA KRYUKOVAYA TRYASKA + +1CFBF +ZNAMENNY NEUME KUFISMA + +1CFC0 +ZNAMENNY NEUME OBLAKO + +1CFC1 +ZNAMENNY NEUME DUDA + +1CFC2 +ZNAMENNY NEUME NEMKA + +1CFC3 +ZNAMENNY NEUME PAUK + +1D000 +BYZANTINE MUSICAL SYMBOL PSILI + +1D001 +BYZANTINE MUSICAL SYMBOL DASEIA + +1D002 +BYZANTINE MUSICAL SYMBOL PERISPOMENI + +1D003 +BYZANTINE MUSICAL SYMBOL OXEIA EKFONITIKON + +1D004 +BYZANTINE MUSICAL SYMBOL OXEIA DIPLI + +1D005 +BYZANTINE MUSICAL SYMBOL VAREIA EKFONITIKON + +1D006 +BYZANTINE MUSICAL SYMBOL VAREIA DIPLI + +1D007 +BYZANTINE MUSICAL SYMBOL KATHISTI + +1D008 +BYZANTINE MUSICAL SYMBOL SYRMATIKI + +1D009 +BYZANTINE MUSICAL SYMBOL PARAKLITIKI + +1D00A +BYZANTINE MUSICAL SYMBOL YPOKRISIS + +1D00B +BYZANTINE MUSICAL SYMBOL YPOKRISIS DIPLI + +1D00C +BYZANTINE MUSICAL SYMBOL KREMASTI + +1D00D +BYZANTINE MUSICAL SYMBOL APESO EKFONITIKON + +1D00E +BYZANTINE MUSICAL SYMBOL EXO EKFONITIKON + +1D00F +BYZANTINE MUSICAL SYMBOL TELEIA + +1D010 +BYZANTINE MUSICAL SYMBOL KENTIMATA + +1D011 +BYZANTINE MUSICAL SYMBOL APOSTROFOS + +1D012 +BYZANTINE MUSICAL SYMBOL APOSTROFOS DIPLI + +1D013 +BYZANTINE MUSICAL SYMBOL SYNEVMA + +1D014 +BYZANTINE MUSICAL SYMBOL THITA + +1D015 +BYZANTINE MUSICAL SYMBOL OLIGON ARCHAION + +1D016 +BYZANTINE MUSICAL SYMBOL GORGON ARCHAION + +1D017 +BYZANTINE MUSICAL SYMBOL PSILON + +1D018 +BYZANTINE MUSICAL SYMBOL CHAMILON + +1D019 +BYZANTINE MUSICAL SYMBOL VATHY + +1D01A +BYZANTINE MUSICAL SYMBOL ISON ARCHAION + +1D01B +BYZANTINE MUSICAL SYMBOL KENTIMA ARCHAION + +1D01C +BYZANTINE MUSICAL SYMBOL KENTIMATA ARCHAION + +1D01D +BYZANTINE MUSICAL SYMBOL SAXIMATA + +1D01E +BYZANTINE MUSICAL SYMBOL PARICHON + +1D01F +BYZANTINE MUSICAL SYMBOL STAVROS APODEXIA + +1D020 +BYZANTINE MUSICAL SYMBOL OXEIAI ARCHAION + +1D021 +BYZANTINE MUSICAL SYMBOL VAREIAI ARCHAION + +1D022 +BYZANTINE MUSICAL SYMBOL APODERMA ARCHAION + +1D023 +BYZANTINE MUSICAL SYMBOL APOTHEMA + +1D024 +BYZANTINE MUSICAL SYMBOL KLASMA + +1D025 +BYZANTINE MUSICAL SYMBOL REVMA + +1D026 +BYZANTINE MUSICAL SYMBOL PIASMA ARCHAION + +1D027 +BYZANTINE MUSICAL SYMBOL TINAGMA + +1D028 +BYZANTINE MUSICAL SYMBOL ANATRICHISMA + +1D029 +BYZANTINE MUSICAL SYMBOL SEISMA + +1D02A +BYZANTINE MUSICAL SYMBOL SYNAGMA ARCHAION + +1D02B +BYZANTINE MUSICAL SYMBOL SYNAGMA META STAVROU + +1D02C +BYZANTINE MUSICAL SYMBOL OYRANISMA ARCHAION + +1D02D +BYZANTINE MUSICAL SYMBOL THEMA + +1D02E +BYZANTINE MUSICAL SYMBOL LEMOI + +1D02F +BYZANTINE MUSICAL SYMBOL DYO + +1D030 +BYZANTINE MUSICAL SYMBOL TRIA + +1D031 +BYZANTINE MUSICAL SYMBOL TESSERA + +1D032 +BYZANTINE MUSICAL SYMBOL KRATIMATA + +1D033 +BYZANTINE MUSICAL SYMBOL APESO EXO NEO + +1D034 +BYZANTINE MUSICAL SYMBOL FTHORA ARCHAION + +1D035 +BYZANTINE MUSICAL SYMBOL IMIFTHORA + +1D036 +BYZANTINE MUSICAL SYMBOL TROMIKON ARCHAION + +1D037 +BYZANTINE MUSICAL SYMBOL KATAVA TROMIKON + +1D038 +BYZANTINE MUSICAL SYMBOL PELASTON + +1D039 +BYZANTINE MUSICAL SYMBOL PSIFISTON + +1D03A +BYZANTINE MUSICAL SYMBOL KONTEVMA + +1D03B +BYZANTINE MUSICAL SYMBOL CHOREVMA ARCHAION + +1D03C +BYZANTINE MUSICAL SYMBOL RAPISMA + +1D03D +BYZANTINE MUSICAL SYMBOL PARAKALESMA ARCHAION + +1D03E +BYZANTINE MUSICAL SYMBOL PARAKLITIKI ARCHAION + +1D03F +BYZANTINE MUSICAL SYMBOL ICHADIN + +1D040 +BYZANTINE MUSICAL SYMBOL NANA + +1D041 +BYZANTINE MUSICAL SYMBOL PETASMA + +1D042 +BYZANTINE MUSICAL SYMBOL KONTEVMA ALLO + +1D043 +BYZANTINE MUSICAL SYMBOL TROMIKON ALLO + +1D044 +BYZANTINE MUSICAL SYMBOL STRAGGISMATA + +1D045 +BYZANTINE MUSICAL SYMBOL GRONTHISMATA + +1D046 +BYZANTINE MUSICAL SYMBOL ISON NEO + +1D047 +BYZANTINE MUSICAL SYMBOL OLIGON NEO + +1D048 +BYZANTINE MUSICAL SYMBOL OXEIA NEO + +1D049 +BYZANTINE MUSICAL SYMBOL PETASTI + +1D04A +BYZANTINE MUSICAL SYMBOL KOUFISMA + +1D04B +BYZANTINE MUSICAL SYMBOL PETASTOKOUFISMA + +1D04C +BYZANTINE MUSICAL SYMBOL KRATIMOKOUFISMA + +1D04D +BYZANTINE MUSICAL SYMBOL PELASTON NEO + +1D04E +BYZANTINE MUSICAL SYMBOL KENTIMATA NEO ANO + +1D04F +BYZANTINE MUSICAL SYMBOL KENTIMA NEO ANO + +1D050 +BYZANTINE MUSICAL SYMBOL YPSILI + +1D051 +BYZANTINE MUSICAL SYMBOL APOSTROFOS NEO + +1D052 +BYZANTINE MUSICAL SYMBOL APOSTROFOI SYNDESMOS NEO + +1D053 +BYZANTINE MUSICAL SYMBOL YPORROI + +1D054 +BYZANTINE MUSICAL SYMBOL KRATIMOYPORROON + +1D055 +BYZANTINE MUSICAL SYMBOL ELAFRON + +1D056 +BYZANTINE MUSICAL SYMBOL CHAMILI + +1D057 +BYZANTINE MUSICAL SYMBOL MIKRON ISON + +1D058 +BYZANTINE MUSICAL SYMBOL VAREIA NEO + +1D059 +BYZANTINE MUSICAL SYMBOL PIASMA NEO + +1D05A +BYZANTINE MUSICAL SYMBOL PSIFISTON NEO + +1D05B +BYZANTINE MUSICAL SYMBOL OMALON + +1D05C +BYZANTINE MUSICAL SYMBOL ANTIKENOMA + +1D05D +BYZANTINE MUSICAL SYMBOL LYGISMA + +1D05E +BYZANTINE MUSICAL SYMBOL PARAKLITIKI NEO + +1D05F +BYZANTINE MUSICAL SYMBOL PARAKALESMA NEO + +1D060 +BYZANTINE MUSICAL SYMBOL ETERON PARAKALESMA + +1D061 +BYZANTINE MUSICAL SYMBOL KYLISMA + +1D062 +BYZANTINE MUSICAL SYMBOL ANTIKENOKYLISMA + +1D063 +BYZANTINE MUSICAL SYMBOL TROMIKON NEO + +1D064 +BYZANTINE MUSICAL SYMBOL EKSTREPTON + +1D065 +BYZANTINE MUSICAL SYMBOL SYNAGMA NEO + +1D066 +BYZANTINE MUSICAL SYMBOL SYRMA + +1D067 +BYZANTINE MUSICAL SYMBOL CHOREVMA NEO + +1D068 +BYZANTINE MUSICAL SYMBOL EPEGERMA + +1D069 +BYZANTINE MUSICAL SYMBOL SEISMA NEO + +1D06A +BYZANTINE MUSICAL SYMBOL XIRON KLASMA + +1D06B +BYZANTINE MUSICAL SYMBOL TROMIKOPSIFISTON + +1D06C +BYZANTINE MUSICAL SYMBOL PSIFISTOLYGISMA + +1D06D +BYZANTINE MUSICAL SYMBOL TROMIKOLYGISMA + +1D06E +BYZANTINE MUSICAL SYMBOL TROMIKOPARAKALESMA + +1D06F +BYZANTINE MUSICAL SYMBOL PSIFISTOPARAKALESMA + +1D070 +BYZANTINE MUSICAL SYMBOL TROMIKOSYNAGMA + +1D071 +BYZANTINE MUSICAL SYMBOL PSIFISTOSYNAGMA + +1D072 +BYZANTINE MUSICAL SYMBOL GORGOSYNTHETON + +1D073 +BYZANTINE MUSICAL SYMBOL ARGOSYNTHETON + +1D074 +BYZANTINE MUSICAL SYMBOL ETERON ARGOSYNTHETON + +1D075 +BYZANTINE MUSICAL SYMBOL OYRANISMA NEO + +1D076 +BYZANTINE MUSICAL SYMBOL THEMATISMOS ESO + +1D077 +BYZANTINE MUSICAL SYMBOL THEMATISMOS EXO + +1D078 +BYZANTINE MUSICAL SYMBOL THEMA APLOUN + +1D079 +BYZANTINE MUSICAL SYMBOL THES KAI APOTHES + +1D07A +BYZANTINE MUSICAL SYMBOL KATAVASMA + +1D07B +BYZANTINE MUSICAL SYMBOL ENDOFONON + +1D07C +BYZANTINE MUSICAL SYMBOL YFEN KATO + +1D07D +BYZANTINE MUSICAL SYMBOL YFEN ANO + +1D07E +BYZANTINE MUSICAL SYMBOL STAVROS + +1D07F +BYZANTINE MUSICAL SYMBOL KLASMA ANO + +1D080 +BYZANTINE MUSICAL SYMBOL DIPLI ARCHAION + +1D081 +BYZANTINE MUSICAL SYMBOL KRATIMA ARCHAION + +1D082 +BYZANTINE MUSICAL SYMBOL KRATIMA ALLO + +1D083 +BYZANTINE MUSICAL SYMBOL KRATIMA NEO + +1D084 +BYZANTINE MUSICAL SYMBOL APODERMA NEO + +1D085 +BYZANTINE MUSICAL SYMBOL APLI + +1D086 +BYZANTINE MUSICAL SYMBOL DIPLI + +1D087 +BYZANTINE MUSICAL SYMBOL TRIPLI + +1D088 +BYZANTINE MUSICAL SYMBOL TETRAPLI + +1D089 +BYZANTINE MUSICAL SYMBOL KORONIS + +1D08A +BYZANTINE MUSICAL SYMBOL LEIMMA ENOS CHRONOU + +1D08B +BYZANTINE MUSICAL SYMBOL LEIMMA DYO CHRONON + +1D08C +BYZANTINE MUSICAL SYMBOL LEIMMA TRION CHRONON + +1D08D +BYZANTINE MUSICAL SYMBOL LEIMMA TESSARON CHRONON + +1D08E +BYZANTINE MUSICAL SYMBOL LEIMMA IMISEOS CHRONOU + +1D08F +BYZANTINE MUSICAL SYMBOL GORGON NEO ANO + +1D090 +BYZANTINE MUSICAL SYMBOL GORGON PARESTIGMENON ARISTERA + +1D091 +BYZANTINE MUSICAL SYMBOL GORGON PARESTIGMENON DEXIA + +1D092 +BYZANTINE MUSICAL SYMBOL DIGORGON + +1D093 +BYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON ARISTERA KATO + +1D094 +BYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON ARISTERA ANO + +1D095 +BYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON DEXIA + +1D096 +BYZANTINE MUSICAL SYMBOL TRIGORGON + +1D097 +BYZANTINE MUSICAL SYMBOL ARGON + +1D098 +BYZANTINE MUSICAL SYMBOL IMIDIARGON + +1D099 +BYZANTINE MUSICAL SYMBOL DIARGON + +1D09A +BYZANTINE MUSICAL SYMBOL AGOGI POLI ARGI + +1D09B +BYZANTINE MUSICAL SYMBOL AGOGI ARGOTERI + +1D09C +BYZANTINE MUSICAL SYMBOL AGOGI ARGI + +1D09D +BYZANTINE MUSICAL SYMBOL AGOGI METRIA + +1D09E +BYZANTINE MUSICAL SYMBOL AGOGI MESI + +1D09F +BYZANTINE MUSICAL SYMBOL AGOGI GORGI + +1D0A0 +BYZANTINE MUSICAL SYMBOL AGOGI GORGOTERI + +1D0A1 +BYZANTINE MUSICAL SYMBOL AGOGI POLI GORGI + +1D0A2 +BYZANTINE MUSICAL SYMBOL MARTYRIA PROTOS ICHOS + +1D0A3 +BYZANTINE MUSICAL SYMBOL MARTYRIA ALLI PROTOS ICHOS + +1D0A4 +BYZANTINE MUSICAL SYMBOL MARTYRIA DEYTEROS ICHOS + +1D0A5 +BYZANTINE MUSICAL SYMBOL MARTYRIA ALLI DEYTEROS ICHOS + +1D0A6 +BYZANTINE MUSICAL SYMBOL MARTYRIA TRITOS ICHOS + +1D0A7 +BYZANTINE MUSICAL SYMBOL MARTYRIA TRIFONIAS + +1D0A8 +BYZANTINE MUSICAL SYMBOL MARTYRIA TETARTOS ICHOS + +1D0A9 +BYZANTINE MUSICAL SYMBOL MARTYRIA TETARTOS LEGETOS ICHOS + +1D0AA +BYZANTINE MUSICAL SYMBOL MARTYRIA LEGETOS ICHOS + +1D0AB +BYZANTINE MUSICAL SYMBOL MARTYRIA PLAGIOS ICHOS + +1D0AC +BYZANTINE MUSICAL SYMBOL ISAKIA TELOUS ICHIMATOS + +1D0AD +BYZANTINE MUSICAL SYMBOL APOSTROFOI TELOUS ICHIMATOS + +1D0AE +BYZANTINE MUSICAL SYMBOL FANEROSIS TETRAFONIAS + +1D0AF +BYZANTINE MUSICAL SYMBOL FANEROSIS MONOFONIAS + +1D0B0 +BYZANTINE MUSICAL SYMBOL FANEROSIS DIFONIAS + +1D0B1 +BYZANTINE MUSICAL SYMBOL MARTYRIA VARYS ICHOS + +1D0B2 +BYZANTINE MUSICAL SYMBOL MARTYRIA PROTOVARYS ICHOS + +1D0B3 +BYZANTINE MUSICAL SYMBOL MARTYRIA PLAGIOS TETARTOS ICHOS + +1D0B4 +BYZANTINE MUSICAL SYMBOL GORTHMIKON N APLOUN + +1D0B5 +BYZANTINE MUSICAL SYMBOL GORTHMIKON N DIPLOUN + +1D0B6 +BYZANTINE MUSICAL SYMBOL ENARXIS KAI FTHORA VOU + +1D0B7 +BYZANTINE MUSICAL SYMBOL IMIFONON + +1D0B8 +BYZANTINE MUSICAL SYMBOL IMIFTHORON + +1D0B9 +BYZANTINE MUSICAL SYMBOL FTHORA ARCHAION DEYTEROU ICHOU + +1D0BA +BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI PA + +1D0BB +BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NANA + +1D0BC +BYZANTINE MUSICAL SYMBOL FTHORA NAOS ICHOS + +1D0BD +BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI DI + +1D0BE +BYZANTINE MUSICAL SYMBOL FTHORA SKLIRON DIATONON DI + +1D0BF +BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI KE + +1D0C0 +BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI ZO + +1D0C1 +BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NI KATO + +1D0C2 +BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NI ANO + +1D0C3 +BYZANTINE MUSICAL SYMBOL FTHORA MALAKON CHROMA DIFONIAS + +1D0C4 +BYZANTINE MUSICAL SYMBOL FTHORA MALAKON CHROMA MONOFONIAS + +1D0C5 +BYZANTINE MUSICAL SYMBOL FTHORA SKLIRON CHROMA VASIS + +1D0C5 +BYZANTINE MUSICAL SYMBOL FHTORA SKLIRON CHROMA VASIS + +1D0C6 +BYZANTINE MUSICAL SYMBOL FTHORA SKLIRON CHROMA SYNAFI + +1D0C7 +BYZANTINE MUSICAL SYMBOL FTHORA NENANO + +1D0C8 +BYZANTINE MUSICAL SYMBOL CHROA ZYGOS + +1D0C9 +BYZANTINE MUSICAL SYMBOL CHROA KLITON + +1D0CA +BYZANTINE MUSICAL SYMBOL CHROA SPATHI + +1D0CB +BYZANTINE MUSICAL SYMBOL FTHORA I YFESIS TETARTIMORION + +1D0CC +BYZANTINE MUSICAL SYMBOL FTHORA ENARMONIOS ANTIFONIA + +1D0CD +BYZANTINE MUSICAL SYMBOL YFESIS TRITIMORION + +1D0CE +BYZANTINE MUSICAL SYMBOL DIESIS TRITIMORION + +1D0CF +BYZANTINE MUSICAL SYMBOL DIESIS TETARTIMORION + +1D0D0 +BYZANTINE MUSICAL SYMBOL DIESIS APLI DYO DODEKATA + +1D0D1 +BYZANTINE MUSICAL SYMBOL DIESIS MONOGRAMMOS TESSERA DODEKATA + +1D0D2 +BYZANTINE MUSICAL SYMBOL DIESIS DIGRAMMOS EX DODEKATA + +1D0D3 +BYZANTINE MUSICAL SYMBOL DIESIS TRIGRAMMOS OKTO DODEKATA + +1D0D4 +BYZANTINE MUSICAL SYMBOL YFESIS APLI DYO DODEKATA + +1D0D5 +BYZANTINE MUSICAL SYMBOL YFESIS MONOGRAMMOS TESSERA DODEKATA + +1D0D6 +BYZANTINE MUSICAL SYMBOL YFESIS DIGRAMMOS EX DODEKATA + +1D0D7 +BYZANTINE MUSICAL SYMBOL YFESIS TRIGRAMMOS OKTO DODEKATA + +1D0D8 +BYZANTINE MUSICAL SYMBOL GENIKI DIESIS + +1D0D9 +BYZANTINE MUSICAL SYMBOL GENIKI YFESIS + +1D0DA +BYZANTINE MUSICAL SYMBOL DIASTOLI APLI MIKRI + +1D0DB +BYZANTINE MUSICAL SYMBOL DIASTOLI APLI MEGALI + +1D0DC +BYZANTINE MUSICAL SYMBOL DIASTOLI DIPLI + +1D0DD +BYZANTINE MUSICAL SYMBOL DIASTOLI THESEOS + +1D0DE +BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS + +1D0DF +BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS DISIMOU + +1D0E0 +BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS TRISIMOU + +1D0E1 +BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS TETRASIMOU + +1D0E2 +BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS + +1D0E3 +BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS DISIMOU + +1D0E4 +BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS TRISIMOU + +1D0E5 +BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS TETRASIMOU + +1D0E6 +BYZANTINE MUSICAL SYMBOL DIGRAMMA GG + +1D0E7 +BYZANTINE MUSICAL SYMBOL DIFTOGGOS OU + +1D0E8 +BYZANTINE MUSICAL SYMBOL STIGMA + +1D0E9 +BYZANTINE MUSICAL SYMBOL ARKTIKO PA + +1D0EA +BYZANTINE MUSICAL SYMBOL ARKTIKO VOU + +1D0EB +BYZANTINE MUSICAL SYMBOL ARKTIKO GA + +1D0EC +BYZANTINE MUSICAL SYMBOL ARKTIKO DI + +1D0ED +BYZANTINE MUSICAL SYMBOL ARKTIKO KE + +1D0EE +BYZANTINE MUSICAL SYMBOL ARKTIKO ZO + +1D0EF +BYZANTINE MUSICAL SYMBOL ARKTIKO NI + +1D0F0 +BYZANTINE MUSICAL SYMBOL KENTIMATA NEO MESO + +1D0F1 +BYZANTINE MUSICAL SYMBOL KENTIMA NEO MESO + +1D0F2 +BYZANTINE MUSICAL SYMBOL KENTIMATA NEO KATO + +1D0F3 +BYZANTINE MUSICAL SYMBOL KENTIMA NEO KATO + +1D0F4 +BYZANTINE MUSICAL SYMBOL KLASMA KATO + +1D0F5 +BYZANTINE MUSICAL SYMBOL GORGON NEO KATO + +1D100 +MUSICAL SYMBOL SINGLE BARLINE + +1D101 +MUSICAL SYMBOL DOUBLE BARLINE + +1D102 +MUSICAL SYMBOL FINAL BARLINE + +1D103 +MUSICAL SYMBOL REVERSE FINAL BARLINE + +1D104 +MUSICAL SYMBOL DASHED BARLINE + +1D105 +MUSICAL SYMBOL SHORT BARLINE + +1D106 +MUSICAL SYMBOL LEFT REPEAT SIGN + +1D107 +MUSICAL SYMBOL RIGHT REPEAT SIGN + +1D108 +MUSICAL SYMBOL REPEAT DOTS + +1D109 +MUSICAL SYMBOL DAL SEGNO + +1D10A +MUSICAL SYMBOL DA CAPO + +1D10B +MUSICAL SYMBOL SEGNO + +1D10C +MUSICAL SYMBOL CODA + +1D10D +MUSICAL SYMBOL REPEATED FIGURE-1 + +1D10E +MUSICAL SYMBOL REPEATED FIGURE-2 + +1D10F +MUSICAL SYMBOL REPEATED FIGURE-3 + +1D110 +MUSICAL SYMBOL FERMATA + +1D111 +MUSICAL SYMBOL FERMATA BELOW + +1D112 +MUSICAL SYMBOL BREATH MARK + +1D113 +MUSICAL SYMBOL CAESURA + +1D114 +MUSICAL SYMBOL BRACE + +1D115 +MUSICAL SYMBOL BRACKET + +1D116 +MUSICAL SYMBOL ONE-LINE STAFF + +1D117 +MUSICAL SYMBOL TWO-LINE STAFF + +1D118 +MUSICAL SYMBOL THREE-LINE STAFF + +1D119 +MUSICAL SYMBOL FOUR-LINE STAFF + +1D11A +MUSICAL SYMBOL FIVE-LINE STAFF + +1D11B +MUSICAL SYMBOL SIX-LINE STAFF + +1D11C +MUSICAL SYMBOL SIX-STRING FRETBOARD + +1D11D +MUSICAL SYMBOL FOUR-STRING FRETBOARD + +1D11E +MUSICAL SYMBOL G CLEF + +1D11F +MUSICAL SYMBOL G CLEF OTTAVA ALTA + +1D120 +MUSICAL SYMBOL G CLEF OTTAVA BASSA + +1D121 +MUSICAL SYMBOL C CLEF + +1D122 +MUSICAL SYMBOL F CLEF + +1D123 +MUSICAL SYMBOL F CLEF OTTAVA ALTA + +1D124 +MUSICAL SYMBOL F CLEF OTTAVA BASSA + +1D125 +MUSICAL SYMBOL DRUM CLEF-1 + +1D126 +MUSICAL SYMBOL DRUM CLEF-2 + +1D129 +MUSICAL SYMBOL MULTIPLE MEASURE REST + +1D12A +MUSICAL SYMBOL DOUBLE SHARP + +1D12B +MUSICAL SYMBOL DOUBLE FLAT + +1D12C +MUSICAL SYMBOL FLAT UP + +1D12D +MUSICAL SYMBOL FLAT DOWN + +1D12E +MUSICAL SYMBOL NATURAL UP + +1D12F +MUSICAL SYMBOL NATURAL DOWN + +1D130 +MUSICAL SYMBOL SHARP UP + +1D131 +MUSICAL SYMBOL SHARP DOWN + +1D132 +MUSICAL SYMBOL QUARTER TONE SHARP + +1D133 +MUSICAL SYMBOL QUARTER TONE FLAT + +1D134 +MUSICAL SYMBOL COMMON TIME + +1D135 +MUSICAL SYMBOL CUT TIME + +1D136 +MUSICAL SYMBOL OTTAVA ALTA + +1D137 +MUSICAL SYMBOL OTTAVA BASSA + +1D138 +MUSICAL SYMBOL QUINDICESIMA ALTA + +1D139 +MUSICAL SYMBOL QUINDICESIMA BASSA + +1D13A +MUSICAL SYMBOL MULTI REST + +1D13B +MUSICAL SYMBOL WHOLE REST + +1D13C +MUSICAL SYMBOL HALF REST + +1D13D +MUSICAL SYMBOL QUARTER REST + +1D13E +MUSICAL SYMBOL EIGHTH REST + +1D13F +MUSICAL SYMBOL SIXTEENTH REST + +1D140 +MUSICAL SYMBOL THIRTY-SECOND REST + +1D141 +MUSICAL SYMBOL SIXTY-FOURTH REST + +1D142 +MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH REST + +1D143 +MUSICAL SYMBOL X NOTEHEAD + +1D144 +MUSICAL SYMBOL PLUS NOTEHEAD + +1D145 +MUSICAL SYMBOL CIRCLE X NOTEHEAD + +1D146 +MUSICAL SYMBOL SQUARE NOTEHEAD WHITE + +1D147 +MUSICAL SYMBOL SQUARE NOTEHEAD BLACK + +1D148 +MUSICAL SYMBOL TRIANGLE NOTEHEAD UP WHITE + +1D149 +MUSICAL SYMBOL TRIANGLE NOTEHEAD UP BLACK + +1D14A +MUSICAL SYMBOL TRIANGLE NOTEHEAD LEFT WHITE + +1D14B +MUSICAL SYMBOL TRIANGLE NOTEHEAD LEFT BLACK + +1D14C +MUSICAL SYMBOL TRIANGLE NOTEHEAD RIGHT WHITE + +1D14D +MUSICAL SYMBOL TRIANGLE NOTEHEAD RIGHT BLACK + +1D14E +MUSICAL SYMBOL TRIANGLE NOTEHEAD DOWN WHITE + +1D14F +MUSICAL SYMBOL TRIANGLE NOTEHEAD DOWN BLACK + +1D150 +MUSICAL SYMBOL TRIANGLE NOTEHEAD UP RIGHT WHITE + +1D151 +MUSICAL SYMBOL TRIANGLE NOTEHEAD UP RIGHT BLACK + +1D152 +MUSICAL SYMBOL MOON NOTEHEAD WHITE + +1D153 +MUSICAL SYMBOL MOON NOTEHEAD BLACK + +1D154 +MUSICAL SYMBOL TRIANGLE-ROUND NOTEHEAD DOWN WHITE + +1D155 +MUSICAL SYMBOL TRIANGLE-ROUND NOTEHEAD DOWN BLACK + +1D156 +MUSICAL SYMBOL PARENTHESIS NOTEHEAD + +1D157 +MUSICAL SYMBOL VOID NOTEHEAD + +1D158 +MUSICAL SYMBOL NOTEHEAD BLACK + +1D159 +MUSICAL SYMBOL NULL NOTEHEAD + +1D15A +MUSICAL SYMBOL CLUSTER NOTEHEAD WHITE + +1D15B +MUSICAL SYMBOL CLUSTER NOTEHEAD BLACK + +1D15C +MUSICAL SYMBOL BREVE + +1D15D +MUSICAL SYMBOL WHOLE NOTE + +1D15E +MUSICAL SYMBOL HALF NOTE + +1D15F +MUSICAL SYMBOL QUARTER NOTE + +1D160 +MUSICAL SYMBOL EIGHTH NOTE + +1D161 +MUSICAL SYMBOL SIXTEENTH NOTE + +1D162 +MUSICAL SYMBOL THIRTY-SECOND NOTE + +1D163 +MUSICAL SYMBOL SIXTY-FOURTH NOTE + +1D164 +MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH NOTE + +1D165 +MUSICAL SYMBOL COMBINING STEM + +1D166 +MUSICAL SYMBOL COMBINING SPRECHGESANG STEM + +1D167 +MUSICAL SYMBOL COMBINING TREMOLO-1 + +1D168 +MUSICAL SYMBOL COMBINING TREMOLO-2 + +1D169 +MUSICAL SYMBOL COMBINING TREMOLO-3 + +1D16A +MUSICAL SYMBOL FINGERED TREMOLO-1 + +1D16B +MUSICAL SYMBOL FINGERED TREMOLO-2 + +1D16C +MUSICAL SYMBOL FINGERED TREMOLO-3 + +1D16D +MUSICAL SYMBOL COMBINING AUGMENTATION DOT + +1D16E +MUSICAL SYMBOL COMBINING FLAG-1 + +1D16F +MUSICAL SYMBOL COMBINING FLAG-2 + +1D170 +MUSICAL SYMBOL COMBINING FLAG-3 + +1D171 +MUSICAL SYMBOL COMBINING FLAG-4 + +1D172 +MUSICAL SYMBOL COMBINING FLAG-5 + +1D173 +MUSICAL SYMBOL BEGIN BEAM + +1D174 +MUSICAL SYMBOL END BEAM + +1D175 +MUSICAL SYMBOL BEGIN TIE + +1D176 +MUSICAL SYMBOL END TIE + +1D177 +MUSICAL SYMBOL BEGIN SLUR + +1D178 +MUSICAL SYMBOL END SLUR + +1D179 +MUSICAL SYMBOL BEGIN PHRASE + +1D17A +MUSICAL SYMBOL END PHRASE + +1D17B +MUSICAL SYMBOL COMBINING ACCENT + +1D17C +MUSICAL SYMBOL COMBINING STACCATO + +1D17D +MUSICAL SYMBOL COMBINING TENUTO + +1D17E +MUSICAL SYMBOL COMBINING STACCATISSIMO + +1D17F +MUSICAL SYMBOL COMBINING MARCATO + +1D180 +MUSICAL SYMBOL COMBINING MARCATO-STACCATO + +1D181 +MUSICAL SYMBOL COMBINING ACCENT-STACCATO + +1D182 +MUSICAL SYMBOL COMBINING LOURE + +1D183 +MUSICAL SYMBOL ARPEGGIATO UP + +1D184 +MUSICAL SYMBOL ARPEGGIATO DOWN + +1D185 +MUSICAL SYMBOL COMBINING DOIT + +1D186 +MUSICAL SYMBOL COMBINING RIP + +1D187 +MUSICAL SYMBOL COMBINING FLIP + +1D188 +MUSICAL SYMBOL COMBINING SMEAR + +1D189 +MUSICAL SYMBOL COMBINING BEND + +1D18A +MUSICAL SYMBOL COMBINING DOUBLE TONGUE + +1D18B +MUSICAL SYMBOL COMBINING TRIPLE TONGUE + +1D18C +MUSICAL SYMBOL RINFORZANDO + +1D18D +MUSICAL SYMBOL SUBITO + +1D18E +MUSICAL SYMBOL Z + +1D18F +MUSICAL SYMBOL PIANO + +1D190 +MUSICAL SYMBOL MEZZO + +1D191 +MUSICAL SYMBOL FORTE + +1D192 +MUSICAL SYMBOL CRESCENDO + +1D193 +MUSICAL SYMBOL DECRESCENDO + +1D194 +MUSICAL SYMBOL GRACE NOTE SLASH + +1D195 +MUSICAL SYMBOL GRACE NOTE NO SLASH + +1D196 +MUSICAL SYMBOL TR + +1D197 +MUSICAL SYMBOL TURN + +1D198 +MUSICAL SYMBOL INVERTED TURN + +1D199 +MUSICAL SYMBOL TURN SLASH + +1D19A +MUSICAL SYMBOL TURN UP + +1D19B +MUSICAL SYMBOL ORNAMENT STROKE-1 + +1D19C +MUSICAL SYMBOL ORNAMENT STROKE-2 + +1D19D +MUSICAL SYMBOL ORNAMENT STROKE-3 + +1D19E +MUSICAL SYMBOL ORNAMENT STROKE-4 + +1D19F +MUSICAL SYMBOL ORNAMENT STROKE-5 + +1D1A0 +MUSICAL SYMBOL ORNAMENT STROKE-6 + +1D1A1 +MUSICAL SYMBOL ORNAMENT STROKE-7 + +1D1A2 +MUSICAL SYMBOL ORNAMENT STROKE-8 + +1D1A3 +MUSICAL SYMBOL ORNAMENT STROKE-9 + +1D1A4 +MUSICAL SYMBOL ORNAMENT STROKE-10 + +1D1A5 +MUSICAL SYMBOL ORNAMENT STROKE-11 + +1D1A6 +MUSICAL SYMBOL HAUPTSTIMME + +1D1A7 +MUSICAL SYMBOL NEBENSTIMME + +1D1A8 +MUSICAL SYMBOL END OF STIMME + +1D1A9 +MUSICAL SYMBOL DEGREE SLASH + +1D1AA +MUSICAL SYMBOL COMBINING DOWN BOW + +1D1AB +MUSICAL SYMBOL COMBINING UP BOW + +1D1AC +MUSICAL SYMBOL COMBINING HARMONIC + +1D1AD +MUSICAL SYMBOL COMBINING SNAP PIZZICATO + +1D1AE +MUSICAL SYMBOL PEDAL MARK + +1D1AF +MUSICAL SYMBOL PEDAL UP MARK + +1D1B0 +MUSICAL SYMBOL HALF PEDAL MARK + +1D1B1 +MUSICAL SYMBOL GLISSANDO UP + +1D1B2 +MUSICAL SYMBOL GLISSANDO DOWN + +1D1B3 +MUSICAL SYMBOL WITH FINGERNAILS + +1D1B4 +MUSICAL SYMBOL DAMP + +1D1B5 +MUSICAL SYMBOL DAMP ALL + +1D1B6 +MUSICAL SYMBOL MAXIMA + +1D1B7 +MUSICAL SYMBOL LONGA + +1D1B8 +MUSICAL SYMBOL BREVIS + +1D1B9 +MUSICAL SYMBOL SEMIBREVIS WHITE + +1D1BA +MUSICAL SYMBOL SEMIBREVIS BLACK + +1D1BB +MUSICAL SYMBOL MINIMA + +1D1BC +MUSICAL SYMBOL MINIMA BLACK + +1D1BD +MUSICAL SYMBOL SEMIMINIMA WHITE + +1D1BE +MUSICAL SYMBOL SEMIMINIMA BLACK + +1D1BF +MUSICAL SYMBOL FUSA WHITE + +1D1C0 +MUSICAL SYMBOL FUSA BLACK + +1D1C1 +MUSICAL SYMBOL LONGA PERFECTA REST + +1D1C2 +MUSICAL SYMBOL LONGA IMPERFECTA REST + +1D1C3 +MUSICAL SYMBOL BREVIS REST + +1D1C4 +MUSICAL SYMBOL SEMIBREVIS REST + +1D1C5 +MUSICAL SYMBOL MINIMA REST + +1D1C6 +MUSICAL SYMBOL SEMIMINIMA REST + +1D1C7 +MUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE PERFECTA + +1D1C8 +MUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE IMPERFECTA + +1D1C9 +MUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE PERFECTA DIMINUTION-1 + +1D1CA +MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE PERFECTA + +1D1CB +MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA + +1D1CC +MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-1 + +1D1CD +MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-2 + +1D1CE +MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-3 + +1D1CF +MUSICAL SYMBOL CROIX + +1D1D0 +MUSICAL SYMBOL GREGORIAN C CLEF + +1D1D1 +MUSICAL SYMBOL GREGORIAN F CLEF + +1D1D2 +MUSICAL SYMBOL SQUARE B + +1D1D3 +MUSICAL SYMBOL VIRGA + +1D1D4 +MUSICAL SYMBOL PODATUS + +1D1D5 +MUSICAL SYMBOL CLIVIS + +1D1D6 +MUSICAL SYMBOL SCANDICUS + +1D1D7 +MUSICAL SYMBOL CLIMACUS + +1D1D8 +MUSICAL SYMBOL TORCULUS + +1D1D9 +MUSICAL SYMBOL PORRECTUS + +1D1DA +MUSICAL SYMBOL PORRECTUS FLEXUS + +1D1DB +MUSICAL SYMBOL SCANDICUS FLEXUS + +1D1DC +MUSICAL SYMBOL TORCULUS RESUPINUS + +1D1DD +MUSICAL SYMBOL PES SUBPUNCTIS + +1D1DE +MUSICAL SYMBOL KIEVAN C CLEF + +1D1DF +MUSICAL SYMBOL KIEVAN END OF PIECE + +1D1E0 +MUSICAL SYMBOL KIEVAN FINAL NOTE + +1D1E1 +MUSICAL SYMBOL KIEVAN RECITATIVE MARK + +1D1E2 +MUSICAL SYMBOL KIEVAN WHOLE NOTE + +1D1E3 +MUSICAL SYMBOL KIEVAN HALF NOTE + +1D1E4 +MUSICAL SYMBOL KIEVAN QUARTER NOTE STEM DOWN + +1D1E5 +MUSICAL SYMBOL KIEVAN QUARTER NOTE STEM UP + +1D1E6 +MUSICAL SYMBOL KIEVAN EIGHTH NOTE STEM DOWN + +1D1E7 +MUSICAL SYMBOL KIEVAN EIGHTH NOTE STEM UP + +1D1E8 +MUSICAL SYMBOL KIEVAN FLAT SIGN + +1D1E9 +MUSICAL SYMBOL SORI + +1D1EA +MUSICAL SYMBOL KORON + +1D200 +GREEK VOCAL NOTATION SYMBOL-1 + +1D201 +GREEK VOCAL NOTATION SYMBOL-2 + +1D202 +GREEK VOCAL NOTATION SYMBOL-3 + +1D203 +GREEK VOCAL NOTATION SYMBOL-4 + +1D204 +GREEK VOCAL NOTATION SYMBOL-5 + +1D205 +GREEK VOCAL NOTATION SYMBOL-6 + +1D206 +GREEK VOCAL NOTATION SYMBOL-7 + +1D207 +GREEK VOCAL NOTATION SYMBOL-8 + +1D208 +GREEK VOCAL NOTATION SYMBOL-9 + +1D209 +GREEK VOCAL NOTATION SYMBOL-10 + +1D20A +GREEK VOCAL NOTATION SYMBOL-11 + +1D20B +GREEK VOCAL NOTATION SYMBOL-12 + +1D20C +GREEK VOCAL NOTATION SYMBOL-13 + +1D20D +GREEK VOCAL NOTATION SYMBOL-14 + +1D20E +GREEK VOCAL NOTATION SYMBOL-15 + +1D20F +GREEK VOCAL NOTATION SYMBOL-16 + +1D210 +GREEK VOCAL NOTATION SYMBOL-17 + +1D211 +GREEK VOCAL NOTATION SYMBOL-18 + +1D212 +GREEK VOCAL NOTATION SYMBOL-19 + +1D213 +GREEK VOCAL NOTATION SYMBOL-20 + +1D214 +GREEK VOCAL NOTATION SYMBOL-21 + +1D215 +GREEK VOCAL NOTATION SYMBOL-22 + +1D216 +GREEK VOCAL NOTATION SYMBOL-23 + +1D217 +GREEK VOCAL NOTATION SYMBOL-24 + +1D218 +GREEK VOCAL NOTATION SYMBOL-50 + +1D219 +GREEK VOCAL NOTATION SYMBOL-51 + +1D21A +GREEK VOCAL NOTATION SYMBOL-52 + +1D21B +GREEK VOCAL NOTATION SYMBOL-53 + +1D21C +GREEK VOCAL NOTATION SYMBOL-54 + +1D21D +GREEK INSTRUMENTAL NOTATION SYMBOL-1 + +1D21E +GREEK INSTRUMENTAL NOTATION SYMBOL-2 + +1D21F +GREEK INSTRUMENTAL NOTATION SYMBOL-4 + +1D220 +GREEK INSTRUMENTAL NOTATION SYMBOL-5 + +1D221 +GREEK INSTRUMENTAL NOTATION SYMBOL-7 + +1D222 +GREEK INSTRUMENTAL NOTATION SYMBOL-8 + +1D223 +GREEK INSTRUMENTAL NOTATION SYMBOL-11 + +1D224 +GREEK INSTRUMENTAL NOTATION SYMBOL-12 + +1D225 +GREEK INSTRUMENTAL NOTATION SYMBOL-13 + +1D226 +GREEK INSTRUMENTAL NOTATION SYMBOL-14 + +1D227 +GREEK INSTRUMENTAL NOTATION SYMBOL-17 + +1D228 +GREEK INSTRUMENTAL NOTATION SYMBOL-18 + +1D229 +GREEK INSTRUMENTAL NOTATION SYMBOL-19 + +1D22A +GREEK INSTRUMENTAL NOTATION SYMBOL-23 + +1D22B +GREEK INSTRUMENTAL NOTATION SYMBOL-24 + +1D22C +GREEK INSTRUMENTAL NOTATION SYMBOL-25 + +1D22D +GREEK INSTRUMENTAL NOTATION SYMBOL-26 + +1D22E +GREEK INSTRUMENTAL NOTATION SYMBOL-27 + +1D22F +GREEK INSTRUMENTAL NOTATION SYMBOL-29 + +1D230 +GREEK INSTRUMENTAL NOTATION SYMBOL-30 + +1D231 +GREEK INSTRUMENTAL NOTATION SYMBOL-32 + +1D232 +GREEK INSTRUMENTAL NOTATION SYMBOL-36 + +1D233 +GREEK INSTRUMENTAL NOTATION SYMBOL-37 + +1D234 +GREEK INSTRUMENTAL NOTATION SYMBOL-38 + +1D235 +GREEK INSTRUMENTAL NOTATION SYMBOL-39 + +1D236 +GREEK INSTRUMENTAL NOTATION SYMBOL-40 + +1D237 +GREEK INSTRUMENTAL NOTATION SYMBOL-42 + +1D238 +GREEK INSTRUMENTAL NOTATION SYMBOL-43 + +1D239 +GREEK INSTRUMENTAL NOTATION SYMBOL-45 + +1D23A +GREEK INSTRUMENTAL NOTATION SYMBOL-47 + +1D23B +GREEK INSTRUMENTAL NOTATION SYMBOL-48 + +1D23C +GREEK INSTRUMENTAL NOTATION SYMBOL-49 + +1D23D +GREEK INSTRUMENTAL NOTATION SYMBOL-50 + +1D23E +GREEK INSTRUMENTAL NOTATION SYMBOL-51 + +1D23F +GREEK INSTRUMENTAL NOTATION SYMBOL-52 + +1D240 +GREEK INSTRUMENTAL NOTATION SYMBOL-53 + +1D241 +GREEK INSTRUMENTAL NOTATION SYMBOL-54 + +1D242 +COMBINING GREEK MUSICAL TRISEME + +1D243 +COMBINING GREEK MUSICAL TETRASEME + +1D244 +COMBINING GREEK MUSICAL PENTASEME + +1D245 +GREEK MUSICAL LEIMMA + +1D2C0 +KAKTOVIK NUMERAL ZERO + +1D2C1 +KAKTOVIK NUMERAL ONE + +1D2C2 +KAKTOVIK NUMERAL TWO + +1D2C3 +KAKTOVIK NUMERAL THREE + +1D2C4 +KAKTOVIK NUMERAL FOUR + +1D2C5 +KAKTOVIK NUMERAL FIVE + +1D2C6 +KAKTOVIK NUMERAL SIX + +1D2C7 +KAKTOVIK NUMERAL SEVEN + +1D2C8 +KAKTOVIK NUMERAL EIGHT + +1D2C9 +KAKTOVIK NUMERAL NINE + +1D2CA +KAKTOVIK NUMERAL TEN + +1D2CB +KAKTOVIK NUMERAL ELEVEN + +1D2CC +KAKTOVIK NUMERAL TWELVE + +1D2CD +KAKTOVIK NUMERAL THIRTEEN + +1D2CE +KAKTOVIK NUMERAL FOURTEEN + +1D2CF +KAKTOVIK NUMERAL FIFTEEN + +1D2D0 +KAKTOVIK NUMERAL SIXTEEN + +1D2D1 +KAKTOVIK NUMERAL SEVENTEEN + +1D2D2 +KAKTOVIK NUMERAL EIGHTEEN + +1D2D3 +KAKTOVIK NUMERAL NINETEEN + +1D2E0 +MAYAN NUMERAL ZERO + +1D2E1 +MAYAN NUMERAL ONE + +1D2E2 +MAYAN NUMERAL TWO + +1D2E3 +MAYAN NUMERAL THREE + +1D2E4 +MAYAN NUMERAL FOUR + +1D2E5 +MAYAN NUMERAL FIVE + +1D2E6 +MAYAN NUMERAL SIX + +1D2E7 +MAYAN NUMERAL SEVEN + +1D2E8 +MAYAN NUMERAL EIGHT + +1D2E9 +MAYAN NUMERAL NINE + +1D2EA +MAYAN NUMERAL TEN + +1D2EB +MAYAN NUMERAL ELEVEN + +1D2EC +MAYAN NUMERAL TWELVE + +1D2ED +MAYAN NUMERAL THIRTEEN + +1D2EE +MAYAN NUMERAL FOURTEEN + +1D2EF +MAYAN NUMERAL FIFTEEN + +1D2F0 +MAYAN NUMERAL SIXTEEN + +1D2F1 +MAYAN NUMERAL SEVENTEEN + +1D2F2 +MAYAN NUMERAL EIGHTEEN + +1D2F3 +MAYAN NUMERAL NINETEEN + +1D300 +MONOGRAM FOR EARTH + +1D301 +DIGRAM FOR HEAVENLY EARTH + +1D302 +DIGRAM FOR HUMAN EARTH + +1D303 +DIGRAM FOR EARTHLY HEAVEN + +1D304 +DIGRAM FOR EARTHLY HUMAN + +1D305 +DIGRAM FOR EARTH + +1D306 +TETRAGRAM FOR CENTRE + +1D307 +TETRAGRAM FOR FULL CIRCLE + +1D308 +TETRAGRAM FOR MIRED + +1D309 +TETRAGRAM FOR BARRIER + +1D30A +TETRAGRAM FOR KEEPING SMALL + +1D30B +TETRAGRAM FOR CONTRARIETY + +1D30C +TETRAGRAM FOR ASCENT + +1D30D +TETRAGRAM FOR OPPOSITION + +1D30E +TETRAGRAM FOR BRANCHING OUT + +1D30F +TETRAGRAM FOR DEFECTIVENESS OR DISTORTION + +1D310 +TETRAGRAM FOR DIVERGENCE + +1D311 +TETRAGRAM FOR YOUTHFULNESS + +1D312 +TETRAGRAM FOR INCREASE + +1D313 +TETRAGRAM FOR PENETRATION + +1D314 +TETRAGRAM FOR REACH + +1D315 +TETRAGRAM FOR CONTACT + +1D316 +TETRAGRAM FOR HOLDING BACK + +1D317 +TETRAGRAM FOR WAITING + +1D318 +TETRAGRAM FOR FOLLOWING + +1D319 +TETRAGRAM FOR ADVANCE + +1D31A +TETRAGRAM FOR RELEASE + +1D31B +TETRAGRAM FOR RESISTANCE + +1D31C +TETRAGRAM FOR EASE + +1D31D +TETRAGRAM FOR JOY + +1D31E +TETRAGRAM FOR CONTENTION + +1D31F +TETRAGRAM FOR ENDEAVOUR + +1D320 +TETRAGRAM FOR DUTIES + +1D321 +TETRAGRAM FOR CHANGE + +1D322 +TETRAGRAM FOR DECISIVENESS + +1D323 +TETRAGRAM FOR BOLD RESOLUTION + +1D324 +TETRAGRAM FOR PACKING + +1D325 +TETRAGRAM FOR LEGION + +1D326 +TETRAGRAM FOR CLOSENESS + +1D327 +TETRAGRAM FOR KINSHIP + +1D328 +TETRAGRAM FOR GATHERING + +1D329 +TETRAGRAM FOR STRENGTH + +1D32A +TETRAGRAM FOR PURITY + +1D32B +TETRAGRAM FOR FULLNESS + +1D32C +TETRAGRAM FOR RESIDENCE + +1D32D +TETRAGRAM FOR LAW OR MODEL + +1D32E +TETRAGRAM FOR RESPONSE + +1D32F +TETRAGRAM FOR GOING TO MEET + +1D330 +TETRAGRAM FOR ENCOUNTERS + +1D331 +TETRAGRAM FOR STOVE + +1D332 +TETRAGRAM FOR GREATNESS + +1D333 +TETRAGRAM FOR ENLARGEMENT + +1D334 +TETRAGRAM FOR PATTERN + +1D335 +TETRAGRAM FOR RITUAL + +1D336 +TETRAGRAM FOR FLIGHT + +1D337 +TETRAGRAM FOR VASTNESS OR WASTING + +1D338 +TETRAGRAM FOR CONSTANCY + +1D339 +TETRAGRAM FOR MEASURE + +1D33A +TETRAGRAM FOR ETERNITY + +1D33B +TETRAGRAM FOR UNITY + +1D33C +TETRAGRAM FOR DIMINISHMENT + +1D33D +TETRAGRAM FOR CLOSED MOUTH + +1D33E +TETRAGRAM FOR GUARDEDNESS + +1D33F +TETRAGRAM FOR GATHERING IN + +1D340 +TETRAGRAM FOR MASSING + +1D341 +TETRAGRAM FOR ACCUMULATION + +1D342 +TETRAGRAM FOR EMBELLISHMENT + +1D343 +TETRAGRAM FOR DOUBT + +1D344 +TETRAGRAM FOR WATCH + +1D345 +TETRAGRAM FOR SINKING + +1D346 +TETRAGRAM FOR INNER + +1D347 +TETRAGRAM FOR DEPARTURE + +1D348 +TETRAGRAM FOR DARKENING + +1D349 +TETRAGRAM FOR DIMMING + +1D34A +TETRAGRAM FOR EXHAUSTION + +1D34B +TETRAGRAM FOR SEVERANCE + +1D34C +TETRAGRAM FOR STOPPAGE + +1D34D +TETRAGRAM FOR HARDNESS + +1D34E +TETRAGRAM FOR COMPLETION + +1D34F +TETRAGRAM FOR CLOSURE + +1D350 +TETRAGRAM FOR FAILURE + +1D351 +TETRAGRAM FOR AGGRAVATION + +1D352 +TETRAGRAM FOR COMPLIANCE + +1D353 +TETRAGRAM FOR ON THE VERGE + +1D354 +TETRAGRAM FOR DIFFICULTIES + +1D355 +TETRAGRAM FOR LABOURING + +1D356 +TETRAGRAM FOR FOSTERING + +1D360 +COUNTING ROD UNIT DIGIT ONE + +1D361 +COUNTING ROD UNIT DIGIT TWO + +1D362 +COUNTING ROD UNIT DIGIT THREE + +1D363 +COUNTING ROD UNIT DIGIT FOUR + +1D364 +COUNTING ROD UNIT DIGIT FIVE + +1D365 +COUNTING ROD UNIT DIGIT SIX + +1D366 +COUNTING ROD UNIT DIGIT SEVEN + +1D367 +COUNTING ROD UNIT DIGIT EIGHT + +1D368 +COUNTING ROD UNIT DIGIT NINE + +1D369 +COUNTING ROD TENS DIGIT ONE + +1D36A +COUNTING ROD TENS DIGIT TWO + +1D36B +COUNTING ROD TENS DIGIT THREE + +1D36C +COUNTING ROD TENS DIGIT FOUR + +1D36D +COUNTING ROD TENS DIGIT FIVE + +1D36E +COUNTING ROD TENS DIGIT SIX + +1D36F +COUNTING ROD TENS DIGIT SEVEN + +1D370 +COUNTING ROD TENS DIGIT EIGHT + +1D371 +COUNTING ROD TENS DIGIT NINE + +1D372 +IDEOGRAPHIC TALLY MARK ONE + +1D373 +IDEOGRAPHIC TALLY MARK TWO + +1D374 +IDEOGRAPHIC TALLY MARK THREE + +1D375 +IDEOGRAPHIC TALLY MARK FOUR + +1D376 +IDEOGRAPHIC TALLY MARK FIVE + +1D377 +TALLY MARK ONE + +1D378 +TALLY MARK FIVE + +1D400 +MATHEMATICAL BOLD CAPITAL A + +1D401 +MATHEMATICAL BOLD CAPITAL B + +1D402 +MATHEMATICAL BOLD CAPITAL C + +1D403 +MATHEMATICAL BOLD CAPITAL D + +1D404 +MATHEMATICAL BOLD CAPITAL E + +1D405 +MATHEMATICAL BOLD CAPITAL F + +1D406 +MATHEMATICAL BOLD CAPITAL G + +1D407 +MATHEMATICAL BOLD CAPITAL H + +1D408 +MATHEMATICAL BOLD CAPITAL I + +1D409 +MATHEMATICAL BOLD CAPITAL J + +1D40A +MATHEMATICAL BOLD CAPITAL K + +1D40B +MATHEMATICAL BOLD CAPITAL L + +1D40C +MATHEMATICAL BOLD CAPITAL M + +1D40D +MATHEMATICAL BOLD CAPITAL N + +1D40E +MATHEMATICAL BOLD CAPITAL O + +1D40F +MATHEMATICAL BOLD CAPITAL P + +1D410 +MATHEMATICAL BOLD CAPITAL Q + +1D411 +MATHEMATICAL BOLD CAPITAL R + +1D412 +MATHEMATICAL BOLD CAPITAL S + +1D413 +MATHEMATICAL BOLD CAPITAL T + +1D414 +MATHEMATICAL BOLD CAPITAL U + +1D415 +MATHEMATICAL BOLD CAPITAL V + +1D416 +MATHEMATICAL BOLD CAPITAL W + +1D417 +MATHEMATICAL BOLD CAPITAL X + +1D418 +MATHEMATICAL BOLD CAPITAL Y + +1D419 +MATHEMATICAL BOLD CAPITAL Z + +1D41A +MATHEMATICAL BOLD SMALL A + +1D41B +MATHEMATICAL BOLD SMALL B + +1D41C +MATHEMATICAL BOLD SMALL C + +1D41D +MATHEMATICAL BOLD SMALL D + +1D41E +MATHEMATICAL BOLD SMALL E + +1D41F +MATHEMATICAL BOLD SMALL F + +1D420 +MATHEMATICAL BOLD SMALL G + +1D421 +MATHEMATICAL BOLD SMALL H + +1D422 +MATHEMATICAL BOLD SMALL I + +1D423 +MATHEMATICAL BOLD SMALL J + +1D424 +MATHEMATICAL BOLD SMALL K + +1D425 +MATHEMATICAL BOLD SMALL L + +1D426 +MATHEMATICAL BOLD SMALL M + +1D427 +MATHEMATICAL BOLD SMALL N + +1D428 +MATHEMATICAL BOLD SMALL O + +1D429 +MATHEMATICAL BOLD SMALL P + +1D42A +MATHEMATICAL BOLD SMALL Q + +1D42B +MATHEMATICAL BOLD SMALL R + +1D42C +MATHEMATICAL BOLD SMALL S + +1D42D +MATHEMATICAL BOLD SMALL T + +1D42E +MATHEMATICAL BOLD SMALL U + +1D42F +MATHEMATICAL BOLD SMALL V + +1D430 +MATHEMATICAL BOLD SMALL W + +1D431 +MATHEMATICAL BOLD SMALL X + +1D432 +MATHEMATICAL BOLD SMALL Y + +1D433 +MATHEMATICAL BOLD SMALL Z + +1D434 +MATHEMATICAL ITALIC CAPITAL A + +1D435 +MATHEMATICAL ITALIC CAPITAL B + +1D436 +MATHEMATICAL ITALIC CAPITAL C + +1D437 +MATHEMATICAL ITALIC CAPITAL D + +1D438 +MATHEMATICAL ITALIC CAPITAL E + +1D439 +MATHEMATICAL ITALIC CAPITAL F + +1D43A +MATHEMATICAL ITALIC CAPITAL G + +1D43B +MATHEMATICAL ITALIC CAPITAL H + +1D43C +MATHEMATICAL ITALIC CAPITAL I + +1D43D +MATHEMATICAL ITALIC CAPITAL J + +1D43E +MATHEMATICAL ITALIC CAPITAL K + +1D43F +MATHEMATICAL ITALIC CAPITAL L + +1D440 +MATHEMATICAL ITALIC CAPITAL M + +1D441 +MATHEMATICAL ITALIC CAPITAL N + +1D442 +MATHEMATICAL ITALIC CAPITAL O + +1D443 +MATHEMATICAL ITALIC CAPITAL P + +1D444 +MATHEMATICAL ITALIC CAPITAL Q + +1D445 +MATHEMATICAL ITALIC CAPITAL R + +1D446 +MATHEMATICAL ITALIC CAPITAL S + +1D447 +MATHEMATICAL ITALIC CAPITAL T + +1D448 +MATHEMATICAL ITALIC CAPITAL U + +1D449 +MATHEMATICAL ITALIC CAPITAL V + +1D44A +MATHEMATICAL ITALIC CAPITAL W + +1D44B +MATHEMATICAL ITALIC CAPITAL X + +1D44C +MATHEMATICAL ITALIC CAPITAL Y + +1D44D +MATHEMATICAL ITALIC CAPITAL Z + +1D44E +MATHEMATICAL ITALIC SMALL A + +1D44F +MATHEMATICAL ITALIC SMALL B + +1D450 +MATHEMATICAL ITALIC SMALL C + +1D451 +MATHEMATICAL ITALIC SMALL D + +1D452 +MATHEMATICAL ITALIC SMALL E + +1D453 +MATHEMATICAL ITALIC SMALL F + +1D454 +MATHEMATICAL ITALIC SMALL G + +1D456 +MATHEMATICAL ITALIC SMALL I + +1D457 +MATHEMATICAL ITALIC SMALL J + +1D458 +MATHEMATICAL ITALIC SMALL K + +1D459 +MATHEMATICAL ITALIC SMALL L + +1D45A +MATHEMATICAL ITALIC SMALL M + +1D45B +MATHEMATICAL ITALIC SMALL N + +1D45C +MATHEMATICAL ITALIC SMALL O + +1D45D +MATHEMATICAL ITALIC SMALL P + +1D45E +MATHEMATICAL ITALIC SMALL Q + +1D45F +MATHEMATICAL ITALIC SMALL R + +1D460 +MATHEMATICAL ITALIC SMALL S + +1D461 +MATHEMATICAL ITALIC SMALL T + +1D462 +MATHEMATICAL ITALIC SMALL U + +1D463 +MATHEMATICAL ITALIC SMALL V + +1D464 +MATHEMATICAL ITALIC SMALL W + +1D465 +MATHEMATICAL ITALIC SMALL X + +1D466 +MATHEMATICAL ITALIC SMALL Y + +1D467 +MATHEMATICAL ITALIC SMALL Z + +1D468 +MATHEMATICAL BOLD ITALIC CAPITAL A + +1D469 +MATHEMATICAL BOLD ITALIC CAPITAL B + +1D46A +MATHEMATICAL BOLD ITALIC CAPITAL C + +1D46B +MATHEMATICAL BOLD ITALIC CAPITAL D + +1D46C +MATHEMATICAL BOLD ITALIC CAPITAL E + +1D46D +MATHEMATICAL BOLD ITALIC CAPITAL F + +1D46E +MATHEMATICAL BOLD ITALIC CAPITAL G + +1D46F +MATHEMATICAL BOLD ITALIC CAPITAL H + +1D470 +MATHEMATICAL BOLD ITALIC CAPITAL I + +1D471 +MATHEMATICAL BOLD ITALIC CAPITAL J + +1D472 +MATHEMATICAL BOLD ITALIC CAPITAL K + +1D473 +MATHEMATICAL BOLD ITALIC CAPITAL L + +1D474 +MATHEMATICAL BOLD ITALIC CAPITAL M + +1D475 +MATHEMATICAL BOLD ITALIC CAPITAL N + +1D476 +MATHEMATICAL BOLD ITALIC CAPITAL O + +1D477 +MATHEMATICAL BOLD ITALIC CAPITAL P + +1D478 +MATHEMATICAL BOLD ITALIC CAPITAL Q + +1D479 +MATHEMATICAL BOLD ITALIC CAPITAL R + +1D47A +MATHEMATICAL BOLD ITALIC CAPITAL S + +1D47B +MATHEMATICAL BOLD ITALIC CAPITAL T + +1D47C +MATHEMATICAL BOLD ITALIC CAPITAL U + +1D47D +MATHEMATICAL BOLD ITALIC CAPITAL V + +1D47E +MATHEMATICAL BOLD ITALIC CAPITAL W + +1D47F +MATHEMATICAL BOLD ITALIC CAPITAL X + +1D480 +MATHEMATICAL BOLD ITALIC CAPITAL Y + +1D481 +MATHEMATICAL BOLD ITALIC CAPITAL Z + +1D482 +MATHEMATICAL BOLD ITALIC SMALL A + +1D483 +MATHEMATICAL BOLD ITALIC SMALL B + +1D484 +MATHEMATICAL BOLD ITALIC SMALL C + +1D485 +MATHEMATICAL BOLD ITALIC SMALL D + +1D486 +MATHEMATICAL BOLD ITALIC SMALL E + +1D487 +MATHEMATICAL BOLD ITALIC SMALL F + +1D488 +MATHEMATICAL BOLD ITALIC SMALL G + +1D489 +MATHEMATICAL BOLD ITALIC SMALL H + +1D48A +MATHEMATICAL BOLD ITALIC SMALL I + +1D48B +MATHEMATICAL BOLD ITALIC SMALL J + +1D48C +MATHEMATICAL BOLD ITALIC SMALL K + +1D48D +MATHEMATICAL BOLD ITALIC SMALL L + +1D48E +MATHEMATICAL BOLD ITALIC SMALL M + +1D48F +MATHEMATICAL BOLD ITALIC SMALL N + +1D490 +MATHEMATICAL BOLD ITALIC SMALL O + +1D491 +MATHEMATICAL BOLD ITALIC SMALL P + +1D492 +MATHEMATICAL BOLD ITALIC SMALL Q + +1D493 +MATHEMATICAL BOLD ITALIC SMALL R + +1D494 +MATHEMATICAL BOLD ITALIC SMALL S + +1D495 +MATHEMATICAL BOLD ITALIC SMALL T + +1D496 +MATHEMATICAL BOLD ITALIC SMALL U + +1D497 +MATHEMATICAL BOLD ITALIC SMALL V + +1D498 +MATHEMATICAL BOLD ITALIC SMALL W + +1D499 +MATHEMATICAL BOLD ITALIC SMALL X + +1D49A +MATHEMATICAL BOLD ITALIC SMALL Y + +1D49B +MATHEMATICAL BOLD ITALIC SMALL Z + +1D49C +MATHEMATICAL SCRIPT CAPITAL A + +1D49E +MATHEMATICAL SCRIPT CAPITAL C + +1D49F +MATHEMATICAL SCRIPT CAPITAL D + +1D4A2 +MATHEMATICAL SCRIPT CAPITAL G + +1D4A5 +MATHEMATICAL SCRIPT CAPITAL J + +1D4A6 +MATHEMATICAL SCRIPT CAPITAL K + +1D4A9 +MATHEMATICAL SCRIPT CAPITAL N + +1D4AA +MATHEMATICAL SCRIPT CAPITAL O + +1D4AB +MATHEMATICAL SCRIPT CAPITAL P + +1D4AC +MATHEMATICAL SCRIPT CAPITAL Q + +1D4AE +MATHEMATICAL SCRIPT CAPITAL S + +1D4AF +MATHEMATICAL SCRIPT CAPITAL T + +1D4B0 +MATHEMATICAL SCRIPT CAPITAL U + +1D4B1 +MATHEMATICAL SCRIPT CAPITAL V + +1D4B2 +MATHEMATICAL SCRIPT CAPITAL W + +1D4B3 +MATHEMATICAL SCRIPT CAPITAL X + +1D4B4 +MATHEMATICAL SCRIPT CAPITAL Y + +1D4B5 +MATHEMATICAL SCRIPT CAPITAL Z + +1D4B6 +MATHEMATICAL SCRIPT SMALL A + +1D4B7 +MATHEMATICAL SCRIPT SMALL B + +1D4B8 +MATHEMATICAL SCRIPT SMALL C + +1D4B9 +MATHEMATICAL SCRIPT SMALL D + +1D4BB +MATHEMATICAL SCRIPT SMALL F + +1D4BD +MATHEMATICAL SCRIPT SMALL H + +1D4BE +MATHEMATICAL SCRIPT SMALL I + +1D4BF +MATHEMATICAL SCRIPT SMALL J + +1D4C0 +MATHEMATICAL SCRIPT SMALL K + +1D4C1 +MATHEMATICAL SCRIPT SMALL L + +1D4C2 +MATHEMATICAL SCRIPT SMALL M + +1D4C3 +MATHEMATICAL SCRIPT SMALL N + +1D4C5 +MATHEMATICAL SCRIPT SMALL P + +1D4C6 +MATHEMATICAL SCRIPT SMALL Q + +1D4C7 +MATHEMATICAL SCRIPT SMALL R + +1D4C8 +MATHEMATICAL SCRIPT SMALL S + +1D4C9 +MATHEMATICAL SCRIPT SMALL T + +1D4CA +MATHEMATICAL SCRIPT SMALL U + +1D4CB +MATHEMATICAL SCRIPT SMALL V + +1D4CC +MATHEMATICAL SCRIPT SMALL W + +1D4CD +MATHEMATICAL SCRIPT SMALL X + +1D4CE +MATHEMATICAL SCRIPT SMALL Y + +1D4CF +MATHEMATICAL SCRIPT SMALL Z + +1D4D0 +MATHEMATICAL BOLD SCRIPT CAPITAL A + +1D4D1 +MATHEMATICAL BOLD SCRIPT CAPITAL B + +1D4D2 +MATHEMATICAL BOLD SCRIPT CAPITAL C + +1D4D3 +MATHEMATICAL BOLD SCRIPT CAPITAL D + +1D4D4 +MATHEMATICAL BOLD SCRIPT CAPITAL E + +1D4D5 +MATHEMATICAL BOLD SCRIPT CAPITAL F + +1D4D6 +MATHEMATICAL BOLD SCRIPT CAPITAL G + +1D4D7 +MATHEMATICAL BOLD SCRIPT CAPITAL H + +1D4D8 +MATHEMATICAL BOLD SCRIPT CAPITAL I + +1D4D9 +MATHEMATICAL BOLD SCRIPT CAPITAL J + +1D4DA +MATHEMATICAL BOLD SCRIPT CAPITAL K + +1D4DB +MATHEMATICAL BOLD SCRIPT CAPITAL L + +1D4DC +MATHEMATICAL BOLD SCRIPT CAPITAL M + +1D4DD +MATHEMATICAL BOLD SCRIPT CAPITAL N + +1D4DE +MATHEMATICAL BOLD SCRIPT CAPITAL O + +1D4DF +MATHEMATICAL BOLD SCRIPT CAPITAL P + +1D4E0 +MATHEMATICAL BOLD SCRIPT CAPITAL Q + +1D4E1 +MATHEMATICAL BOLD SCRIPT CAPITAL R + +1D4E2 +MATHEMATICAL BOLD SCRIPT CAPITAL S + +1D4E3 +MATHEMATICAL BOLD SCRIPT CAPITAL T + +1D4E4 +MATHEMATICAL BOLD SCRIPT CAPITAL U + +1D4E5 +MATHEMATICAL BOLD SCRIPT CAPITAL V + +1D4E6 +MATHEMATICAL BOLD SCRIPT CAPITAL W + +1D4E7 +MATHEMATICAL BOLD SCRIPT CAPITAL X + +1D4E8 +MATHEMATICAL BOLD SCRIPT CAPITAL Y + +1D4E9 +MATHEMATICAL BOLD SCRIPT CAPITAL Z + +1D4EA +MATHEMATICAL BOLD SCRIPT SMALL A + +1D4EB +MATHEMATICAL BOLD SCRIPT SMALL B + +1D4EC +MATHEMATICAL BOLD SCRIPT SMALL C + +1D4ED +MATHEMATICAL BOLD SCRIPT SMALL D + +1D4EE +MATHEMATICAL BOLD SCRIPT SMALL E + +1D4EF +MATHEMATICAL BOLD SCRIPT SMALL F + +1D4F0 +MATHEMATICAL BOLD SCRIPT SMALL G + +1D4F1 +MATHEMATICAL BOLD SCRIPT SMALL H + +1D4F2 +MATHEMATICAL BOLD SCRIPT SMALL I + +1D4F3 +MATHEMATICAL BOLD SCRIPT SMALL J + +1D4F4 +MATHEMATICAL BOLD SCRIPT SMALL K + +1D4F5 +MATHEMATICAL BOLD SCRIPT SMALL L + +1D4F6 +MATHEMATICAL BOLD SCRIPT SMALL M + +1D4F7 +MATHEMATICAL BOLD SCRIPT SMALL N + +1D4F8 +MATHEMATICAL BOLD SCRIPT SMALL O + +1D4F9 +MATHEMATICAL BOLD SCRIPT SMALL P + +1D4FA +MATHEMATICAL BOLD SCRIPT SMALL Q + +1D4FB +MATHEMATICAL BOLD SCRIPT SMALL R + +1D4FC +MATHEMATICAL BOLD SCRIPT SMALL S + +1D4FD +MATHEMATICAL BOLD SCRIPT SMALL T + +1D4FE +MATHEMATICAL BOLD SCRIPT SMALL U + +1D4FF +MATHEMATICAL BOLD SCRIPT SMALL V + +1D500 +MATHEMATICAL BOLD SCRIPT SMALL W + +1D501 +MATHEMATICAL BOLD SCRIPT SMALL X + +1D502 +MATHEMATICAL BOLD SCRIPT SMALL Y + +1D503 +MATHEMATICAL BOLD SCRIPT SMALL Z + +1D504 +MATHEMATICAL FRAKTUR CAPITAL A + +1D505 +MATHEMATICAL FRAKTUR CAPITAL B + +1D507 +MATHEMATICAL FRAKTUR CAPITAL D + +1D508 +MATHEMATICAL FRAKTUR CAPITAL E + +1D509 +MATHEMATICAL FRAKTUR CAPITAL F + +1D50A +MATHEMATICAL FRAKTUR CAPITAL G + +1D50D +MATHEMATICAL FRAKTUR CAPITAL J + +1D50E +MATHEMATICAL FRAKTUR CAPITAL K + +1D50F +MATHEMATICAL FRAKTUR CAPITAL L + +1D510 +MATHEMATICAL FRAKTUR CAPITAL M + +1D511 +MATHEMATICAL FRAKTUR CAPITAL N + +1D512 +MATHEMATICAL FRAKTUR CAPITAL O + +1D513 +MATHEMATICAL FRAKTUR CAPITAL P + +1D514 +MATHEMATICAL FRAKTUR CAPITAL Q + +1D516 +MATHEMATICAL FRAKTUR CAPITAL S + +1D517 +MATHEMATICAL FRAKTUR CAPITAL T + +1D518 +MATHEMATICAL FRAKTUR CAPITAL U + +1D519 +MATHEMATICAL FRAKTUR CAPITAL V + +1D51A +MATHEMATICAL FRAKTUR CAPITAL W + +1D51B +MATHEMATICAL FRAKTUR CAPITAL X + +1D51C +MATHEMATICAL FRAKTUR CAPITAL Y + +1D51E +MATHEMATICAL FRAKTUR SMALL A + +1D51F +MATHEMATICAL FRAKTUR SMALL B + +1D520 +MATHEMATICAL FRAKTUR SMALL C + +1D521 +MATHEMATICAL FRAKTUR SMALL D + +1D522 +MATHEMATICAL FRAKTUR SMALL E + +1D523 +MATHEMATICAL FRAKTUR SMALL F + +1D524 +MATHEMATICAL FRAKTUR SMALL G + +1D525 +MATHEMATICAL FRAKTUR SMALL H + +1D526 +MATHEMATICAL FRAKTUR SMALL I + +1D527 +MATHEMATICAL FRAKTUR SMALL J + +1D528 +MATHEMATICAL FRAKTUR SMALL K + +1D529 +MATHEMATICAL FRAKTUR SMALL L + +1D52A +MATHEMATICAL FRAKTUR SMALL M + +1D52B +MATHEMATICAL FRAKTUR SMALL N + +1D52C +MATHEMATICAL FRAKTUR SMALL O + +1D52D +MATHEMATICAL FRAKTUR SMALL P + +1D52E +MATHEMATICAL FRAKTUR SMALL Q + +1D52F +MATHEMATICAL FRAKTUR SMALL R + +1D530 +MATHEMATICAL FRAKTUR SMALL S + +1D531 +MATHEMATICAL FRAKTUR SMALL T + +1D532 +MATHEMATICAL FRAKTUR SMALL U + +1D533 +MATHEMATICAL FRAKTUR SMALL V + +1D534 +MATHEMATICAL FRAKTUR SMALL W + +1D535 +MATHEMATICAL FRAKTUR SMALL X + +1D536 +MATHEMATICAL FRAKTUR SMALL Y + +1D537 +MATHEMATICAL FRAKTUR SMALL Z + +1D538 +MATHEMATICAL DOUBLE-STRUCK CAPITAL A + +1D539 +MATHEMATICAL DOUBLE-STRUCK CAPITAL B + +1D53B +MATHEMATICAL DOUBLE-STRUCK CAPITAL D + +1D53C +MATHEMATICAL DOUBLE-STRUCK CAPITAL E + +1D53D +MATHEMATICAL DOUBLE-STRUCK CAPITAL F + +1D53E +MATHEMATICAL DOUBLE-STRUCK CAPITAL G + +1D540 +MATHEMATICAL DOUBLE-STRUCK CAPITAL I + +1D541 +MATHEMATICAL DOUBLE-STRUCK CAPITAL J + +1D542 +MATHEMATICAL DOUBLE-STRUCK CAPITAL K + +1D543 +MATHEMATICAL DOUBLE-STRUCK CAPITAL L + +1D544 +MATHEMATICAL DOUBLE-STRUCK CAPITAL M + +1D546 +MATHEMATICAL DOUBLE-STRUCK CAPITAL O + +1D54A +MATHEMATICAL DOUBLE-STRUCK CAPITAL S + +1D54B +MATHEMATICAL DOUBLE-STRUCK CAPITAL T + +1D54C +MATHEMATICAL DOUBLE-STRUCK CAPITAL U + +1D54D +MATHEMATICAL DOUBLE-STRUCK CAPITAL V + +1D54E +MATHEMATICAL DOUBLE-STRUCK CAPITAL W + +1D54F +MATHEMATICAL DOUBLE-STRUCK CAPITAL X + +1D550 +MATHEMATICAL DOUBLE-STRUCK CAPITAL Y + +1D552 +MATHEMATICAL DOUBLE-STRUCK SMALL A + +1D553 +MATHEMATICAL DOUBLE-STRUCK SMALL B + +1D554 +MATHEMATICAL DOUBLE-STRUCK SMALL C + +1D555 +MATHEMATICAL DOUBLE-STRUCK SMALL D + +1D556 +MATHEMATICAL DOUBLE-STRUCK SMALL E + +1D557 +MATHEMATICAL DOUBLE-STRUCK SMALL F + +1D558 +MATHEMATICAL DOUBLE-STRUCK SMALL G + +1D559 +MATHEMATICAL DOUBLE-STRUCK SMALL H + +1D55A +MATHEMATICAL DOUBLE-STRUCK SMALL I + +1D55B +MATHEMATICAL DOUBLE-STRUCK SMALL J + +1D55C +MATHEMATICAL DOUBLE-STRUCK SMALL K + +1D55D +MATHEMATICAL DOUBLE-STRUCK SMALL L + +1D55E +MATHEMATICAL DOUBLE-STRUCK SMALL M + +1D55F +MATHEMATICAL DOUBLE-STRUCK SMALL N + +1D560 +MATHEMATICAL DOUBLE-STRUCK SMALL O + +1D561 +MATHEMATICAL DOUBLE-STRUCK SMALL P + +1D562 +MATHEMATICAL DOUBLE-STRUCK SMALL Q + +1D563 +MATHEMATICAL DOUBLE-STRUCK SMALL R + +1D564 +MATHEMATICAL DOUBLE-STRUCK SMALL S + +1D565 +MATHEMATICAL DOUBLE-STRUCK SMALL T + +1D566 +MATHEMATICAL DOUBLE-STRUCK SMALL U + +1D567 +MATHEMATICAL DOUBLE-STRUCK SMALL V + +1D568 +MATHEMATICAL DOUBLE-STRUCK SMALL W + +1D569 +MATHEMATICAL DOUBLE-STRUCK SMALL X + +1D56A +MATHEMATICAL DOUBLE-STRUCK SMALL Y + +1D56B +MATHEMATICAL DOUBLE-STRUCK SMALL Z + +1D56C +MATHEMATICAL BOLD FRAKTUR CAPITAL A + +1D56D +MATHEMATICAL BOLD FRAKTUR CAPITAL B + +1D56E +MATHEMATICAL BOLD FRAKTUR CAPITAL C + +1D56F +MATHEMATICAL BOLD FRAKTUR CAPITAL D + +1D570 +MATHEMATICAL BOLD FRAKTUR CAPITAL E + +1D571 +MATHEMATICAL BOLD FRAKTUR CAPITAL F + +1D572 +MATHEMATICAL BOLD FRAKTUR CAPITAL G + +1D573 +MATHEMATICAL BOLD FRAKTUR CAPITAL H + +1D574 +MATHEMATICAL BOLD FRAKTUR CAPITAL I + +1D575 +MATHEMATICAL BOLD FRAKTUR CAPITAL J + +1D576 +MATHEMATICAL BOLD FRAKTUR CAPITAL K + +1D577 +MATHEMATICAL BOLD FRAKTUR CAPITAL L + +1D578 +MATHEMATICAL BOLD FRAKTUR CAPITAL M + +1D579 +MATHEMATICAL BOLD FRAKTUR CAPITAL N + +1D57A +MATHEMATICAL BOLD FRAKTUR CAPITAL O + +1D57B +MATHEMATICAL BOLD FRAKTUR CAPITAL P + +1D57C +MATHEMATICAL BOLD FRAKTUR CAPITAL Q + +1D57D +MATHEMATICAL BOLD FRAKTUR CAPITAL R + +1D57E +MATHEMATICAL BOLD FRAKTUR CAPITAL S + +1D57F +MATHEMATICAL BOLD FRAKTUR CAPITAL T + +1D580 +MATHEMATICAL BOLD FRAKTUR CAPITAL U + +1D581 +MATHEMATICAL BOLD FRAKTUR CAPITAL V + +1D582 +MATHEMATICAL BOLD FRAKTUR CAPITAL W + +1D583 +MATHEMATICAL BOLD FRAKTUR CAPITAL X + +1D584 +MATHEMATICAL BOLD FRAKTUR CAPITAL Y + +1D585 +MATHEMATICAL BOLD FRAKTUR CAPITAL Z + +1D586 +MATHEMATICAL BOLD FRAKTUR SMALL A + +1D587 +MATHEMATICAL BOLD FRAKTUR SMALL B + +1D588 +MATHEMATICAL BOLD FRAKTUR SMALL C + +1D589 +MATHEMATICAL BOLD FRAKTUR SMALL D + +1D58A +MATHEMATICAL BOLD FRAKTUR SMALL E + +1D58B +MATHEMATICAL BOLD FRAKTUR SMALL F + +1D58C +MATHEMATICAL BOLD FRAKTUR SMALL G + +1D58D +MATHEMATICAL BOLD FRAKTUR SMALL H + +1D58E +MATHEMATICAL BOLD FRAKTUR SMALL I + +1D58F +MATHEMATICAL BOLD FRAKTUR SMALL J + +1D590 +MATHEMATICAL BOLD FRAKTUR SMALL K + +1D591 +MATHEMATICAL BOLD FRAKTUR SMALL L + +1D592 +MATHEMATICAL BOLD FRAKTUR SMALL M + +1D593 +MATHEMATICAL BOLD FRAKTUR SMALL N + +1D594 +MATHEMATICAL BOLD FRAKTUR SMALL O + +1D595 +MATHEMATICAL BOLD FRAKTUR SMALL P + +1D596 +MATHEMATICAL BOLD FRAKTUR SMALL Q + +1D597 +MATHEMATICAL BOLD FRAKTUR SMALL R + +1D598 +MATHEMATICAL BOLD FRAKTUR SMALL S + +1D599 +MATHEMATICAL BOLD FRAKTUR SMALL T + +1D59A +MATHEMATICAL BOLD FRAKTUR SMALL U + +1D59B +MATHEMATICAL BOLD FRAKTUR SMALL V + +1D59C +MATHEMATICAL BOLD FRAKTUR SMALL W + +1D59D +MATHEMATICAL BOLD FRAKTUR SMALL X + +1D59E +MATHEMATICAL BOLD FRAKTUR SMALL Y + +1D59F +MATHEMATICAL BOLD FRAKTUR SMALL Z + +1D5A0 +MATHEMATICAL SANS-SERIF CAPITAL A + +1D5A1 +MATHEMATICAL SANS-SERIF CAPITAL B + +1D5A2 +MATHEMATICAL SANS-SERIF CAPITAL C + +1D5A3 +MATHEMATICAL SANS-SERIF CAPITAL D + +1D5A4 +MATHEMATICAL SANS-SERIF CAPITAL E + +1D5A5 +MATHEMATICAL SANS-SERIF CAPITAL F + +1D5A6 +MATHEMATICAL SANS-SERIF CAPITAL G + +1D5A7 +MATHEMATICAL SANS-SERIF CAPITAL H + +1D5A8 +MATHEMATICAL SANS-SERIF CAPITAL I + +1D5A9 +MATHEMATICAL SANS-SERIF CAPITAL J + +1D5AA +MATHEMATICAL SANS-SERIF CAPITAL K + +1D5AB +MATHEMATICAL SANS-SERIF CAPITAL L + +1D5AC +MATHEMATICAL SANS-SERIF CAPITAL M + +1D5AD +MATHEMATICAL SANS-SERIF CAPITAL N + +1D5AE +MATHEMATICAL SANS-SERIF CAPITAL O + +1D5AF +MATHEMATICAL SANS-SERIF CAPITAL P + +1D5B0 +MATHEMATICAL SANS-SERIF CAPITAL Q + +1D5B1 +MATHEMATICAL SANS-SERIF CAPITAL R + +1D5B2 +MATHEMATICAL SANS-SERIF CAPITAL S + +1D5B3 +MATHEMATICAL SANS-SERIF CAPITAL T + +1D5B4 +MATHEMATICAL SANS-SERIF CAPITAL U + +1D5B5 +MATHEMATICAL SANS-SERIF CAPITAL V + +1D5B6 +MATHEMATICAL SANS-SERIF CAPITAL W + +1D5B7 +MATHEMATICAL SANS-SERIF CAPITAL X + +1D5B8 +MATHEMATICAL SANS-SERIF CAPITAL Y + +1D5B9 +MATHEMATICAL SANS-SERIF CAPITAL Z + +1D5BA +MATHEMATICAL SANS-SERIF SMALL A + +1D5BB +MATHEMATICAL SANS-SERIF SMALL B + +1D5BC +MATHEMATICAL SANS-SERIF SMALL C + +1D5BD +MATHEMATICAL SANS-SERIF SMALL D + +1D5BE +MATHEMATICAL SANS-SERIF SMALL E + +1D5BF +MATHEMATICAL SANS-SERIF SMALL F + +1D5C0 +MATHEMATICAL SANS-SERIF SMALL G + +1D5C1 +MATHEMATICAL SANS-SERIF SMALL H + +1D5C2 +MATHEMATICAL SANS-SERIF SMALL I + +1D5C3 +MATHEMATICAL SANS-SERIF SMALL J + +1D5C4 +MATHEMATICAL SANS-SERIF SMALL K + +1D5C5 +MATHEMATICAL SANS-SERIF SMALL L + +1D5C6 +MATHEMATICAL SANS-SERIF SMALL M + +1D5C7 +MATHEMATICAL SANS-SERIF SMALL N + +1D5C8 +MATHEMATICAL SANS-SERIF SMALL O + +1D5C9 +MATHEMATICAL SANS-SERIF SMALL P + +1D5CA +MATHEMATICAL SANS-SERIF SMALL Q + +1D5CB +MATHEMATICAL SANS-SERIF SMALL R + +1D5CC +MATHEMATICAL SANS-SERIF SMALL S + +1D5CD +MATHEMATICAL SANS-SERIF SMALL T + +1D5CE +MATHEMATICAL SANS-SERIF SMALL U + +1D5CF +MATHEMATICAL SANS-SERIF SMALL V + +1D5D0 +MATHEMATICAL SANS-SERIF SMALL W + +1D5D1 +MATHEMATICAL SANS-SERIF SMALL X + +1D5D2 +MATHEMATICAL SANS-SERIF SMALL Y + +1D5D3 +MATHEMATICAL SANS-SERIF SMALL Z + +1D5D4 +MATHEMATICAL SANS-SERIF BOLD CAPITAL A + +1D5D5 +MATHEMATICAL SANS-SERIF BOLD CAPITAL B + +1D5D6 +MATHEMATICAL SANS-SERIF BOLD CAPITAL C + +1D5D7 +MATHEMATICAL SANS-SERIF BOLD CAPITAL D + +1D5D8 +MATHEMATICAL SANS-SERIF BOLD CAPITAL E + +1D5D9 +MATHEMATICAL SANS-SERIF BOLD CAPITAL F + +1D5DA +MATHEMATICAL SANS-SERIF BOLD CAPITAL G + +1D5DB +MATHEMATICAL SANS-SERIF BOLD CAPITAL H + +1D5DC +MATHEMATICAL SANS-SERIF BOLD CAPITAL I + +1D5DD +MATHEMATICAL SANS-SERIF BOLD CAPITAL J + +1D5DE +MATHEMATICAL SANS-SERIF BOLD CAPITAL K + +1D5DF +MATHEMATICAL SANS-SERIF BOLD CAPITAL L + +1D5E0 +MATHEMATICAL SANS-SERIF BOLD CAPITAL M + +1D5E1 +MATHEMATICAL SANS-SERIF BOLD CAPITAL N + +1D5E2 +MATHEMATICAL SANS-SERIF BOLD CAPITAL O + +1D5E3 +MATHEMATICAL SANS-SERIF BOLD CAPITAL P + +1D5E4 +MATHEMATICAL SANS-SERIF BOLD CAPITAL Q + +1D5E5 +MATHEMATICAL SANS-SERIF BOLD CAPITAL R + +1D5E6 +MATHEMATICAL SANS-SERIF BOLD CAPITAL S + +1D5E7 +MATHEMATICAL SANS-SERIF BOLD CAPITAL T + +1D5E8 +MATHEMATICAL SANS-SERIF BOLD CAPITAL U + +1D5E9 +MATHEMATICAL SANS-SERIF BOLD CAPITAL V + +1D5EA +MATHEMATICAL SANS-SERIF BOLD CAPITAL W + +1D5EB +MATHEMATICAL SANS-SERIF BOLD CAPITAL X + +1D5EC +MATHEMATICAL SANS-SERIF BOLD CAPITAL Y + +1D5ED +MATHEMATICAL SANS-SERIF BOLD CAPITAL Z + +1D5EE +MATHEMATICAL SANS-SERIF BOLD SMALL A + +1D5EF +MATHEMATICAL SANS-SERIF BOLD SMALL B + +1D5F0 +MATHEMATICAL SANS-SERIF BOLD SMALL C + +1D5F1 +MATHEMATICAL SANS-SERIF BOLD SMALL D + +1D5F2 +MATHEMATICAL SANS-SERIF BOLD SMALL E + +1D5F3 +MATHEMATICAL SANS-SERIF BOLD SMALL F + +1D5F4 +MATHEMATICAL SANS-SERIF BOLD SMALL G + +1D5F5 +MATHEMATICAL SANS-SERIF BOLD SMALL H + +1D5F6 +MATHEMATICAL SANS-SERIF BOLD SMALL I + +1D5F7 +MATHEMATICAL SANS-SERIF BOLD SMALL J + +1D5F8 +MATHEMATICAL SANS-SERIF BOLD SMALL K + +1D5F9 +MATHEMATICAL SANS-SERIF BOLD SMALL L + +1D5FA +MATHEMATICAL SANS-SERIF BOLD SMALL M + +1D5FB +MATHEMATICAL SANS-SERIF BOLD SMALL N + +1D5FC +MATHEMATICAL SANS-SERIF BOLD SMALL O + +1D5FD +MATHEMATICAL SANS-SERIF BOLD SMALL P + +1D5FE +MATHEMATICAL SANS-SERIF BOLD SMALL Q + +1D5FF +MATHEMATICAL SANS-SERIF BOLD SMALL R + +1D600 +MATHEMATICAL SANS-SERIF BOLD SMALL S + +1D601 +MATHEMATICAL SANS-SERIF BOLD SMALL T + +1D602 +MATHEMATICAL SANS-SERIF BOLD SMALL U + +1D603 +MATHEMATICAL SANS-SERIF BOLD SMALL V + +1D604 +MATHEMATICAL SANS-SERIF BOLD SMALL W + +1D605 +MATHEMATICAL SANS-SERIF BOLD SMALL X + +1D606 +MATHEMATICAL SANS-SERIF BOLD SMALL Y + +1D607 +MATHEMATICAL SANS-SERIF BOLD SMALL Z + +1D608 +MATHEMATICAL SANS-SERIF ITALIC CAPITAL A + +1D609 +MATHEMATICAL SANS-SERIF ITALIC CAPITAL B + +1D60A +MATHEMATICAL SANS-SERIF ITALIC CAPITAL C + +1D60B +MATHEMATICAL SANS-SERIF ITALIC CAPITAL D + +1D60C +MATHEMATICAL SANS-SERIF ITALIC CAPITAL E + +1D60D +MATHEMATICAL SANS-SERIF ITALIC CAPITAL F + +1D60E +MATHEMATICAL SANS-SERIF ITALIC CAPITAL G + +1D60F +MATHEMATICAL SANS-SERIF ITALIC CAPITAL H + +1D610 +MATHEMATICAL SANS-SERIF ITALIC CAPITAL I + +1D611 +MATHEMATICAL SANS-SERIF ITALIC CAPITAL J + +1D612 +MATHEMATICAL SANS-SERIF ITALIC CAPITAL K + +1D613 +MATHEMATICAL SANS-SERIF ITALIC CAPITAL L + +1D614 +MATHEMATICAL SANS-SERIF ITALIC CAPITAL M + +1D615 +MATHEMATICAL SANS-SERIF ITALIC CAPITAL N + +1D616 +MATHEMATICAL SANS-SERIF ITALIC CAPITAL O + +1D617 +MATHEMATICAL SANS-SERIF ITALIC CAPITAL P + +1D618 +MATHEMATICAL SANS-SERIF ITALIC CAPITAL Q + +1D619 +MATHEMATICAL SANS-SERIF ITALIC CAPITAL R + +1D61A +MATHEMATICAL SANS-SERIF ITALIC CAPITAL S + +1D61B +MATHEMATICAL SANS-SERIF ITALIC CAPITAL T + +1D61C +MATHEMATICAL SANS-SERIF ITALIC CAPITAL U + +1D61D +MATHEMATICAL SANS-SERIF ITALIC CAPITAL V + +1D61E +MATHEMATICAL SANS-SERIF ITALIC CAPITAL W + +1D61F +MATHEMATICAL SANS-SERIF ITALIC CAPITAL X + +1D620 +MATHEMATICAL SANS-SERIF ITALIC CAPITAL Y + +1D621 +MATHEMATICAL SANS-SERIF ITALIC CAPITAL Z + +1D622 +MATHEMATICAL SANS-SERIF ITALIC SMALL A + +1D623 +MATHEMATICAL SANS-SERIF ITALIC SMALL B + +1D624 +MATHEMATICAL SANS-SERIF ITALIC SMALL C + +1D625 +MATHEMATICAL SANS-SERIF ITALIC SMALL D + +1D626 +MATHEMATICAL SANS-SERIF ITALIC SMALL E + +1D627 +MATHEMATICAL SANS-SERIF ITALIC SMALL F + +1D628 +MATHEMATICAL SANS-SERIF ITALIC SMALL G + +1D629 +MATHEMATICAL SANS-SERIF ITALIC SMALL H + +1D62A +MATHEMATICAL SANS-SERIF ITALIC SMALL I + +1D62B +MATHEMATICAL SANS-SERIF ITALIC SMALL J + +1D62C +MATHEMATICAL SANS-SERIF ITALIC SMALL K + +1D62D +MATHEMATICAL SANS-SERIF ITALIC SMALL L + +1D62E +MATHEMATICAL SANS-SERIF ITALIC SMALL M + +1D62F +MATHEMATICAL SANS-SERIF ITALIC SMALL N + +1D630 +MATHEMATICAL SANS-SERIF ITALIC SMALL O + +1D631 +MATHEMATICAL SANS-SERIF ITALIC SMALL P + +1D632 +MATHEMATICAL SANS-SERIF ITALIC SMALL Q + +1D633 +MATHEMATICAL SANS-SERIF ITALIC SMALL R + +1D634 +MATHEMATICAL SANS-SERIF ITALIC SMALL S + +1D635 +MATHEMATICAL SANS-SERIF ITALIC SMALL T + +1D636 +MATHEMATICAL SANS-SERIF ITALIC SMALL U + +1D637 +MATHEMATICAL SANS-SERIF ITALIC SMALL V + +1D638 +MATHEMATICAL SANS-SERIF ITALIC SMALL W + +1D639 +MATHEMATICAL SANS-SERIF ITALIC SMALL X + +1D63A +MATHEMATICAL SANS-SERIF ITALIC SMALL Y + +1D63B +MATHEMATICAL SANS-SERIF ITALIC SMALL Z + +1D63C +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL A + +1D63D +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL B + +1D63E +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL C + +1D63F +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL D + +1D640 +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL E + +1D641 +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL F + +1D642 +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL G + +1D643 +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL H + +1D644 +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL I + +1D645 +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL J + +1D646 +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL K + +1D647 +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL L + +1D648 +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL M + +1D649 +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL N + +1D64A +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL O + +1D64B +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL P + +1D64C +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Q + +1D64D +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL R + +1D64E +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL S + +1D64F +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL T + +1D650 +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL U + +1D651 +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL V + +1D652 +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL W + +1D653 +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL X + +1D654 +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Y + +1D655 +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Z + +1D656 +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL A + +1D657 +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL B + +1D658 +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL C + +1D659 +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL D + +1D65A +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL E + +1D65B +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL F + +1D65C +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL G + +1D65D +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL H + +1D65E +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL I + +1D65F +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL J + +1D660 +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL K + +1D661 +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL L + +1D662 +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL M + +1D663 +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL N + +1D664 +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL O + +1D665 +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL P + +1D666 +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Q + +1D667 +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL R + +1D668 +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL S + +1D669 +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL T + +1D66A +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL U + +1D66B +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL V + +1D66C +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL W + +1D66D +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL X + +1D66E +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Y + +1D66F +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Z + +1D670 +MATHEMATICAL MONOSPACE CAPITAL A + +1D671 +MATHEMATICAL MONOSPACE CAPITAL B + +1D672 +MATHEMATICAL MONOSPACE CAPITAL C + +1D673 +MATHEMATICAL MONOSPACE CAPITAL D + +1D674 +MATHEMATICAL MONOSPACE CAPITAL E + +1D675 +MATHEMATICAL MONOSPACE CAPITAL F + +1D676 +MATHEMATICAL MONOSPACE CAPITAL G + +1D677 +MATHEMATICAL MONOSPACE CAPITAL H + +1D678 +MATHEMATICAL MONOSPACE CAPITAL I + +1D679 +MATHEMATICAL MONOSPACE CAPITAL J + +1D67A +MATHEMATICAL MONOSPACE CAPITAL K + +1D67B +MATHEMATICAL MONOSPACE CAPITAL L + +1D67C +MATHEMATICAL MONOSPACE CAPITAL M + +1D67D +MATHEMATICAL MONOSPACE CAPITAL N + +1D67E +MATHEMATICAL MONOSPACE CAPITAL O + +1D67F +MATHEMATICAL MONOSPACE CAPITAL P + +1D680 +MATHEMATICAL MONOSPACE CAPITAL Q + +1D681 +MATHEMATICAL MONOSPACE CAPITAL R + +1D682 +MATHEMATICAL MONOSPACE CAPITAL S + +1D683 +MATHEMATICAL MONOSPACE CAPITAL T + +1D684 +MATHEMATICAL MONOSPACE CAPITAL U + +1D685 +MATHEMATICAL MONOSPACE CAPITAL V + +1D686 +MATHEMATICAL MONOSPACE CAPITAL W + +1D687 +MATHEMATICAL MONOSPACE CAPITAL X + +1D688 +MATHEMATICAL MONOSPACE CAPITAL Y + +1D689 +MATHEMATICAL MONOSPACE CAPITAL Z + +1D68A +MATHEMATICAL MONOSPACE SMALL A + +1D68B +MATHEMATICAL MONOSPACE SMALL B + +1D68C +MATHEMATICAL MONOSPACE SMALL C + +1D68D +MATHEMATICAL MONOSPACE SMALL D + +1D68E +MATHEMATICAL MONOSPACE SMALL E + +1D68F +MATHEMATICAL MONOSPACE SMALL F + +1D690 +MATHEMATICAL MONOSPACE SMALL G + +1D691 +MATHEMATICAL MONOSPACE SMALL H + +1D692 +MATHEMATICAL MONOSPACE SMALL I + +1D693 +MATHEMATICAL MONOSPACE SMALL J + +1D694 +MATHEMATICAL MONOSPACE SMALL K + +1D695 +MATHEMATICAL MONOSPACE SMALL L + +1D696 +MATHEMATICAL MONOSPACE SMALL M + +1D697 +MATHEMATICAL MONOSPACE SMALL N + +1D698 +MATHEMATICAL MONOSPACE SMALL O + +1D699 +MATHEMATICAL MONOSPACE SMALL P + +1D69A +MATHEMATICAL MONOSPACE SMALL Q + +1D69B +MATHEMATICAL MONOSPACE SMALL R + +1D69C +MATHEMATICAL MONOSPACE SMALL S + +1D69D +MATHEMATICAL MONOSPACE SMALL T + +1D69E +MATHEMATICAL MONOSPACE SMALL U + +1D69F +MATHEMATICAL MONOSPACE SMALL V + +1D6A0 +MATHEMATICAL MONOSPACE SMALL W + +1D6A1 +MATHEMATICAL MONOSPACE SMALL X + +1D6A2 +MATHEMATICAL MONOSPACE SMALL Y + +1D6A3 +MATHEMATICAL MONOSPACE SMALL Z + +1D6A4 +MATHEMATICAL ITALIC SMALL DOTLESS I + +1D6A5 +MATHEMATICAL ITALIC SMALL DOTLESS J + +1D6A8 +MATHEMATICAL BOLD CAPITAL ALPHA + +1D6A9 +MATHEMATICAL BOLD CAPITAL BETA + +1D6AA +MATHEMATICAL BOLD CAPITAL GAMMA + +1D6AB +MATHEMATICAL BOLD CAPITAL DELTA + +1D6AC +MATHEMATICAL BOLD CAPITAL EPSILON + +1D6AD +MATHEMATICAL BOLD CAPITAL ZETA + +1D6AE +MATHEMATICAL BOLD CAPITAL ETA + +1D6AF +MATHEMATICAL BOLD CAPITAL THETA + +1D6B0 +MATHEMATICAL BOLD CAPITAL IOTA + +1D6B1 +MATHEMATICAL BOLD CAPITAL KAPPA + +1D6B2 +MATHEMATICAL BOLD CAPITAL LAMDA + +1D6B3 +MATHEMATICAL BOLD CAPITAL MU + +1D6B4 +MATHEMATICAL BOLD CAPITAL NU + +1D6B5 +MATHEMATICAL BOLD CAPITAL XI + +1D6B6 +MATHEMATICAL BOLD CAPITAL OMICRON + +1D6B7 +MATHEMATICAL BOLD CAPITAL PI + +1D6B8 +MATHEMATICAL BOLD CAPITAL RHO + +1D6B9 +MATHEMATICAL BOLD CAPITAL THETA SYMBOL + +1D6BA +MATHEMATICAL BOLD CAPITAL SIGMA + +1D6BB +MATHEMATICAL BOLD CAPITAL TAU + +1D6BC +MATHEMATICAL BOLD CAPITAL UPSILON + +1D6BD +MATHEMATICAL BOLD CAPITAL PHI + +1D6BE +MATHEMATICAL BOLD CAPITAL CHI + +1D6BF +MATHEMATICAL BOLD CAPITAL PSI + +1D6C0 +MATHEMATICAL BOLD CAPITAL OMEGA + +1D6C1 +MATHEMATICAL BOLD NABLA + +1D6C2 +MATHEMATICAL BOLD SMALL ALPHA + +1D6C3 +MATHEMATICAL BOLD SMALL BETA + +1D6C4 +MATHEMATICAL BOLD SMALL GAMMA + +1D6C5 +MATHEMATICAL BOLD SMALL DELTA + +1D6C6 +MATHEMATICAL BOLD SMALL EPSILON + +1D6C7 +MATHEMATICAL BOLD SMALL ZETA + +1D6C8 +MATHEMATICAL BOLD SMALL ETA + +1D6C9 +MATHEMATICAL BOLD SMALL THETA + +1D6CA +MATHEMATICAL BOLD SMALL IOTA + +1D6CB +MATHEMATICAL BOLD SMALL KAPPA + +1D6CC +MATHEMATICAL BOLD SMALL LAMDA + +1D6CD +MATHEMATICAL BOLD SMALL MU + +1D6CE +MATHEMATICAL BOLD SMALL NU + +1D6CF +MATHEMATICAL BOLD SMALL XI + +1D6D0 +MATHEMATICAL BOLD SMALL OMICRON + +1D6D1 +MATHEMATICAL BOLD SMALL PI + +1D6D2 +MATHEMATICAL BOLD SMALL RHO + +1D6D3 +MATHEMATICAL BOLD SMALL FINAL SIGMA + +1D6D4 +MATHEMATICAL BOLD SMALL SIGMA + +1D6D5 +MATHEMATICAL BOLD SMALL TAU + +1D6D6 +MATHEMATICAL BOLD SMALL UPSILON + +1D6D7 +MATHEMATICAL BOLD SMALL PHI + +1D6D8 +MATHEMATICAL BOLD SMALL CHI + +1D6D9 +MATHEMATICAL BOLD SMALL PSI + +1D6DA +MATHEMATICAL BOLD SMALL OMEGA + +1D6DB +MATHEMATICAL BOLD PARTIAL DIFFERENTIAL + +1D6DC +MATHEMATICAL BOLD EPSILON SYMBOL + +1D6DD +MATHEMATICAL BOLD THETA SYMBOL + +1D6DE +MATHEMATICAL BOLD KAPPA SYMBOL + +1D6DF +MATHEMATICAL BOLD PHI SYMBOL + +1D6E0 +MATHEMATICAL BOLD RHO SYMBOL + +1D6E1 +MATHEMATICAL BOLD PI SYMBOL + +1D6E2 +MATHEMATICAL ITALIC CAPITAL ALPHA + +1D6E3 +MATHEMATICAL ITALIC CAPITAL BETA + +1D6E4 +MATHEMATICAL ITALIC CAPITAL GAMMA + +1D6E5 +MATHEMATICAL ITALIC CAPITAL DELTA + +1D6E6 +MATHEMATICAL ITALIC CAPITAL EPSILON + +1D6E7 +MATHEMATICAL ITALIC CAPITAL ZETA + +1D6E8 +MATHEMATICAL ITALIC CAPITAL ETA + +1D6E9 +MATHEMATICAL ITALIC CAPITAL THETA + +1D6EA +MATHEMATICAL ITALIC CAPITAL IOTA + +1D6EB +MATHEMATICAL ITALIC CAPITAL KAPPA + +1D6EC +MATHEMATICAL ITALIC CAPITAL LAMDA + +1D6ED +MATHEMATICAL ITALIC CAPITAL MU + +1D6EE +MATHEMATICAL ITALIC CAPITAL NU + +1D6EF +MATHEMATICAL ITALIC CAPITAL XI + +1D6F0 +MATHEMATICAL ITALIC CAPITAL OMICRON + +1D6F1 +MATHEMATICAL ITALIC CAPITAL PI + +1D6F2 +MATHEMATICAL ITALIC CAPITAL RHO + +1D6F3 +MATHEMATICAL ITALIC CAPITAL THETA SYMBOL + +1D6F4 +MATHEMATICAL ITALIC CAPITAL SIGMA + +1D6F5 +MATHEMATICAL ITALIC CAPITAL TAU + +1D6F6 +MATHEMATICAL ITALIC CAPITAL UPSILON + +1D6F7 +MATHEMATICAL ITALIC CAPITAL PHI + +1D6F8 +MATHEMATICAL ITALIC CAPITAL CHI + +1D6F9 +MATHEMATICAL ITALIC CAPITAL PSI + +1D6FA +MATHEMATICAL ITALIC CAPITAL OMEGA + +1D6FB +MATHEMATICAL ITALIC NABLA + +1D6FC +MATHEMATICAL ITALIC SMALL ALPHA + +1D6FD +MATHEMATICAL ITALIC SMALL BETA + +1D6FE +MATHEMATICAL ITALIC SMALL GAMMA + +1D6FF +MATHEMATICAL ITALIC SMALL DELTA + +1D700 +MATHEMATICAL ITALIC SMALL EPSILON + +1D701 +MATHEMATICAL ITALIC SMALL ZETA + +1D702 +MATHEMATICAL ITALIC SMALL ETA + +1D703 +MATHEMATICAL ITALIC SMALL THETA + +1D704 +MATHEMATICAL ITALIC SMALL IOTA + +1D705 +MATHEMATICAL ITALIC SMALL KAPPA + +1D706 +MATHEMATICAL ITALIC SMALL LAMDA + +1D707 +MATHEMATICAL ITALIC SMALL MU + +1D708 +MATHEMATICAL ITALIC SMALL NU + +1D709 +MATHEMATICAL ITALIC SMALL XI + +1D70A +MATHEMATICAL ITALIC SMALL OMICRON + +1D70B +MATHEMATICAL ITALIC SMALL PI + +1D70C +MATHEMATICAL ITALIC SMALL RHO + +1D70D +MATHEMATICAL ITALIC SMALL FINAL SIGMA + +1D70E +MATHEMATICAL ITALIC SMALL SIGMA + +1D70F +MATHEMATICAL ITALIC SMALL TAU + +1D710 +MATHEMATICAL ITALIC SMALL UPSILON + +1D711 +MATHEMATICAL ITALIC SMALL PHI + +1D712 +MATHEMATICAL ITALIC SMALL CHI + +1D713 +MATHEMATICAL ITALIC SMALL PSI + +1D714 +MATHEMATICAL ITALIC SMALL OMEGA + +1D715 +MATHEMATICAL ITALIC PARTIAL DIFFERENTIAL + +1D716 +MATHEMATICAL ITALIC EPSILON SYMBOL + +1D717 +MATHEMATICAL ITALIC THETA SYMBOL + +1D718 +MATHEMATICAL ITALIC KAPPA SYMBOL + +1D719 +MATHEMATICAL ITALIC PHI SYMBOL + +1D71A +MATHEMATICAL ITALIC RHO SYMBOL + +1D71B +MATHEMATICAL ITALIC PI SYMBOL + +1D71C +MATHEMATICAL BOLD ITALIC CAPITAL ALPHA + +1D71D +MATHEMATICAL BOLD ITALIC CAPITAL BETA + +1D71E +MATHEMATICAL BOLD ITALIC CAPITAL GAMMA + +1D71F +MATHEMATICAL BOLD ITALIC CAPITAL DELTA + +1D720 +MATHEMATICAL BOLD ITALIC CAPITAL EPSILON + +1D721 +MATHEMATICAL BOLD ITALIC CAPITAL ZETA + +1D722 +MATHEMATICAL BOLD ITALIC CAPITAL ETA + +1D723 +MATHEMATICAL BOLD ITALIC CAPITAL THETA + +1D724 +MATHEMATICAL BOLD ITALIC CAPITAL IOTA + +1D725 +MATHEMATICAL BOLD ITALIC CAPITAL KAPPA + +1D726 +MATHEMATICAL BOLD ITALIC CAPITAL LAMDA + +1D727 +MATHEMATICAL BOLD ITALIC CAPITAL MU + +1D728 +MATHEMATICAL BOLD ITALIC CAPITAL NU + +1D729 +MATHEMATICAL BOLD ITALIC CAPITAL XI + +1D72A +MATHEMATICAL BOLD ITALIC CAPITAL OMICRON + +1D72B +MATHEMATICAL BOLD ITALIC CAPITAL PI + +1D72C +MATHEMATICAL BOLD ITALIC CAPITAL RHO + +1D72D +MATHEMATICAL BOLD ITALIC CAPITAL THETA SYMBOL + +1D72E +MATHEMATICAL BOLD ITALIC CAPITAL SIGMA + +1D72F +MATHEMATICAL BOLD ITALIC CAPITAL TAU + +1D730 +MATHEMATICAL BOLD ITALIC CAPITAL UPSILON + +1D731 +MATHEMATICAL BOLD ITALIC CAPITAL PHI + +1D732 +MATHEMATICAL BOLD ITALIC CAPITAL CHI + +1D733 +MATHEMATICAL BOLD ITALIC CAPITAL PSI + +1D734 +MATHEMATICAL BOLD ITALIC CAPITAL OMEGA + +1D735 +MATHEMATICAL BOLD ITALIC NABLA + +1D736 +MATHEMATICAL BOLD ITALIC SMALL ALPHA + +1D737 +MATHEMATICAL BOLD ITALIC SMALL BETA + +1D738 +MATHEMATICAL BOLD ITALIC SMALL GAMMA + +1D739 +MATHEMATICAL BOLD ITALIC SMALL DELTA + +1D73A +MATHEMATICAL BOLD ITALIC SMALL EPSILON + +1D73B +MATHEMATICAL BOLD ITALIC SMALL ZETA + +1D73C +MATHEMATICAL BOLD ITALIC SMALL ETA + +1D73D +MATHEMATICAL BOLD ITALIC SMALL THETA + +1D73E +MATHEMATICAL BOLD ITALIC SMALL IOTA + +1D73F +MATHEMATICAL BOLD ITALIC SMALL KAPPA + +1D740 +MATHEMATICAL BOLD ITALIC SMALL LAMDA + +1D741 +MATHEMATICAL BOLD ITALIC SMALL MU + +1D742 +MATHEMATICAL BOLD ITALIC SMALL NU + +1D743 +MATHEMATICAL BOLD ITALIC SMALL XI + +1D744 +MATHEMATICAL BOLD ITALIC SMALL OMICRON + +1D745 +MATHEMATICAL BOLD ITALIC SMALL PI + +1D746 +MATHEMATICAL BOLD ITALIC SMALL RHO + +1D747 +MATHEMATICAL BOLD ITALIC SMALL FINAL SIGMA + +1D748 +MATHEMATICAL BOLD ITALIC SMALL SIGMA + +1D749 +MATHEMATICAL BOLD ITALIC SMALL TAU + +1D74A +MATHEMATICAL BOLD ITALIC SMALL UPSILON + +1D74B +MATHEMATICAL BOLD ITALIC SMALL PHI + +1D74C +MATHEMATICAL BOLD ITALIC SMALL CHI + +1D74D +MATHEMATICAL BOLD ITALIC SMALL PSI + +1D74E +MATHEMATICAL BOLD ITALIC SMALL OMEGA + +1D74F +MATHEMATICAL BOLD ITALIC PARTIAL DIFFERENTIAL + +1D750 +MATHEMATICAL BOLD ITALIC EPSILON SYMBOL + +1D751 +MATHEMATICAL BOLD ITALIC THETA SYMBOL + +1D752 +MATHEMATICAL BOLD ITALIC KAPPA SYMBOL + +1D753 +MATHEMATICAL BOLD ITALIC PHI SYMBOL + +1D754 +MATHEMATICAL BOLD ITALIC RHO SYMBOL + +1D755 +MATHEMATICAL BOLD ITALIC PI SYMBOL + +1D756 +MATHEMATICAL SANS-SERIF BOLD CAPITAL ALPHA + +1D757 +MATHEMATICAL SANS-SERIF BOLD CAPITAL BETA + +1D758 +MATHEMATICAL SANS-SERIF BOLD CAPITAL GAMMA + +1D759 +MATHEMATICAL SANS-SERIF BOLD CAPITAL DELTA + +1D75A +MATHEMATICAL SANS-SERIF BOLD CAPITAL EPSILON + +1D75B +MATHEMATICAL SANS-SERIF BOLD CAPITAL ZETA + +1D75C +MATHEMATICAL SANS-SERIF BOLD CAPITAL ETA + +1D75D +MATHEMATICAL SANS-SERIF BOLD CAPITAL THETA + +1D75E +MATHEMATICAL SANS-SERIF BOLD CAPITAL IOTA + +1D75F +MATHEMATICAL SANS-SERIF BOLD CAPITAL KAPPA + +1D760 +MATHEMATICAL SANS-SERIF BOLD CAPITAL LAMDA + +1D761 +MATHEMATICAL SANS-SERIF BOLD CAPITAL MU + +1D762 +MATHEMATICAL SANS-SERIF BOLD CAPITAL NU + +1D763 +MATHEMATICAL SANS-SERIF BOLD CAPITAL XI + +1D764 +MATHEMATICAL SANS-SERIF BOLD CAPITAL OMICRON + +1D765 +MATHEMATICAL SANS-SERIF BOLD CAPITAL PI + +1D766 +MATHEMATICAL SANS-SERIF BOLD CAPITAL RHO + +1D767 +MATHEMATICAL SANS-SERIF BOLD CAPITAL THETA SYMBOL + +1D768 +MATHEMATICAL SANS-SERIF BOLD CAPITAL SIGMA + +1D769 +MATHEMATICAL SANS-SERIF BOLD CAPITAL TAU + +1D76A +MATHEMATICAL SANS-SERIF BOLD CAPITAL UPSILON + +1D76B +MATHEMATICAL SANS-SERIF BOLD CAPITAL PHI + +1D76C +MATHEMATICAL SANS-SERIF BOLD CAPITAL CHI + +1D76D +MATHEMATICAL SANS-SERIF BOLD CAPITAL PSI + +1D76E +MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA + +1D76F +MATHEMATICAL SANS-SERIF BOLD NABLA + +1D770 +MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA + +1D771 +MATHEMATICAL SANS-SERIF BOLD SMALL BETA + +1D772 +MATHEMATICAL SANS-SERIF BOLD SMALL GAMMA + +1D773 +MATHEMATICAL SANS-SERIF BOLD SMALL DELTA + +1D774 +MATHEMATICAL SANS-SERIF BOLD SMALL EPSILON + +1D775 +MATHEMATICAL SANS-SERIF BOLD SMALL ZETA + +1D776 +MATHEMATICAL SANS-SERIF BOLD SMALL ETA + +1D777 +MATHEMATICAL SANS-SERIF BOLD SMALL THETA + +1D778 +MATHEMATICAL SANS-SERIF BOLD SMALL IOTA + +1D779 +MATHEMATICAL SANS-SERIF BOLD SMALL KAPPA + +1D77A +MATHEMATICAL SANS-SERIF BOLD SMALL LAMDA + +1D77B +MATHEMATICAL SANS-SERIF BOLD SMALL MU + +1D77C +MATHEMATICAL SANS-SERIF BOLD SMALL NU + +1D77D +MATHEMATICAL SANS-SERIF BOLD SMALL XI + +1D77E +MATHEMATICAL SANS-SERIF BOLD SMALL OMICRON + +1D77F +MATHEMATICAL SANS-SERIF BOLD SMALL PI + +1D780 +MATHEMATICAL SANS-SERIF BOLD SMALL RHO + +1D781 +MATHEMATICAL SANS-SERIF BOLD SMALL FINAL SIGMA + +1D782 +MATHEMATICAL SANS-SERIF BOLD SMALL SIGMA + +1D783 +MATHEMATICAL SANS-SERIF BOLD SMALL TAU + +1D784 +MATHEMATICAL SANS-SERIF BOLD SMALL UPSILON + +1D785 +MATHEMATICAL SANS-SERIF BOLD SMALL PHI + +1D786 +MATHEMATICAL SANS-SERIF BOLD SMALL CHI + +1D787 +MATHEMATICAL SANS-SERIF BOLD SMALL PSI + +1D788 +MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA + +1D789 +MATHEMATICAL SANS-SERIF BOLD PARTIAL DIFFERENTIAL + +1D78A +MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL + +1D78B +MATHEMATICAL SANS-SERIF BOLD THETA SYMBOL + +1D78C +MATHEMATICAL SANS-SERIF BOLD KAPPA SYMBOL + +1D78D +MATHEMATICAL SANS-SERIF BOLD PHI SYMBOL + +1D78E +MATHEMATICAL SANS-SERIF BOLD RHO SYMBOL + +1D78F +MATHEMATICAL SANS-SERIF BOLD PI SYMBOL + +1D790 +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ALPHA + +1D791 +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL BETA + +1D792 +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL GAMMA + +1D793 +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL DELTA + +1D794 +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL EPSILON + +1D795 +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ZETA + +1D796 +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ETA + +1D797 +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL THETA + +1D798 +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL IOTA + +1D799 +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL KAPPA + +1D79A +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL LAMDA + +1D79B +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL MU + +1D79C +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL NU + +1D79D +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL XI + +1D79E +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMICRON + +1D79F +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PI + +1D7A0 +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL RHO + +1D7A1 +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL THETA SYMBOL + +1D7A2 +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL SIGMA + +1D7A3 +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL TAU + +1D7A4 +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL UPSILON + +1D7A5 +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PHI + +1D7A6 +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL CHI + +1D7A7 +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PSI + +1D7A8 +MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA + +1D7A9 +MATHEMATICAL SANS-SERIF BOLD ITALIC NABLA + +1D7AA +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA + +1D7AB +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL BETA + +1D7AC +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL GAMMA + +1D7AD +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL DELTA + +1D7AE +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL EPSILON + +1D7AF +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ZETA + +1D7B0 +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ETA + +1D7B1 +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL THETA + +1D7B2 +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL IOTA + +1D7B3 +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL KAPPA + +1D7B4 +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL LAMDA + +1D7B5 +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL MU + +1D7B6 +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL NU + +1D7B7 +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL XI + +1D7B8 +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMICRON + +1D7B9 +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PI + +1D7BA +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL RHO + +1D7BB +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL FINAL SIGMA + +1D7BC +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL SIGMA + +1D7BD +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL TAU + +1D7BE +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL UPSILON + +1D7BF +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PHI + +1D7C0 +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL CHI + +1D7C1 +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PSI + +1D7C2 +MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA + +1D7C3 +MATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIAL + +1D7C4 +MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL + +1D7C5 +MATHEMATICAL SANS-SERIF BOLD ITALIC THETA SYMBOL + +1D7C6 +MATHEMATICAL SANS-SERIF BOLD ITALIC KAPPA SYMBOL + +1D7C7 +MATHEMATICAL SANS-SERIF BOLD ITALIC PHI SYMBOL + +1D7C8 +MATHEMATICAL SANS-SERIF BOLD ITALIC RHO SYMBOL + +1D7C9 +MATHEMATICAL SANS-SERIF BOLD ITALIC PI SYMBOL + +1D7CA +MATHEMATICAL BOLD CAPITAL DIGAMMA + +1D7CB +MATHEMATICAL BOLD SMALL DIGAMMA + +1D7CE +MATHEMATICAL BOLD DIGIT ZERO + +1D7CF +MATHEMATICAL BOLD DIGIT ONE + +1D7D0 +MATHEMATICAL BOLD DIGIT TWO + +1D7D1 +MATHEMATICAL BOLD DIGIT THREE + +1D7D2 +MATHEMATICAL BOLD DIGIT FOUR + +1D7D3 +MATHEMATICAL BOLD DIGIT FIVE + +1D7D4 +MATHEMATICAL BOLD DIGIT SIX + +1D7D5 +MATHEMATICAL BOLD DIGIT SEVEN + +1D7D6 +MATHEMATICAL BOLD DIGIT EIGHT + +1D7D7 +MATHEMATICAL BOLD DIGIT NINE + +1D7D8 +MATHEMATICAL DOUBLE-STRUCK DIGIT ZERO + +1D7D9 +MATHEMATICAL DOUBLE-STRUCK DIGIT ONE + +1D7DA +MATHEMATICAL DOUBLE-STRUCK DIGIT TWO + +1D7DB +MATHEMATICAL DOUBLE-STRUCK DIGIT THREE + +1D7DC +MATHEMATICAL DOUBLE-STRUCK DIGIT FOUR + +1D7DD +MATHEMATICAL DOUBLE-STRUCK DIGIT FIVE + +1D7DE +MATHEMATICAL DOUBLE-STRUCK DIGIT SIX + +1D7DF +MATHEMATICAL DOUBLE-STRUCK DIGIT SEVEN + +1D7E0 +MATHEMATICAL DOUBLE-STRUCK DIGIT EIGHT + +1D7E1 +MATHEMATICAL DOUBLE-STRUCK DIGIT NINE + +1D7E2 +MATHEMATICAL SANS-SERIF DIGIT ZERO + +1D7E3 +MATHEMATICAL SANS-SERIF DIGIT ONE + +1D7E4 +MATHEMATICAL SANS-SERIF DIGIT TWO + +1D7E5 +MATHEMATICAL SANS-SERIF DIGIT THREE + +1D7E6 +MATHEMATICAL SANS-SERIF DIGIT FOUR + +1D7E7 +MATHEMATICAL SANS-SERIF DIGIT FIVE + +1D7E8 +MATHEMATICAL SANS-SERIF DIGIT SIX + +1D7E9 +MATHEMATICAL SANS-SERIF DIGIT SEVEN + +1D7EA +MATHEMATICAL SANS-SERIF DIGIT EIGHT + +1D7EB +MATHEMATICAL SANS-SERIF DIGIT NINE + +1D7EC +MATHEMATICAL SANS-SERIF BOLD DIGIT ZERO + +1D7ED +MATHEMATICAL SANS-SERIF BOLD DIGIT ONE + +1D7EE +MATHEMATICAL SANS-SERIF BOLD DIGIT TWO + +1D7EF +MATHEMATICAL SANS-SERIF BOLD DIGIT THREE + +1D7F0 +MATHEMATICAL SANS-SERIF BOLD DIGIT FOUR + +1D7F1 +MATHEMATICAL SANS-SERIF BOLD DIGIT FIVE + +1D7F2 +MATHEMATICAL SANS-SERIF BOLD DIGIT SIX + +1D7F3 +MATHEMATICAL SANS-SERIF BOLD DIGIT SEVEN + +1D7F4 +MATHEMATICAL SANS-SERIF BOLD DIGIT EIGHT + +1D7F5 +MATHEMATICAL SANS-SERIF BOLD DIGIT NINE + +1D7F6 +MATHEMATICAL MONOSPACE DIGIT ZERO + +1D7F7 +MATHEMATICAL MONOSPACE DIGIT ONE + +1D7F8 +MATHEMATICAL MONOSPACE DIGIT TWO + +1D7F9 +MATHEMATICAL MONOSPACE DIGIT THREE + +1D7FA +MATHEMATICAL MONOSPACE DIGIT FOUR + +1D7FB +MATHEMATICAL MONOSPACE DIGIT FIVE + +1D7FC +MATHEMATICAL MONOSPACE DIGIT SIX + +1D7FD +MATHEMATICAL MONOSPACE DIGIT SEVEN + +1D7FE +MATHEMATICAL MONOSPACE DIGIT EIGHT + +1D7FF +MATHEMATICAL MONOSPACE DIGIT NINE + +1D800 +SIGNWRITING HAND-FIST INDEX + +1D801 +SIGNWRITING HAND-CIRCLE INDEX + +1D802 +SIGNWRITING HAND-CUP INDEX + +1D803 +SIGNWRITING HAND-OVAL INDEX + +1D804 +SIGNWRITING HAND-HINGE INDEX + +1D805 +SIGNWRITING HAND-ANGLE INDEX + +1D806 +SIGNWRITING HAND-FIST INDEX BENT + +1D807 +SIGNWRITING HAND-CIRCLE INDEX BENT + +1D808 +SIGNWRITING HAND-FIST THUMB UNDER INDEX BENT + +1D809 +SIGNWRITING HAND-FIST INDEX RAISED KNUCKLE + +1D80A +SIGNWRITING HAND-FIST INDEX CUPPED + +1D80B +SIGNWRITING HAND-FIST INDEX HINGED + +1D80C +SIGNWRITING HAND-FIST INDEX HINGED LOW + +1D80D +SIGNWRITING HAND-CIRCLE INDEX HINGE + +1D80E +SIGNWRITING HAND-FIST INDEX MIDDLE + +1D80F +SIGNWRITING HAND-CIRCLE INDEX MIDDLE + +1D810 +SIGNWRITING HAND-FIST INDEX MIDDLE BENT + +1D811 +SIGNWRITING HAND-FIST INDEX MIDDLE RAISED KNUCKLES + +1D812 +SIGNWRITING HAND-FIST INDEX MIDDLE HINGED + +1D813 +SIGNWRITING HAND-FIST INDEX UP MIDDLE HINGED + +1D814 +SIGNWRITING HAND-FIST INDEX HINGED MIDDLE UP + +1D815 +SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED + +1D816 +SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED INDEX BENT + +1D817 +SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED MIDDLE BENT + +1D818 +SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED CUPPED + +1D819 +SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED HINGED + +1D81A +SIGNWRITING HAND-FIST INDEX MIDDLE CROSSED + +1D81B +SIGNWRITING HAND-CIRCLE INDEX MIDDLE CROSSED + +1D81C +SIGNWRITING HAND-FIST MIDDLE BENT OVER INDEX + +1D81D +SIGNWRITING HAND-FIST INDEX BENT OVER MIDDLE + +1D81E +SIGNWRITING HAND-FIST INDEX MIDDLE THUMB + +1D81F +SIGNWRITING HAND-CIRCLE INDEX MIDDLE THUMB + +1D820 +SIGNWRITING HAND-FIST INDEX MIDDLE STRAIGHT THUMB BENT + +1D821 +SIGNWRITING HAND-FIST INDEX MIDDLE BENT THUMB STRAIGHT + +1D822 +SIGNWRITING HAND-FIST INDEX MIDDLE THUMB BENT + +1D823 +SIGNWRITING HAND-FIST INDEX MIDDLE HINGED SPREAD THUMB SIDE + +1D824 +SIGNWRITING HAND-FIST INDEX UP MIDDLE HINGED THUMB SIDE + +1D825 +SIGNWRITING HAND-FIST INDEX UP MIDDLE HINGED THUMB CONJOINED + +1D826 +SIGNWRITING HAND-FIST INDEX HINGED MIDDLE UP THUMB SIDE + +1D827 +SIGNWRITING HAND-FIST INDEX MIDDLE UP SPREAD THUMB FORWARD + +1D828 +SIGNWRITING HAND-FIST INDEX MIDDLE THUMB CUPPED + +1D829 +SIGNWRITING HAND-FIST INDEX MIDDLE THUMB CIRCLED + +1D82A +SIGNWRITING HAND-FIST INDEX MIDDLE THUMB HOOKED + +1D82B +SIGNWRITING HAND-FIST INDEX MIDDLE THUMB HINGED + +1D82C +SIGNWRITING HAND-FIST THUMB BETWEEN INDEX MIDDLE STRAIGHT + +1D82D +SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED THUMB SIDE + +1D82E +SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED THUMB SIDE CONJOINED + +1D82F +SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED THUMB SIDE BENT + +1D830 +SIGNWRITING HAND-FIST MIDDLE THUMB HOOKED INDEX UP + +1D831 +SIGNWRITING HAND-FIST INDEX THUMB HOOKED MIDDLE UP + +1D832 +SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED HINGED THUMB SIDE + +1D833 +SIGNWRITING HAND-FIST INDEX MIDDLE CROSSED THUMB SIDE + +1D834 +SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED THUMB FORWARD + +1D835 +SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED CUPPED THUMB FORWARD + +1D836 +SIGNWRITING HAND-FIST MIDDLE THUMB CUPPED INDEX UP + +1D837 +SIGNWRITING HAND-FIST INDEX THUMB CUPPED MIDDLE UP + +1D838 +SIGNWRITING HAND-FIST MIDDLE THUMB CIRCLED INDEX UP + +1D839 +SIGNWRITING HAND-FIST MIDDLE THUMB CIRCLED INDEX HINGED + +1D83A +SIGNWRITING HAND-FIST INDEX THUMB ANGLED OUT MIDDLE UP + +1D83B +SIGNWRITING HAND-FIST INDEX THUMB ANGLED IN MIDDLE UP + +1D83C +SIGNWRITING HAND-FIST INDEX THUMB CIRCLED MIDDLE UP + +1D83D +SIGNWRITING HAND-FIST INDEX MIDDLE THUMB CONJOINED HINGED + +1D83E +SIGNWRITING HAND-FIST INDEX MIDDLE THUMB ANGLED OUT + +1D83F +SIGNWRITING HAND-FIST INDEX MIDDLE THUMB ANGLED + +1D840 +SIGNWRITING HAND-FIST MIDDLE THUMB ANGLED OUT INDEX UP + +1D841 +SIGNWRITING HAND-FIST MIDDLE THUMB ANGLED OUT INDEX CROSSED + +1D842 +SIGNWRITING HAND-FIST MIDDLE THUMB ANGLED INDEX UP + +1D843 +SIGNWRITING HAND-FIST INDEX THUMB HOOKED MIDDLE HINGED + +1D844 +SIGNWRITING HAND-FLAT FOUR FINGERS + +1D845 +SIGNWRITING HAND-FLAT FOUR FINGERS BENT + +1D846 +SIGNWRITING HAND-FLAT FOUR FINGERS HINGED + +1D847 +SIGNWRITING HAND-FLAT FOUR FINGERS CONJOINED + +1D848 +SIGNWRITING HAND-FLAT FOUR FINGERS CONJOINED SPLIT + +1D849 +SIGNWRITING HAND-CLAW FOUR FINGERS CONJOINED + +1D84A +SIGNWRITING HAND-FIST FOUR FINGERS CONJOINED BENT + +1D84B +SIGNWRITING HAND-HINGE FOUR FINGERS CONJOINED + +1D84C +SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD + +1D84D +SIGNWRITING HAND-FLAT HEEL FIVE FINGERS SPREAD + +1D84E +SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD FOUR BENT + +1D84F +SIGNWRITING HAND-FLAT HEEL FIVE FINGERS SPREAD FOUR BENT + +1D850 +SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD BENT + +1D851 +SIGNWRITING HAND-FLAT HEEL FIVE FINGERS SPREAD BENT + +1D852 +SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD THUMB FORWARD + +1D853 +SIGNWRITING HAND-CUP FIVE FINGERS SPREAD + +1D854 +SIGNWRITING HAND-CUP FIVE FINGERS SPREAD OPEN + +1D855 +SIGNWRITING HAND-HINGE FIVE FINGERS SPREAD OPEN + +1D856 +SIGNWRITING HAND-OVAL FIVE FINGERS SPREAD + +1D857 +SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD HINGED + +1D858 +SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD HINGED THUMB SIDE + +1D859 +SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD HINGED NO THUMB + +1D85A +SIGNWRITING HAND-FLAT + +1D85B +SIGNWRITING HAND-FLAT BETWEEN PALM FACINGS + +1D85C +SIGNWRITING HAND-FLAT HEEL + +1D85D +SIGNWRITING HAND-FLAT THUMB SIDE + +1D85E +SIGNWRITING HAND-FLAT HEEL THUMB SIDE + +1D85F +SIGNWRITING HAND-FLAT THUMB BENT + +1D860 +SIGNWRITING HAND-FLAT THUMB FORWARD + +1D861 +SIGNWRITING HAND-FLAT SPLIT INDEX THUMB SIDE + +1D862 +SIGNWRITING HAND-FLAT SPLIT CENTRE + +1D863 +SIGNWRITING HAND-FLAT SPLIT CENTRE THUMB SIDE + +1D864 +SIGNWRITING HAND-FLAT SPLIT CENTRE THUMB SIDE BENT + +1D865 +SIGNWRITING HAND-FLAT SPLIT LITTLE + +1D866 +SIGNWRITING HAND-CLAW + +1D867 +SIGNWRITING HAND-CLAW THUMB SIDE + +1D868 +SIGNWRITING HAND-CLAW NO THUMB + +1D869 +SIGNWRITING HAND-CLAW THUMB FORWARD + +1D86A +SIGNWRITING HAND-HOOK CURLICUE + +1D86B +SIGNWRITING HAND-HOOK + +1D86C +SIGNWRITING HAND-CUP OPEN + +1D86D +SIGNWRITING HAND-CUP + +1D86E +SIGNWRITING HAND-CUP OPEN THUMB SIDE + +1D86F +SIGNWRITING HAND-CUP THUMB SIDE + +1D870 +SIGNWRITING HAND-CUP OPEN NO THUMB + +1D871 +SIGNWRITING HAND-CUP NO THUMB + +1D872 +SIGNWRITING HAND-CUP OPEN THUMB FORWARD + +1D873 +SIGNWRITING HAND-CUP THUMB FORWARD + +1D874 +SIGNWRITING HAND-CURLICUE OPEN + +1D875 +SIGNWRITING HAND-CURLICUE + +1D876 +SIGNWRITING HAND-CIRCLE + +1D877 +SIGNWRITING HAND-OVAL + +1D878 +SIGNWRITING HAND-OVAL THUMB SIDE + +1D879 +SIGNWRITING HAND-OVAL NO THUMB + +1D87A +SIGNWRITING HAND-OVAL THUMB FORWARD + +1D87B +SIGNWRITING HAND-HINGE OPEN + +1D87C +SIGNWRITING HAND-HINGE OPEN THUMB FORWARD + +1D87D +SIGNWRITING HAND-HINGE + +1D87E +SIGNWRITING HAND-HINGE SMALL + +1D87F +SIGNWRITING HAND-HINGE OPEN THUMB SIDE + +1D880 +SIGNWRITING HAND-HINGE THUMB SIDE + +1D881 +SIGNWRITING HAND-HINGE OPEN NO THUMB + +1D882 +SIGNWRITING HAND-HINGE NO THUMB + +1D883 +SIGNWRITING HAND-HINGE THUMB SIDE TOUCHING INDEX + +1D884 +SIGNWRITING HAND-HINGE THUMB BETWEEN MIDDLE RING + +1D885 +SIGNWRITING HAND-ANGLE + +1D886 +SIGNWRITING HAND-FIST INDEX MIDDLE RING + +1D887 +SIGNWRITING HAND-CIRCLE INDEX MIDDLE RING + +1D888 +SIGNWRITING HAND-HINGE INDEX MIDDLE RING + +1D889 +SIGNWRITING HAND-ANGLE INDEX MIDDLE RING + +1D88A +SIGNWRITING HAND-HINGE LITTLE + +1D88B +SIGNWRITING HAND-FIST INDEX MIDDLE RING BENT + +1D88C +SIGNWRITING HAND-FIST INDEX MIDDLE RING CONJOINED + +1D88D +SIGNWRITING HAND-HINGE INDEX MIDDLE RING CONJOINED + +1D88E +SIGNWRITING HAND-FIST LITTLE DOWN + +1D88F +SIGNWRITING HAND-FIST LITTLE DOWN RIPPLE STRAIGHT + +1D890 +SIGNWRITING HAND-FIST LITTLE DOWN RIPPLE CURVED + +1D891 +SIGNWRITING HAND-FIST LITTLE DOWN OTHERS CIRCLED + +1D892 +SIGNWRITING HAND-FIST LITTLE UP + +1D893 +SIGNWRITING HAND-FIST THUMB UNDER LITTLE UP + +1D894 +SIGNWRITING HAND-CIRCLE LITTLE UP + +1D895 +SIGNWRITING HAND-OVAL LITTLE UP + +1D896 +SIGNWRITING HAND-ANGLE LITTLE UP + +1D897 +SIGNWRITING HAND-FIST LITTLE RAISED KNUCKLE + +1D898 +SIGNWRITING HAND-FIST LITTLE BENT + +1D899 +SIGNWRITING HAND-FIST LITTLE TOUCHES THUMB + +1D89A +SIGNWRITING HAND-FIST LITTLE THUMB + +1D89B +SIGNWRITING HAND-HINGE LITTLE THUMB + +1D89C +SIGNWRITING HAND-FIST LITTLE INDEX THUMB + +1D89D +SIGNWRITING HAND-HINGE LITTLE INDEX THUMB + +1D89E +SIGNWRITING HAND-ANGLE LITTLE INDEX THUMB INDEX THUMB OUT + +1D89F +SIGNWRITING HAND-ANGLE LITTLE INDEX THUMB INDEX THUMB + +1D8A0 +SIGNWRITING HAND-FIST LITTLE INDEX + +1D8A1 +SIGNWRITING HAND-CIRCLE LITTLE INDEX + +1D8A2 +SIGNWRITING HAND-HINGE LITTLE INDEX + +1D8A3 +SIGNWRITING HAND-ANGLE LITTLE INDEX + +1D8A4 +SIGNWRITING HAND-FIST INDEX MIDDLE LITTLE + +1D8A5 +SIGNWRITING HAND-CIRCLE INDEX MIDDLE LITTLE + +1D8A6 +SIGNWRITING HAND-HINGE INDEX MIDDLE LITTLE + +1D8A7 +SIGNWRITING HAND-HINGE RING + +1D8A8 +SIGNWRITING HAND-ANGLE INDEX MIDDLE LITTLE + +1D8A9 +SIGNWRITING HAND-FIST INDEX MIDDLE CROSS LITTLE + +1D8AA +SIGNWRITING HAND-CIRCLE INDEX MIDDLE CROSS LITTLE + +1D8AB +SIGNWRITING HAND-FIST RING DOWN + +1D8AC +SIGNWRITING HAND-HINGE RING DOWN INDEX THUMB HOOK MIDDLE + +1D8AD +SIGNWRITING HAND-ANGLE RING DOWN MIDDLE THUMB INDEX CROSS + +1D8AE +SIGNWRITING HAND-FIST RING UP + +1D8AF +SIGNWRITING HAND-FIST RING RAISED KNUCKLE + +1D8B0 +SIGNWRITING HAND-FIST RING LITTLE + +1D8B1 +SIGNWRITING HAND-CIRCLE RING LITTLE + +1D8B2 +SIGNWRITING HAND-OVAL RING LITTLE + +1D8B3 +SIGNWRITING HAND-ANGLE RING LITTLE + +1D8B4 +SIGNWRITING HAND-FIST RING MIDDLE + +1D8B5 +SIGNWRITING HAND-FIST RING MIDDLE CONJOINED + +1D8B6 +SIGNWRITING HAND-FIST RING MIDDLE RAISED KNUCKLES + +1D8B7 +SIGNWRITING HAND-FIST RING INDEX + +1D8B8 +SIGNWRITING HAND-FIST RING THUMB + +1D8B9 +SIGNWRITING HAND-HOOK RING THUMB + +1D8BA +SIGNWRITING HAND-FIST INDEX RING LITTLE + +1D8BB +SIGNWRITING HAND-CIRCLE INDEX RING LITTLE + +1D8BC +SIGNWRITING HAND-CURLICUE INDEX RING LITTLE ON + +1D8BD +SIGNWRITING HAND-HOOK INDEX RING LITTLE OUT + +1D8BE +SIGNWRITING HAND-HOOK INDEX RING LITTLE IN + +1D8BF +SIGNWRITING HAND-HOOK INDEX RING LITTLE UNDER + +1D8C0 +SIGNWRITING HAND-CUP INDEX RING LITTLE + +1D8C1 +SIGNWRITING HAND-HINGE INDEX RING LITTLE + +1D8C2 +SIGNWRITING HAND-ANGLE INDEX RING LITTLE OUT + +1D8C3 +SIGNWRITING HAND-ANGLE INDEX RING LITTLE + +1D8C4 +SIGNWRITING HAND-FIST MIDDLE DOWN + +1D8C5 +SIGNWRITING HAND-HINGE MIDDLE + +1D8C6 +SIGNWRITING HAND-FIST MIDDLE UP + +1D8C7 +SIGNWRITING HAND-CIRCLE MIDDLE UP + +1D8C8 +SIGNWRITING HAND-FIST MIDDLE RAISED KNUCKLE + +1D8C9 +SIGNWRITING HAND-FIST MIDDLE UP THUMB SIDE + +1D8CA +SIGNWRITING HAND-HOOK MIDDLE THUMB + +1D8CB +SIGNWRITING HAND-FIST MIDDLE THUMB LITTLE + +1D8CC +SIGNWRITING HAND-FIST MIDDLE LITTLE + +1D8CD +SIGNWRITING HAND-FIST MIDDLE RING LITTLE + +1D8CE +SIGNWRITING HAND-CIRCLE MIDDLE RING LITTLE + +1D8CF +SIGNWRITING HAND-CURLICUE MIDDLE RING LITTLE ON + +1D8D0 +SIGNWRITING HAND-CUP MIDDLE RING LITTLE + +1D8D1 +SIGNWRITING HAND-HINGE MIDDLE RING LITTLE + +1D8D2 +SIGNWRITING HAND-ANGLE MIDDLE RING LITTLE OUT + +1D8D3 +SIGNWRITING HAND-ANGLE MIDDLE RING LITTLE IN + +1D8D4 +SIGNWRITING HAND-ANGLE MIDDLE RING LITTLE + +1D8D5 +SIGNWRITING HAND-CIRCLE MIDDLE RING LITTLE BENT + +1D8D6 +SIGNWRITING HAND-CLAW MIDDLE RING LITTLE CONJOINED + +1D8D7 +SIGNWRITING HAND-CLAW MIDDLE RING LITTLE CONJOINED SIDE + +1D8D8 +SIGNWRITING HAND-HOOK MIDDLE RING LITTLE CONJOINED OUT + +1D8D9 +SIGNWRITING HAND-HOOK MIDDLE RING LITTLE CONJOINED IN + +1D8DA +SIGNWRITING HAND-HOOK MIDDLE RING LITTLE CONJOINED + +1D8DB +SIGNWRITING HAND-HINGE INDEX HINGED + +1D8DC +SIGNWRITING HAND-FIST INDEX THUMB SIDE + +1D8DD +SIGNWRITING HAND-HINGE INDEX THUMB SIDE + +1D8DE +SIGNWRITING HAND-FIST INDEX THUMB SIDE THUMB DIAGONAL + +1D8DF +SIGNWRITING HAND-FIST INDEX THUMB SIDE THUMB CONJOINED + +1D8E0 +SIGNWRITING HAND-FIST INDEX THUMB SIDE THUMB BENT + +1D8E1 +SIGNWRITING HAND-FIST INDEX THUMB SIDE INDEX BENT + +1D8E2 +SIGNWRITING HAND-FIST INDEX THUMB SIDE BOTH BENT + +1D8E3 +SIGNWRITING HAND-FIST INDEX THUMB SIDE INDEX HINGE + +1D8E4 +SIGNWRITING HAND-FIST INDEX THUMB FORWARD INDEX STRAIGHT + +1D8E5 +SIGNWRITING HAND-FIST INDEX THUMB FORWARD INDEX BENT + +1D8E6 +SIGNWRITING HAND-FIST INDEX THUMB HOOK + +1D8E7 +SIGNWRITING HAND-FIST INDEX THUMB CURLICUE + +1D8E8 +SIGNWRITING HAND-FIST INDEX THUMB CURVE THUMB INSIDE + +1D8E9 +SIGNWRITING HAND-CLAW INDEX THUMB CURVE THUMB INSIDE + +1D8EA +SIGNWRITING HAND-FIST INDEX THUMB CURVE THUMB UNDER + +1D8EB +SIGNWRITING HAND-FIST INDEX THUMB CIRCLE + +1D8EC +SIGNWRITING HAND-CUP INDEX THUMB + +1D8ED +SIGNWRITING HAND-CUP INDEX THUMB OPEN + +1D8EE +SIGNWRITING HAND-HINGE INDEX THUMB OPEN + +1D8EF +SIGNWRITING HAND-HINGE INDEX THUMB LARGE + +1D8F0 +SIGNWRITING HAND-HINGE INDEX THUMB + +1D8F1 +SIGNWRITING HAND-HINGE INDEX THUMB SMALL + +1D8F2 +SIGNWRITING HAND-ANGLE INDEX THUMB OUT + +1D8F3 +SIGNWRITING HAND-ANGLE INDEX THUMB IN + +1D8F4 +SIGNWRITING HAND-ANGLE INDEX THUMB + +1D8F5 +SIGNWRITING HAND-FIST THUMB + +1D8F6 +SIGNWRITING HAND-FIST THUMB HEEL + +1D8F7 +SIGNWRITING HAND-FIST THUMB SIDE DIAGONAL + +1D8F8 +SIGNWRITING HAND-FIST THUMB SIDE CONJOINED + +1D8F9 +SIGNWRITING HAND-FIST THUMB SIDE BENT + +1D8FA +SIGNWRITING HAND-FIST THUMB FORWARD + +1D8FB +SIGNWRITING HAND-FIST THUMB BETWEEN INDEX MIDDLE + +1D8FC +SIGNWRITING HAND-FIST THUMB BETWEEN MIDDLE RING + +1D8FD +SIGNWRITING HAND-FIST THUMB BETWEEN RING LITTLE + +1D8FE +SIGNWRITING HAND-FIST THUMB UNDER TWO FINGERS + +1D8FF +SIGNWRITING HAND-FIST THUMB OVER TWO FINGERS + +1D900 +SIGNWRITING HAND-FIST THUMB UNDER THREE FINGERS + +1D901 +SIGNWRITING HAND-FIST THUMB UNDER FOUR FINGERS + +1D902 +SIGNWRITING HAND-FIST THUMB OVER FOUR RAISED KNUCKLES + +1D903 +SIGNWRITING HAND-FIST + +1D904 +SIGNWRITING HAND-FIST HEEL + +1D905 +SIGNWRITING TOUCH SINGLE + +1D906 +SIGNWRITING TOUCH MULTIPLE + +1D907 +SIGNWRITING TOUCH BETWEEN + +1D908 +SIGNWRITING GRASP SINGLE + +1D909 +SIGNWRITING GRASP MULTIPLE + +1D90A +SIGNWRITING GRASP BETWEEN + +1D90B +SIGNWRITING STRIKE SINGLE + +1D90C +SIGNWRITING STRIKE MULTIPLE + +1D90D +SIGNWRITING STRIKE BETWEEN + +1D90E +SIGNWRITING BRUSH SINGLE + +1D90F +SIGNWRITING BRUSH MULTIPLE + +1D910 +SIGNWRITING BRUSH BETWEEN + +1D911 +SIGNWRITING RUB SINGLE + +1D912 +SIGNWRITING RUB MULTIPLE + +1D913 +SIGNWRITING RUB BETWEEN + +1D914 +SIGNWRITING SURFACE SYMBOLS + +1D915 +SIGNWRITING SURFACE BETWEEN + +1D916 +SIGNWRITING SQUEEZE LARGE SINGLE + +1D917 +SIGNWRITING SQUEEZE SMALL SINGLE + +1D918 +SIGNWRITING SQUEEZE LARGE MULTIPLE + +1D919 +SIGNWRITING SQUEEZE SMALL MULTIPLE + +1D91A +SIGNWRITING SQUEEZE SEQUENTIAL + +1D91B +SIGNWRITING FLICK LARGE SINGLE + +1D91C +SIGNWRITING FLICK SMALL SINGLE + +1D91D +SIGNWRITING FLICK LARGE MULTIPLE + +1D91E +SIGNWRITING FLICK SMALL MULTIPLE + +1D91F +SIGNWRITING FLICK SEQUENTIAL + +1D920 +SIGNWRITING SQUEEZE FLICK ALTERNATING + +1D921 +SIGNWRITING MOVEMENT-HINGE UP DOWN LARGE + +1D922 +SIGNWRITING MOVEMENT-HINGE UP DOWN SMALL + +1D923 +SIGNWRITING MOVEMENT-HINGE UP SEQUENTIAL + +1D924 +SIGNWRITING MOVEMENT-HINGE DOWN SEQUENTIAL + +1D925 +SIGNWRITING MOVEMENT-HINGE UP DOWN ALTERNATING LARGE + +1D926 +SIGNWRITING MOVEMENT-HINGE UP DOWN ALTERNATING SMALL + +1D927 +SIGNWRITING MOVEMENT-HINGE SIDE TO SIDE SCISSORS + +1D928 +SIGNWRITING MOVEMENT-WALLPLANE FINGER CONTACT + +1D929 +SIGNWRITING MOVEMENT-FLOORPLANE FINGER CONTACT + +1D92A +SIGNWRITING MOVEMENT-WALLPLANE SINGLE STRAIGHT SMALL + +1D92B +SIGNWRITING MOVEMENT-WALLPLANE SINGLE STRAIGHT MEDIUM + +1D92C +SIGNWRITING MOVEMENT-WALLPLANE SINGLE STRAIGHT LARGE + +1D92D +SIGNWRITING MOVEMENT-WALLPLANE SINGLE STRAIGHT LARGEST + +1D92E +SIGNWRITING MOVEMENT-WALLPLANE SINGLE WRIST FLEX + +1D92F +SIGNWRITING MOVEMENT-WALLPLANE DOUBLE STRAIGHT + +1D930 +SIGNWRITING MOVEMENT-WALLPLANE DOUBLE WRIST FLEX + +1D931 +SIGNWRITING MOVEMENT-WALLPLANE DOUBLE ALTERNATING + +1D932 +SIGNWRITING MOVEMENT-WALLPLANE DOUBLE ALTERNATING WRIST FLEX + +1D933 +SIGNWRITING MOVEMENT-WALLPLANE CROSS + +1D934 +SIGNWRITING MOVEMENT-WALLPLANE TRIPLE STRAIGHT MOVEMENT + +1D935 +SIGNWRITING MOVEMENT-WALLPLANE TRIPLE WRIST FLEX + +1D936 +SIGNWRITING MOVEMENT-WALLPLANE TRIPLE ALTERNATING + +1D937 +SIGNWRITING MOVEMENT-WALLPLANE TRIPLE ALTERNATING WRIST FLEX + +1D938 +SIGNWRITING MOVEMENT-WALLPLANE BEND SMALL + +1D939 +SIGNWRITING MOVEMENT-WALLPLANE BEND MEDIUM + +1D93A +SIGNWRITING MOVEMENT-WALLPLANE BEND LARGE + +1D93B +SIGNWRITING MOVEMENT-WALLPLANE CORNER SMALL + +1D93C +SIGNWRITING MOVEMENT-WALLPLANE CORNER MEDIUM + +1D93D +SIGNWRITING MOVEMENT-WALLPLANE CORNER LARGE + +1D93E +SIGNWRITING MOVEMENT-WALLPLANE CORNER ROTATION + +1D93F +SIGNWRITING MOVEMENT-WALLPLANE CHECK SMALL + +1D940 +SIGNWRITING MOVEMENT-WALLPLANE CHECK MEDIUM + +1D941 +SIGNWRITING MOVEMENT-WALLPLANE CHECK LARGE + +1D942 +SIGNWRITING MOVEMENT-WALLPLANE BOX SMALL + +1D943 +SIGNWRITING MOVEMENT-WALLPLANE BOX MEDIUM + +1D944 +SIGNWRITING MOVEMENT-WALLPLANE BOX LARGE + +1D945 +SIGNWRITING MOVEMENT-WALLPLANE ZIGZAG SMALL + +1D946 +SIGNWRITING MOVEMENT-WALLPLANE ZIGZAG MEDIUM + +1D947 +SIGNWRITING MOVEMENT-WALLPLANE ZIGZAG LARGE + +1D948 +SIGNWRITING MOVEMENT-WALLPLANE PEAKS SMALL + +1D949 +SIGNWRITING MOVEMENT-WALLPLANE PEAKS MEDIUM + +1D94A +SIGNWRITING MOVEMENT-WALLPLANE PEAKS LARGE + +1D94B +SIGNWRITING TRAVEL-WALLPLANE ROTATION-WALLPLANE SINGLE + +1D94C +SIGNWRITING TRAVEL-WALLPLANE ROTATION-WALLPLANE DOUBLE + +1D94D +SIGNWRITING TRAVEL-WALLPLANE ROTATION-WALLPLANE ALTERNATING + +1D94E +SIGNWRITING TRAVEL-WALLPLANE ROTATION-FLOORPLANE SINGLE + +1D94F +SIGNWRITING TRAVEL-WALLPLANE ROTATION-FLOORPLANE DOUBLE + +1D950 +SIGNWRITING TRAVEL-WALLPLANE ROTATION-FLOORPLANE ALTERNATING + +1D951 +SIGNWRITING TRAVEL-WALLPLANE SHAKING + +1D952 +SIGNWRITING TRAVEL-WALLPLANE ARM SPIRAL SINGLE + +1D953 +SIGNWRITING TRAVEL-WALLPLANE ARM SPIRAL DOUBLE + +1D954 +SIGNWRITING TRAVEL-WALLPLANE ARM SPIRAL TRIPLE + +1D955 +SIGNWRITING MOVEMENT-DIAGONAL AWAY SMALL + +1D956 +SIGNWRITING MOVEMENT-DIAGONAL AWAY MEDIUM + +1D957 +SIGNWRITING MOVEMENT-DIAGONAL AWAY LARGE + +1D958 +SIGNWRITING MOVEMENT-DIAGONAL AWAY LARGEST + +1D959 +SIGNWRITING MOVEMENT-DIAGONAL TOWARDS SMALL + +1D95A +SIGNWRITING MOVEMENT-DIAGONAL TOWARDS MEDIUM + +1D95B +SIGNWRITING MOVEMENT-DIAGONAL TOWARDS LARGE + +1D95C +SIGNWRITING MOVEMENT-DIAGONAL TOWARDS LARGEST + +1D95D +SIGNWRITING MOVEMENT-DIAGONAL BETWEEN AWAY SMALL + +1D95E +SIGNWRITING MOVEMENT-DIAGONAL BETWEEN AWAY MEDIUM + +1D95F +SIGNWRITING MOVEMENT-DIAGONAL BETWEEN AWAY LARGE + +1D960 +SIGNWRITING MOVEMENT-DIAGONAL BETWEEN AWAY LARGEST + +1D961 +SIGNWRITING MOVEMENT-DIAGONAL BETWEEN TOWARDS SMALL + +1D962 +SIGNWRITING MOVEMENT-DIAGONAL BETWEEN TOWARDS MEDIUM + +1D963 +SIGNWRITING MOVEMENT-DIAGONAL BETWEEN TOWARDS LARGE + +1D964 +SIGNWRITING MOVEMENT-DIAGONAL BETWEEN TOWARDS LARGEST + +1D965 +SIGNWRITING MOVEMENT-FLOORPLANE SINGLE STRAIGHT SMALL + +1D966 +SIGNWRITING MOVEMENT-FLOORPLANE SINGLE STRAIGHT MEDIUM + +1D967 +SIGNWRITING MOVEMENT-FLOORPLANE SINGLE STRAIGHT LARGE + +1D968 +SIGNWRITING MOVEMENT-FLOORPLANE SINGLE STRAIGHT LARGEST + +1D969 +SIGNWRITING MOVEMENT-FLOORPLANE SINGLE WRIST FLEX + +1D96A +SIGNWRITING MOVEMENT-FLOORPLANE DOUBLE STRAIGHT + +1D96B +SIGNWRITING MOVEMENT-FLOORPLANE DOUBLE WRIST FLEX + +1D96C +SIGNWRITING MOVEMENT-FLOORPLANE DOUBLE ALTERNATING + +1D96D +SIGNWRITING MOVEMENT-FLOORPLANE DOUBLE ALTERNATING WRIST FLEX + +1D96E +SIGNWRITING MOVEMENT-FLOORPLANE CROSS + +1D96F +SIGNWRITING MOVEMENT-FLOORPLANE TRIPLE STRAIGHT MOVEMENT + +1D970 +SIGNWRITING MOVEMENT-FLOORPLANE TRIPLE WRIST FLEX + +1D971 +SIGNWRITING MOVEMENT-FLOORPLANE TRIPLE ALTERNATING MOVEMENT + +1D972 +SIGNWRITING MOVEMENT-FLOORPLANE TRIPLE ALTERNATING WRIST FLEX + +1D973 +SIGNWRITING MOVEMENT-FLOORPLANE BEND + +1D974 +SIGNWRITING MOVEMENT-FLOORPLANE CORNER SMALL + +1D975 +SIGNWRITING MOVEMENT-FLOORPLANE CORNER MEDIUM + +1D976 +SIGNWRITING MOVEMENT-FLOORPLANE CORNER LARGE + +1D977 +SIGNWRITING MOVEMENT-FLOORPLANE CHECK + +1D978 +SIGNWRITING MOVEMENT-FLOORPLANE BOX SMALL + +1D979 +SIGNWRITING MOVEMENT-FLOORPLANE BOX MEDIUM + +1D97A +SIGNWRITING MOVEMENT-FLOORPLANE BOX LARGE + +1D97B +SIGNWRITING MOVEMENT-FLOORPLANE ZIGZAG SMALL + +1D97C +SIGNWRITING MOVEMENT-FLOORPLANE ZIGZAG MEDIUM + +1D97D +SIGNWRITING MOVEMENT-FLOORPLANE ZIGZAG LARGE + +1D97E +SIGNWRITING MOVEMENT-FLOORPLANE PEAKS SMALL + +1D97F +SIGNWRITING MOVEMENT-FLOORPLANE PEAKS MEDIUM + +1D980 +SIGNWRITING MOVEMENT-FLOORPLANE PEAKS LARGE + +1D981 +SIGNWRITING TRAVEL-FLOORPLANE ROTATION-FLOORPLANE SINGLE + +1D982 +SIGNWRITING TRAVEL-FLOORPLANE ROTATION-FLOORPLANE DOUBLE + +1D983 +SIGNWRITING TRAVEL-FLOORPLANE ROTATION-FLOORPLANE ALTERNATING + +1D984 +SIGNWRITING TRAVEL-FLOORPLANE ROTATION-WALLPLANE SINGLE + +1D985 +SIGNWRITING TRAVEL-FLOORPLANE ROTATION-WALLPLANE DOUBLE + +1D986 +SIGNWRITING TRAVEL-FLOORPLANE ROTATION-WALLPLANE ALTERNATING + +1D987 +SIGNWRITING TRAVEL-FLOORPLANE SHAKING + +1D988 +SIGNWRITING MOVEMENT-WALLPLANE CURVE QUARTER SMALL + +1D989 +SIGNWRITING MOVEMENT-WALLPLANE CURVE QUARTER MEDIUM + +1D98A +SIGNWRITING MOVEMENT-WALLPLANE CURVE QUARTER LARGE + +1D98B +SIGNWRITING MOVEMENT-WALLPLANE CURVE QUARTER LARGEST + +1D98C +SIGNWRITING MOVEMENT-WALLPLANE CURVE HALF-CIRCLE SMALL + +1D98D +SIGNWRITING MOVEMENT-WALLPLANE CURVE HALF-CIRCLE MEDIUM + +1D98E +SIGNWRITING MOVEMENT-WALLPLANE CURVE HALF-CIRCLE LARGE + +1D98F +SIGNWRITING MOVEMENT-WALLPLANE CURVE HALF-CIRCLE LARGEST + +1D990 +SIGNWRITING MOVEMENT-WALLPLANE CURVE THREE-QUARTER CIRCLE SMALL + +1D991 +SIGNWRITING MOVEMENT-WALLPLANE CURVE THREE-QUARTER CIRCLE MEDIUM + +1D992 +SIGNWRITING MOVEMENT-WALLPLANE HUMP SMALL + +1D993 +SIGNWRITING MOVEMENT-WALLPLANE HUMP MEDIUM + +1D994 +SIGNWRITING MOVEMENT-WALLPLANE HUMP LARGE + +1D995 +SIGNWRITING MOVEMENT-WALLPLANE LOOP SMALL + +1D996 +SIGNWRITING MOVEMENT-WALLPLANE LOOP MEDIUM + +1D997 +SIGNWRITING MOVEMENT-WALLPLANE LOOP LARGE + +1D998 +SIGNWRITING MOVEMENT-WALLPLANE LOOP SMALL DOUBLE + +1D999 +SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE DOUBLE SMALL + +1D99A +SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE DOUBLE MEDIUM + +1D99B +SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE DOUBLE LARGE + +1D99C +SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE TRIPLE SMALL + +1D99D +SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE TRIPLE MEDIUM + +1D99E +SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE TRIPLE LARGE + +1D99F +SIGNWRITING MOVEMENT-WALLPLANE CURVE THEN STRAIGHT + +1D9A0 +SIGNWRITING MOVEMENT-WALLPLANE CURVED CROSS SMALL + +1D9A1 +SIGNWRITING MOVEMENT-WALLPLANE CURVED CROSS MEDIUM + +1D9A2 +SIGNWRITING ROTATION-WALLPLANE SINGLE + +1D9A3 +SIGNWRITING ROTATION-WALLPLANE DOUBLE + +1D9A4 +SIGNWRITING ROTATION-WALLPLANE ALTERNATE + +1D9A5 +SIGNWRITING MOVEMENT-WALLPLANE SHAKING + +1D9A6 +SIGNWRITING MOVEMENT-WALLPLANE CURVE HITTING FRONT WALL + +1D9A7 +SIGNWRITING MOVEMENT-WALLPLANE HUMP HITTING FRONT WALL + +1D9A8 +SIGNWRITING MOVEMENT-WALLPLANE LOOP HITTING FRONT WALL + +1D9A9 +SIGNWRITING MOVEMENT-WALLPLANE WAVE HITTING FRONT WALL + +1D9AA +SIGNWRITING ROTATION-WALLPLANE SINGLE HITTING FRONT WALL + +1D9AB +SIGNWRITING ROTATION-WALLPLANE DOUBLE HITTING FRONT WALL + +1D9AC +SIGNWRITING ROTATION-WALLPLANE ALTERNATING HITTING FRONT WALL + +1D9AD +SIGNWRITING MOVEMENT-WALLPLANE CURVE HITTING CHEST + +1D9AE +SIGNWRITING MOVEMENT-WALLPLANE HUMP HITTING CHEST + +1D9AF +SIGNWRITING MOVEMENT-WALLPLANE LOOP HITTING CHEST + +1D9B0 +SIGNWRITING MOVEMENT-WALLPLANE WAVE HITTING CHEST + +1D9B1 +SIGNWRITING ROTATION-WALLPLANE SINGLE HITTING CHEST + +1D9B2 +SIGNWRITING ROTATION-WALLPLANE DOUBLE HITTING CHEST + +1D9B3 +SIGNWRITING ROTATION-WALLPLANE ALTERNATING HITTING CHEST + +1D9B4 +SIGNWRITING MOVEMENT-WALLPLANE WAVE DIAGONAL PATH SMALL + +1D9B5 +SIGNWRITING MOVEMENT-WALLPLANE WAVE DIAGONAL PATH MEDIUM + +1D9B6 +SIGNWRITING MOVEMENT-WALLPLANE WAVE DIAGONAL PATH LARGE + +1D9B7 +SIGNWRITING MOVEMENT-FLOORPLANE CURVE HITTING CEILING SMALL + +1D9B8 +SIGNWRITING MOVEMENT-FLOORPLANE CURVE HITTING CEILING LARGE + +1D9B9 +SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING CEILING SMALL DOUBLE + +1D9BA +SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING CEILING LARGE DOUBLE + +1D9BB +SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING CEILING SMALL TRIPLE + +1D9BC +SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING CEILING LARGE TRIPLE + +1D9BD +SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING CEILING SMALL SINGLE + +1D9BE +SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING CEILING LARGE SINGLE + +1D9BF +SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING CEILING SMALL DOUBLE + +1D9C0 +SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING CEILING LARGE DOUBLE + +1D9C1 +SIGNWRITING MOVEMENT-FLOORPLANE WAVE HITTING CEILING SMALL + +1D9C2 +SIGNWRITING MOVEMENT-FLOORPLANE WAVE HITTING CEILING LARGE + +1D9C3 +SIGNWRITING ROTATION-FLOORPLANE SINGLE HITTING CEILING + +1D9C4 +SIGNWRITING ROTATION-FLOORPLANE DOUBLE HITTING CEILING + +1D9C5 +SIGNWRITING ROTATION-FLOORPLANE ALTERNATING HITTING CEILING + +1D9C6 +SIGNWRITING MOVEMENT-FLOORPLANE CURVE HITTING FLOOR SMALL + +1D9C7 +SIGNWRITING MOVEMENT-FLOORPLANE CURVE HITTING FLOOR LARGE + +1D9C8 +SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING FLOOR SMALL DOUBLE + +1D9C9 +SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING FLOOR LARGE DOUBLE + +1D9CA +SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING FLOOR TRIPLE SMALL TRIPLE + +1D9CB +SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING FLOOR TRIPLE LARGE TRIPLE + +1D9CC +SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING FLOOR SMALL SINGLE + +1D9CD +SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING FLOOR LARGE SINGLE + +1D9CE +SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING FLOOR SMALL DOUBLE + +1D9CF +SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING FLOOR LARGE DOUBLE + +1D9D0 +SIGNWRITING MOVEMENT-FLOORPLANE WAVE HITTING FLOOR SMALL + +1D9D1 +SIGNWRITING MOVEMENT-FLOORPLANE WAVE HITTING FLOOR LARGE + +1D9D2 +SIGNWRITING ROTATION-FLOORPLANE SINGLE HITTING FLOOR + +1D9D3 +SIGNWRITING ROTATION-FLOORPLANE DOUBLE HITTING FLOOR + +1D9D4 +SIGNWRITING ROTATION-FLOORPLANE ALTERNATING HITTING FLOOR + +1D9D5 +SIGNWRITING MOVEMENT-FLOORPLANE CURVE SMALL + +1D9D6 +SIGNWRITING MOVEMENT-FLOORPLANE CURVE MEDIUM + +1D9D7 +SIGNWRITING MOVEMENT-FLOORPLANE CURVE LARGE + +1D9D8 +SIGNWRITING MOVEMENT-FLOORPLANE CURVE LARGEST + +1D9D9 +SIGNWRITING MOVEMENT-FLOORPLANE CURVE COMBINED + +1D9DA +SIGNWRITING MOVEMENT-FLOORPLANE HUMP SMALL + +1D9DB +SIGNWRITING MOVEMENT-FLOORPLANE LOOP SMALL + +1D9DC +SIGNWRITING MOVEMENT-FLOORPLANE WAVE SNAKE + +1D9DD +SIGNWRITING MOVEMENT-FLOORPLANE WAVE SMALL + +1D9DE +SIGNWRITING MOVEMENT-FLOORPLANE WAVE LARGE + +1D9DF +SIGNWRITING ROTATION-FLOORPLANE SINGLE + +1D9E0 +SIGNWRITING ROTATION-FLOORPLANE DOUBLE + +1D9E1 +SIGNWRITING ROTATION-FLOORPLANE ALTERNATING + +1D9E2 +SIGNWRITING MOVEMENT-FLOORPLANE SHAKING PARALLEL + +1D9E3 +SIGNWRITING MOVEMENT-WALLPLANE ARM CIRCLE SMALL SINGLE + +1D9E4 +SIGNWRITING MOVEMENT-WALLPLANE ARM CIRCLE MEDIUM SINGLE + +1D9E5 +SIGNWRITING MOVEMENT-WALLPLANE ARM CIRCLE SMALL DOUBLE + +1D9E6 +SIGNWRITING MOVEMENT-WALLPLANE ARM CIRCLE MEDIUM DOUBLE + +1D9E7 +SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL SMALL SINGLE + +1D9E8 +SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL MEDIUM SINGLE + +1D9E9 +SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL LARGE SINGLE + +1D9EA +SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL SMALL DOUBLE + +1D9EB +SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL MEDIUM DOUBLE + +1D9EC +SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL LARGE DOUBLE + +1D9ED +SIGNWRITING MOVEMENT-WALLPLANE WRIST CIRCLE FRONT SINGLE + +1D9EE +SIGNWRITING MOVEMENT-WALLPLANE WRIST CIRCLE FRONT DOUBLE + +1D9EF +SIGNWRITING MOVEMENT-FLOORPLANE WRIST CIRCLE HITTING WALL SINGLE + +1D9F0 +SIGNWRITING MOVEMENT-FLOORPLANE WRIST CIRCLE HITTING WALL DOUBLE + +1D9F1 +SIGNWRITING MOVEMENT-WALLPLANE FINGER CIRCLES SINGLE + +1D9F2 +SIGNWRITING MOVEMENT-WALLPLANE FINGER CIRCLES DOUBLE + +1D9F3 +SIGNWRITING MOVEMENT-FLOORPLANE FINGER CIRCLES HITTING WALL SINGLE + +1D9F4 +SIGNWRITING MOVEMENT-FLOORPLANE FINGER CIRCLES HITTING WALL DOUBLE + +1D9F5 +SIGNWRITING DYNAMIC ARROWHEAD SMALL + +1D9F6 +SIGNWRITING DYNAMIC ARROWHEAD LARGE + +1D9F7 +SIGNWRITING DYNAMIC FAST + +1D9F8 +SIGNWRITING DYNAMIC SLOW + +1D9F9 +SIGNWRITING DYNAMIC TENSE + +1D9FA +SIGNWRITING DYNAMIC RELAXED + +1D9FB +SIGNWRITING DYNAMIC SIMULTANEOUS + +1D9FC +SIGNWRITING DYNAMIC SIMULTANEOUS ALTERNATING + +1D9FD +SIGNWRITING DYNAMIC EVERY OTHER TIME + +1D9FE +SIGNWRITING DYNAMIC GRADUAL + +1D9FF +SIGNWRITING HEAD + +1DA00 +SIGNWRITING HEAD RIM + +1DA01 +SIGNWRITING HEAD MOVEMENT-WALLPLANE STRAIGHT + +1DA02 +SIGNWRITING HEAD MOVEMENT-WALLPLANE TILT + +1DA03 +SIGNWRITING HEAD MOVEMENT-FLOORPLANE STRAIGHT + +1DA04 +SIGNWRITING HEAD MOVEMENT-WALLPLANE CURVE + +1DA05 +SIGNWRITING HEAD MOVEMENT-FLOORPLANE CURVE + +1DA06 +SIGNWRITING HEAD MOVEMENT CIRCLE + +1DA07 +SIGNWRITING FACE DIRECTION POSITION NOSE FORWARD TILTING + +1DA08 +SIGNWRITING FACE DIRECTION POSITION NOSE UP OR DOWN + +1DA09 +SIGNWRITING FACE DIRECTION POSITION NOSE UP OR DOWN TILTING + +1DA0A +SIGNWRITING EYEBROWS STRAIGHT UP + +1DA0B +SIGNWRITING EYEBROWS STRAIGHT NEUTRAL + +1DA0C +SIGNWRITING EYEBROWS STRAIGHT DOWN + +1DA0D +SIGNWRITING DREAMY EYEBROWS NEUTRAL DOWN + +1DA0E +SIGNWRITING DREAMY EYEBROWS DOWN NEUTRAL + +1DA0F +SIGNWRITING DREAMY EYEBROWS UP NEUTRAL + +1DA10 +SIGNWRITING DREAMY EYEBROWS NEUTRAL UP + +1DA11 +SIGNWRITING FOREHEAD NEUTRAL + +1DA12 +SIGNWRITING FOREHEAD CONTACT + +1DA13 +SIGNWRITING FOREHEAD WRINKLED + +1DA14 +SIGNWRITING EYES OPEN + +1DA15 +SIGNWRITING EYES SQUEEZED + +1DA16 +SIGNWRITING EYES CLOSED + +1DA17 +SIGNWRITING EYE BLINK SINGLE + +1DA18 +SIGNWRITING EYE BLINK MULTIPLE + +1DA19 +SIGNWRITING EYES HALF OPEN + +1DA1A +SIGNWRITING EYES WIDE OPEN + +1DA1B +SIGNWRITING EYES HALF CLOSED + +1DA1C +SIGNWRITING EYES WIDENING MOVEMENT + +1DA1D +SIGNWRITING EYE WINK + +1DA1E +SIGNWRITING EYELASHES UP + +1DA1F +SIGNWRITING EYELASHES DOWN + +1DA20 +SIGNWRITING EYELASHES FLUTTERING + +1DA21 +SIGNWRITING EYEGAZE-WALLPLANE STRAIGHT + +1DA22 +SIGNWRITING EYEGAZE-WALLPLANE STRAIGHT DOUBLE + +1DA23 +SIGNWRITING EYEGAZE-WALLPLANE STRAIGHT ALTERNATING + +1DA24 +SIGNWRITING EYEGAZE-FLOORPLANE STRAIGHT + +1DA25 +SIGNWRITING EYEGAZE-FLOORPLANE STRAIGHT DOUBLE + +1DA26 +SIGNWRITING EYEGAZE-FLOORPLANE STRAIGHT ALTERNATING + +1DA27 +SIGNWRITING EYEGAZE-WALLPLANE CURVED + +1DA28 +SIGNWRITING EYEGAZE-FLOORPLANE CURVED + +1DA29 +SIGNWRITING EYEGAZE-WALLPLANE CIRCLING + +1DA2A +SIGNWRITING CHEEKS PUFFED + +1DA2B +SIGNWRITING CHEEKS NEUTRAL + +1DA2C +SIGNWRITING CHEEKS SUCKED + +1DA2D +SIGNWRITING TENSE CHEEKS HIGH + +1DA2E +SIGNWRITING TENSE CHEEKS MIDDLE + +1DA2F +SIGNWRITING TENSE CHEEKS LOW + +1DA30 +SIGNWRITING EARS + +1DA31 +SIGNWRITING NOSE NEUTRAL + +1DA32 +SIGNWRITING NOSE CONTACT + +1DA33 +SIGNWRITING NOSE WRINKLES + +1DA34 +SIGNWRITING NOSE WIGGLES + +1DA35 +SIGNWRITING AIR BLOWING OUT + +1DA36 +SIGNWRITING AIR SUCKING IN + +1DA37 +SIGNWRITING AIR BLOW SMALL ROTATIONS + +1DA38 +SIGNWRITING AIR SUCK SMALL ROTATIONS + +1DA39 +SIGNWRITING BREATH INHALE + +1DA3A +SIGNWRITING BREATH EXHALE + +1DA3B +SIGNWRITING MOUTH CLOSED NEUTRAL + +1DA3C +SIGNWRITING MOUTH CLOSED FORWARD + +1DA3D +SIGNWRITING MOUTH CLOSED CONTACT + +1DA3E +SIGNWRITING MOUTH SMILE + +1DA3F +SIGNWRITING MOUTH SMILE WRINKLED + +1DA40 +SIGNWRITING MOUTH SMILE OPEN + +1DA41 +SIGNWRITING MOUTH FROWN + +1DA42 +SIGNWRITING MOUTH FROWN WRINKLED + +1DA43 +SIGNWRITING MOUTH FROWN OPEN + +1DA44 +SIGNWRITING MOUTH OPEN CIRCLE + +1DA45 +SIGNWRITING MOUTH OPEN FORWARD + +1DA46 +SIGNWRITING MOUTH OPEN WRINKLED + +1DA47 +SIGNWRITING MOUTH OPEN OVAL + +1DA48 +SIGNWRITING MOUTH OPEN OVAL WRINKLED + +1DA49 +SIGNWRITING MOUTH OPEN OVAL YAWN + +1DA4A +SIGNWRITING MOUTH OPEN RECTANGLE + +1DA4B +SIGNWRITING MOUTH OPEN RECTANGLE WRINKLED + +1DA4C +SIGNWRITING MOUTH OPEN RECTANGLE YAWN + +1DA4D +SIGNWRITING MOUTH KISS + +1DA4E +SIGNWRITING MOUTH KISS FORWARD + +1DA4F +SIGNWRITING MOUTH KISS WRINKLED + +1DA50 +SIGNWRITING MOUTH TENSE + +1DA51 +SIGNWRITING MOUTH TENSE FORWARD + +1DA52 +SIGNWRITING MOUTH TENSE SUCKED + +1DA53 +SIGNWRITING LIPS PRESSED TOGETHER + +1DA54 +SIGNWRITING LIP LOWER OVER UPPER + +1DA55 +SIGNWRITING LIP UPPER OVER LOWER + +1DA56 +SIGNWRITING MOUTH CORNERS + +1DA57 +SIGNWRITING MOUTH WRINKLES SINGLE + +1DA58 +SIGNWRITING MOUTH WRINKLES DOUBLE + +1DA59 +SIGNWRITING TONGUE STICKING OUT FAR + +1DA5A +SIGNWRITING TONGUE LICKING LIPS + +1DA5B +SIGNWRITING TONGUE TIP BETWEEN LIPS + +1DA5C +SIGNWRITING TONGUE TIP TOUCHING INSIDE MOUTH + +1DA5D +SIGNWRITING TONGUE INSIDE MOUTH RELAXED + +1DA5E +SIGNWRITING TONGUE MOVES AGAINST CHEEK + +1DA5F +SIGNWRITING TONGUE CENTRE STICKING OUT + +1DA60 +SIGNWRITING TONGUE CENTRE INSIDE MOUTH + +1DA61 +SIGNWRITING TEETH + +1DA62 +SIGNWRITING TEETH MOVEMENT + +1DA63 +SIGNWRITING TEETH ON TONGUE + +1DA64 +SIGNWRITING TEETH ON TONGUE MOVEMENT + +1DA65 +SIGNWRITING TEETH ON LIPS + +1DA66 +SIGNWRITING TEETH ON LIPS MOVEMENT + +1DA67 +SIGNWRITING TEETH BITE LIPS + +1DA68 +SIGNWRITING MOVEMENT-WALLPLANE JAW + +1DA69 +SIGNWRITING MOVEMENT-FLOORPLANE JAW + +1DA6A +SIGNWRITING NECK + +1DA6B +SIGNWRITING HAIR + +1DA6C +SIGNWRITING EXCITEMENT + +1DA6D +SIGNWRITING SHOULDER HIP SPINE + +1DA6E +SIGNWRITING SHOULDER HIP POSITIONS + +1DA6F +SIGNWRITING WALLPLANE SHOULDER HIP MOVE + +1DA70 +SIGNWRITING FLOORPLANE SHOULDER HIP MOVE + +1DA71 +SIGNWRITING SHOULDER TILTING FROM WAIST + +1DA72 +SIGNWRITING TORSO-WALLPLANE STRAIGHT STRETCH + +1DA73 +SIGNWRITING TORSO-WALLPLANE CURVED BEND + +1DA74 +SIGNWRITING TORSO-FLOORPLANE TWISTING + +1DA75 +SIGNWRITING UPPER BODY TILTING FROM HIP JOINTS + +1DA76 +SIGNWRITING LIMB COMBINATION + +1DA77 +SIGNWRITING LIMB LENGTH-1 + +1DA78 +SIGNWRITING LIMB LENGTH-2 + +1DA79 +SIGNWRITING LIMB LENGTH-3 + +1DA7A +SIGNWRITING LIMB LENGTH-4 + +1DA7B +SIGNWRITING LIMB LENGTH-5 + +1DA7C +SIGNWRITING LIMB LENGTH-6 + +1DA7D +SIGNWRITING LIMB LENGTH-7 + +1DA7E +SIGNWRITING FINGER + +1DA7F +SIGNWRITING LOCATION-WALLPLANE SPACE + +1DA80 +SIGNWRITING LOCATION-FLOORPLANE SPACE + +1DA81 +SIGNWRITING LOCATION HEIGHT + +1DA82 +SIGNWRITING LOCATION WIDTH + +1DA83 +SIGNWRITING LOCATION DEPTH + +1DA84 +SIGNWRITING LOCATION HEAD NECK + +1DA85 +SIGNWRITING LOCATION TORSO + +1DA86 +SIGNWRITING LOCATION LIMBS DIGITS + +1DA87 +SIGNWRITING COMMA + +1DA88 +SIGNWRITING FULL STOP + +1DA89 +SIGNWRITING SEMICOLON + +1DA8A +SIGNWRITING COLON + +1DA8B +SIGNWRITING PARENTHESIS + +1DA9B +SIGNWRITING FILL MODIFIER-2 + +1DA9C +SIGNWRITING FILL MODIFIER-3 + +1DA9D +SIGNWRITING FILL MODIFIER-4 + +1DA9E +SIGNWRITING FILL MODIFIER-5 + +1DA9F +SIGNWRITING FILL MODIFIER-6 + +1DAA1 +SIGNWRITING ROTATION MODIFIER-2 + +1DAA2 +SIGNWRITING ROTATION MODIFIER-3 + +1DAA3 +SIGNWRITING ROTATION MODIFIER-4 + +1DAA4 +SIGNWRITING ROTATION MODIFIER-5 + +1DAA5 +SIGNWRITING ROTATION MODIFIER-6 + +1DAA6 +SIGNWRITING ROTATION MODIFIER-7 + +1DAA7 +SIGNWRITING ROTATION MODIFIER-8 + +1DAA8 +SIGNWRITING ROTATION MODIFIER-9 + +1DAA9 +SIGNWRITING ROTATION MODIFIER-10 + +1DAAA +SIGNWRITING ROTATION MODIFIER-11 + +1DAAB +SIGNWRITING ROTATION MODIFIER-12 + +1DAAC +SIGNWRITING ROTATION MODIFIER-13 + +1DAAD +SIGNWRITING ROTATION MODIFIER-14 + +1DAAE +SIGNWRITING ROTATION MODIFIER-15 + +1DAAF +SIGNWRITING ROTATION MODIFIER-16 + +1DF00 +LATIN SMALL LETTER FENG DIGRAPH WITH TRILL + +1DF01 +LATIN SMALL LETTER REVERSED SCRIPT G + +1DF02 +LATIN LETTER SMALL CAPITAL TURNED G + +1DF03 +LATIN SMALL LETTER REVERSED K + +1DF04 +LATIN LETTER SMALL CAPITAL L WITH BELT + +1DF05 +LATIN SMALL LETTER LEZH WITH RETROFLEX HOOK + +1DF06 +LATIN SMALL LETTER TURNED Y WITH BELT + +1DF07 +LATIN SMALL LETTER REVERSED ENG + +1DF08 +LATIN SMALL LETTER TURNED R WITH LONG LEG AND RETROFLEX HOOK + +1DF09 +LATIN SMALL LETTER T WITH HOOK AND RETROFLEX HOOK + +1DF0A +LATIN LETTER RETROFLEX CLICK WITH RETROFLEX HOOK + +1DF0B +LATIN SMALL LETTER ESH WITH DOUBLE BAR + +1DF0C +LATIN SMALL LETTER ESH WITH DOUBLE BAR AND CURL + +1DF0D +LATIN SMALL LETTER TURNED T WITH CURL + +1DF0E +LATIN LETTER INVERTED GLOTTAL STOP WITH CURL + +1DF0F +LATIN LETTER STRETCHED C WITH CURL + +1DF10 +LATIN LETTER SMALL CAPITAL TURNED K + +1DF11 +LATIN SMALL LETTER L WITH FISHHOOK + +1DF12 +LATIN SMALL LETTER DEZH DIGRAPH WITH PALATAL HOOK + +1DF13 +LATIN SMALL LETTER L WITH BELT AND PALATAL HOOK + +1DF14 +LATIN SMALL LETTER ENG WITH PALATAL HOOK + +1DF15 +LATIN SMALL LETTER TURNED R WITH PALATAL HOOK + +1DF16 +LATIN SMALL LETTER R WITH FISHHOOK AND PALATAL HOOK + +1DF17 +LATIN SMALL LETTER TESH DIGRAPH WITH PALATAL HOOK + +1DF18 +LATIN SMALL LETTER EZH WITH PALATAL HOOK + +1DF19 +LATIN SMALL LETTER DEZH DIGRAPH WITH RETROFLEX HOOK + +1DF1A +LATIN SMALL LETTER I WITH STROKE AND RETROFLEX HOOK + +1DF1B +LATIN SMALL LETTER O WITH RETROFLEX HOOK + +1DF1C +LATIN SMALL LETTER TESH DIGRAPH WITH RETROFLEX HOOK + +1DF1D +LATIN SMALL LETTER C WITH RETROFLEX HOOK + +1DF1E +LATIN SMALL LETTER S WITH CURL + +1DF25 +LATIN SMALL LETTER D WITH MID-HEIGHT LEFT HOOK + +1DF26 +LATIN SMALL LETTER L WITH MID-HEIGHT LEFT HOOK + +1DF27 +LATIN SMALL LETTER N WITH MID-HEIGHT LEFT HOOK + +1DF28 +LATIN SMALL LETTER R WITH MID-HEIGHT LEFT HOOK + +1DF29 +LATIN SMALL LETTER S WITH MID-HEIGHT LEFT HOOK + +1DF2A +LATIN SMALL LETTER T WITH MID-HEIGHT LEFT HOOK + +1E000 +COMBINING GLAGOLITIC LETTER AZU + +1E001 +COMBINING GLAGOLITIC LETTER BUKY + +1E002 +COMBINING GLAGOLITIC LETTER VEDE + +1E003 +COMBINING GLAGOLITIC LETTER GLAGOLI + +1E004 +COMBINING GLAGOLITIC LETTER DOBRO + +1E005 +COMBINING GLAGOLITIC LETTER YESTU + +1E006 +COMBINING GLAGOLITIC LETTER ZHIVETE + +1E008 +COMBINING GLAGOLITIC LETTER ZEMLJA + +1E009 +COMBINING GLAGOLITIC LETTER IZHE + +1E00A +COMBINING GLAGOLITIC LETTER INITIAL IZHE + +1E00B +COMBINING GLAGOLITIC LETTER I + +1E00C +COMBINING GLAGOLITIC LETTER DJERVI + +1E00D +COMBINING GLAGOLITIC LETTER KAKO + +1E00E +COMBINING GLAGOLITIC LETTER LJUDIJE + +1E00F +COMBINING GLAGOLITIC LETTER MYSLITE + +1E010 +COMBINING GLAGOLITIC LETTER NASHI + +1E011 +COMBINING GLAGOLITIC LETTER ONU + +1E012 +COMBINING GLAGOLITIC LETTER POKOJI + +1E013 +COMBINING GLAGOLITIC LETTER RITSI + +1E014 +COMBINING GLAGOLITIC LETTER SLOVO + +1E015 +COMBINING GLAGOLITIC LETTER TVRIDO + +1E016 +COMBINING GLAGOLITIC LETTER UKU + +1E017 +COMBINING GLAGOLITIC LETTER FRITU + +1E018 +COMBINING GLAGOLITIC LETTER HERU + +1E01B +COMBINING GLAGOLITIC LETTER SHTA + +1E01C +COMBINING GLAGOLITIC LETTER TSI + +1E01D +COMBINING GLAGOLITIC LETTER CHRIVI + +1E01E +COMBINING GLAGOLITIC LETTER SHA + +1E01F +COMBINING GLAGOLITIC LETTER YERU + +1E020 +COMBINING GLAGOLITIC LETTER YERI + +1E021 +COMBINING GLAGOLITIC LETTER YATI + +1E023 +COMBINING GLAGOLITIC LETTER YU + +1E024 +COMBINING GLAGOLITIC LETTER SMALL YUS + +1E026 +COMBINING GLAGOLITIC LETTER YO + +1E027 +COMBINING GLAGOLITIC LETTER IOTATED SMALL YUS + +1E028 +COMBINING GLAGOLITIC LETTER BIG YUS + +1E029 +COMBINING GLAGOLITIC LETTER IOTATED BIG YUS + +1E02A +COMBINING GLAGOLITIC LETTER FITA + +1E030 +MODIFIER LETTER CYRILLIC SMALL A + +1E031 +MODIFIER LETTER CYRILLIC SMALL BE + +1E032 +MODIFIER LETTER CYRILLIC SMALL VE + +1E033 +MODIFIER LETTER CYRILLIC SMALL GHE + +1E034 +MODIFIER LETTER CYRILLIC SMALL DE + +1E035 +MODIFIER LETTER CYRILLIC SMALL IE + +1E036 +MODIFIER LETTER CYRILLIC SMALL ZHE + +1E037 +MODIFIER LETTER CYRILLIC SMALL ZE + +1E038 +MODIFIER LETTER CYRILLIC SMALL I + +1E039 +MODIFIER LETTER CYRILLIC SMALL KA + +1E03A +MODIFIER LETTER CYRILLIC SMALL EL + +1E03B +MODIFIER LETTER CYRILLIC SMALL EM + +1E03C +MODIFIER LETTER CYRILLIC SMALL O + +1E03D +MODIFIER LETTER CYRILLIC SMALL PE + +1E03E +MODIFIER LETTER CYRILLIC SMALL ER + +1E03F +MODIFIER LETTER CYRILLIC SMALL ES + +1E040 +MODIFIER LETTER CYRILLIC SMALL TE + +1E041 +MODIFIER LETTER CYRILLIC SMALL U + +1E042 +MODIFIER LETTER CYRILLIC SMALL EF + +1E043 +MODIFIER LETTER CYRILLIC SMALL HA + +1E044 +MODIFIER LETTER CYRILLIC SMALL TSE + +1E045 +MODIFIER LETTER CYRILLIC SMALL CHE + +1E046 +MODIFIER LETTER CYRILLIC SMALL SHA + +1E047 +MODIFIER LETTER CYRILLIC SMALL YERU + +1E048 +MODIFIER LETTER CYRILLIC SMALL E + +1E049 +MODIFIER LETTER CYRILLIC SMALL YU + +1E04A +MODIFIER LETTER CYRILLIC SMALL DZZE + +1E04B +MODIFIER LETTER CYRILLIC SMALL SCHWA + +1E04C +MODIFIER LETTER CYRILLIC SMALL BYELORUSSIAN-UKRAINIAN I + +1E04D +MODIFIER LETTER CYRILLIC SMALL JE + +1E04E +MODIFIER LETTER CYRILLIC SMALL BARRED O + +1E04F +MODIFIER LETTER CYRILLIC SMALL STRAIGHT U + +1E050 +MODIFIER LETTER CYRILLIC SMALL PALOCHKA + +1E051 +CYRILLIC SUBSCRIPT SMALL LETTER A + +1E052 +CYRILLIC SUBSCRIPT SMALL LETTER BE + +1E053 +CYRILLIC SUBSCRIPT SMALL LETTER VE + +1E054 +CYRILLIC SUBSCRIPT SMALL LETTER GHE + +1E055 +CYRILLIC SUBSCRIPT SMALL LETTER DE + +1E056 +CYRILLIC SUBSCRIPT SMALL LETTER IE + +1E057 +CYRILLIC SUBSCRIPT SMALL LETTER ZHE + +1E058 +CYRILLIC SUBSCRIPT SMALL LETTER ZE + +1E059 +CYRILLIC SUBSCRIPT SMALL LETTER I + +1E05A +CYRILLIC SUBSCRIPT SMALL LETTER KA + +1E05B +CYRILLIC SUBSCRIPT SMALL LETTER EL + +1E05C +CYRILLIC SUBSCRIPT SMALL LETTER O + +1E05D +CYRILLIC SUBSCRIPT SMALL LETTER PE + +1E05E +CYRILLIC SUBSCRIPT SMALL LETTER ES + +1E05F +CYRILLIC SUBSCRIPT SMALL LETTER U + +1E060 +CYRILLIC SUBSCRIPT SMALL LETTER EF + +1E061 +CYRILLIC SUBSCRIPT SMALL LETTER HA + +1E062 +CYRILLIC SUBSCRIPT SMALL LETTER TSE + +1E063 +CYRILLIC SUBSCRIPT SMALL LETTER CHE + +1E064 +CYRILLIC SUBSCRIPT SMALL LETTER SHA + +1E065 +CYRILLIC SUBSCRIPT SMALL LETTER HARD SIGN + +1E066 +CYRILLIC SUBSCRIPT SMALL LETTER YERU + +1E067 +CYRILLIC SUBSCRIPT SMALL LETTER GHE WITH UPTURN + +1E068 +CYRILLIC SUBSCRIPT SMALL LETTER BYELORUSSIAN-UKRAINIAN I + +1E069 +CYRILLIC SUBSCRIPT SMALL LETTER DZE + +1E06A +CYRILLIC SUBSCRIPT SMALL LETTER DZHE + +1E06B +MODIFIER LETTER CYRILLIC SMALL ES WITH DESCENDER + +1E06C +MODIFIER LETTER CYRILLIC SMALL YERU WITH BACK YER + +1E06D +MODIFIER LETTER CYRILLIC SMALL STRAIGHT U WITH STROKE + +1E08F +COMBINING CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I + +1E100 +NYIAKENG PUACHUE HMONG LETTER MA + +1E101 +NYIAKENG PUACHUE HMONG LETTER TSA + +1E102 +NYIAKENG PUACHUE HMONG LETTER NTA + +1E103 +NYIAKENG PUACHUE HMONG LETTER TA + +1E104 +NYIAKENG PUACHUE HMONG LETTER HA + +1E105 +NYIAKENG PUACHUE HMONG LETTER NA + +1E106 +NYIAKENG PUACHUE HMONG LETTER XA + +1E107 +NYIAKENG PUACHUE HMONG LETTER NKA + +1E108 +NYIAKENG PUACHUE HMONG LETTER CA + +1E109 +NYIAKENG PUACHUE HMONG LETTER LA + +1E10A +NYIAKENG PUACHUE HMONG LETTER SA + +1E10B +NYIAKENG PUACHUE HMONG LETTER ZA + +1E10C +NYIAKENG PUACHUE HMONG LETTER NCA + +1E10D +NYIAKENG PUACHUE HMONG LETTER NTSA + +1E10E +NYIAKENG PUACHUE HMONG LETTER KA + +1E10F +NYIAKENG PUACHUE HMONG LETTER DA + +1E110 +NYIAKENG PUACHUE HMONG LETTER NYA + +1E111 +NYIAKENG PUACHUE HMONG LETTER NRA + +1E112 +NYIAKENG PUACHUE HMONG LETTER VA + +1E113 +NYIAKENG PUACHUE HMONG LETTER NTXA + +1E114 +NYIAKENG PUACHUE HMONG LETTER TXA + +1E115 +NYIAKENG PUACHUE HMONG LETTER FA + +1E116 +NYIAKENG PUACHUE HMONG LETTER RA + +1E117 +NYIAKENG PUACHUE HMONG LETTER QA + +1E118 +NYIAKENG PUACHUE HMONG LETTER YA + +1E119 +NYIAKENG PUACHUE HMONG LETTER NQA + +1E11A +NYIAKENG PUACHUE HMONG LETTER PA + +1E11B +NYIAKENG PUACHUE HMONG LETTER XYA + +1E11C +NYIAKENG PUACHUE HMONG LETTER NPA + +1E11D +NYIAKENG PUACHUE HMONG LETTER DLA + +1E11E +NYIAKENG PUACHUE HMONG LETTER NPLA + +1E11F +NYIAKENG PUACHUE HMONG LETTER HAH + +1E120 +NYIAKENG PUACHUE HMONG LETTER MLA + +1E121 +NYIAKENG PUACHUE HMONG LETTER PLA + +1E122 +NYIAKENG PUACHUE HMONG LETTER GA + +1E123 +NYIAKENG PUACHUE HMONG LETTER RRA + +1E124 +NYIAKENG PUACHUE HMONG LETTER A + +1E125 +NYIAKENG PUACHUE HMONG LETTER AA + +1E126 +NYIAKENG PUACHUE HMONG LETTER I + +1E127 +NYIAKENG PUACHUE HMONG LETTER U + +1E128 +NYIAKENG PUACHUE HMONG LETTER O + +1E129 +NYIAKENG PUACHUE HMONG LETTER OO + +1E12A +NYIAKENG PUACHUE HMONG LETTER E + +1E12B +NYIAKENG PUACHUE HMONG LETTER EE + +1E12C +NYIAKENG PUACHUE HMONG LETTER W + +1E130 +NYIAKENG PUACHUE HMONG TONE-B + +1E131 +NYIAKENG PUACHUE HMONG TONE-M + +1E132 +NYIAKENG PUACHUE HMONG TONE-J + +1E133 +NYIAKENG PUACHUE HMONG TONE-V + +1E134 +NYIAKENG PUACHUE HMONG TONE-S + +1E135 +NYIAKENG PUACHUE HMONG TONE-G + +1E136 +NYIAKENG PUACHUE HMONG TONE-D + +1E137 +NYIAKENG PUACHUE HMONG SIGN FOR PERSON + +1E138 +NYIAKENG PUACHUE HMONG SIGN FOR THING + +1E139 +NYIAKENG PUACHUE HMONG SIGN FOR LOCATION + +1E13A +NYIAKENG PUACHUE HMONG SIGN FOR ANIMAL + +1E13B +NYIAKENG PUACHUE HMONG SIGN FOR INVERTEBRATE + +1E13C +NYIAKENG PUACHUE HMONG SIGN XW XW + +1E13D +NYIAKENG PUACHUE HMONG SYLLABLE LENGTHENER + +1E140 +NYIAKENG PUACHUE HMONG DIGIT ZERO + +1E141 +NYIAKENG PUACHUE HMONG DIGIT ONE + +1E142 +NYIAKENG PUACHUE HMONG DIGIT TWO + +1E143 +NYIAKENG PUACHUE HMONG DIGIT THREE + +1E144 +NYIAKENG PUACHUE HMONG DIGIT FOUR + +1E145 +NYIAKENG PUACHUE HMONG DIGIT FIVE + +1E146 +NYIAKENG PUACHUE HMONG DIGIT SIX + +1E147 +NYIAKENG PUACHUE HMONG DIGIT SEVEN + +1E148 +NYIAKENG PUACHUE HMONG DIGIT EIGHT + +1E149 +NYIAKENG PUACHUE HMONG DIGIT NINE + +1E14E +NYIAKENG PUACHUE HMONG LOGOGRAM NYAJ + +1E14F +NYIAKENG PUACHUE HMONG CIRCLED CA + +1E290 +TOTO LETTER PA + +1E291 +TOTO LETTER BA + +1E292 +TOTO LETTER TA + +1E293 +TOTO LETTER DA + +1E294 +TOTO LETTER KA + +1E295 +TOTO LETTER GA + +1E296 +TOTO LETTER MA + +1E297 +TOTO LETTER NA + +1E298 +TOTO LETTER NGA + +1E299 +TOTO LETTER SA + +1E29A +TOTO LETTER CHA + +1E29B +TOTO LETTER YA + +1E29C +TOTO LETTER WA + +1E29D +TOTO LETTER JA + +1E29E +TOTO LETTER HA + +1E29F +TOTO LETTER RA + +1E2A0 +TOTO LETTER LA + +1E2A1 +TOTO LETTER I + +1E2A2 +TOTO LETTER BREATHY I + +1E2A3 +TOTO LETTER IU + +1E2A4 +TOTO LETTER BREATHY IU + +1E2A5 +TOTO LETTER U + +1E2A6 +TOTO LETTER E + +1E2A7 +TOTO LETTER BREATHY E + +1E2A8 +TOTO LETTER EO + +1E2A9 +TOTO LETTER BREATHY EO + +1E2AA +TOTO LETTER O + +1E2AB +TOTO LETTER AE + +1E2AC +TOTO LETTER BREATHY AE + +1E2AD +TOTO LETTER A + +1E2AE +TOTO SIGN RISING TONE + +1E2C0 +WANCHO LETTER AA + +1E2C1 +WANCHO LETTER A + +1E2C2 +WANCHO LETTER BA + +1E2C3 +WANCHO LETTER CA + +1E2C4 +WANCHO LETTER DA + +1E2C5 +WANCHO LETTER GA + +1E2C6 +WANCHO LETTER YA + +1E2C7 +WANCHO LETTER PHA + +1E2C8 +WANCHO LETTER LA + +1E2C9 +WANCHO LETTER NA + +1E2CA +WANCHO LETTER PA + +1E2CB +WANCHO LETTER TA + +1E2CC +WANCHO LETTER THA + +1E2CD +WANCHO LETTER FA + +1E2CE +WANCHO LETTER SA + +1E2CF +WANCHO LETTER SHA + +1E2D0 +WANCHO LETTER JA + +1E2D1 +WANCHO LETTER ZA + +1E2D2 +WANCHO LETTER WA + +1E2D3 +WANCHO LETTER VA + +1E2D4 +WANCHO LETTER KA + +1E2D5 +WANCHO LETTER O + +1E2D6 +WANCHO LETTER AU + +1E2D7 +WANCHO LETTER RA + +1E2D8 +WANCHO LETTER MA + +1E2D9 +WANCHO LETTER KHA + +1E2DA +WANCHO LETTER HA + +1E2DB +WANCHO LETTER E + +1E2DC +WANCHO LETTER I + +1E2DD +WANCHO LETTER NGA + +1E2DE +WANCHO LETTER U + +1E2DF +WANCHO LETTER LLHA + +1E2E0 +WANCHO LETTER TSA + +1E2E1 +WANCHO LETTER TRA + +1E2E2 +WANCHO LETTER ONG + +1E2E3 +WANCHO LETTER AANG + +1E2E4 +WANCHO LETTER ANG + +1E2E5 +WANCHO LETTER ING + +1E2E6 +WANCHO LETTER ON + +1E2E7 +WANCHO LETTER EN + +1E2E8 +WANCHO LETTER AAN + +1E2E9 +WANCHO LETTER NYA + +1E2EA +WANCHO LETTER UEN + +1E2EB +WANCHO LETTER YIH + +1E2EC +WANCHO TONE TUP + +1E2ED +WANCHO TONE TUPNI + +1E2EE +WANCHO TONE KOI + +1E2EF +WANCHO TONE KOINI + +1E2F0 +WANCHO DIGIT ZERO + +1E2F1 +WANCHO DIGIT ONE + +1E2F2 +WANCHO DIGIT TWO + +1E2F3 +WANCHO DIGIT THREE + +1E2F4 +WANCHO DIGIT FOUR + +1E2F5 +WANCHO DIGIT FIVE + +1E2F6 +WANCHO DIGIT SIX + +1E2F7 +WANCHO DIGIT SEVEN + +1E2F8 +WANCHO DIGIT EIGHT + +1E2F9 +WANCHO DIGIT NINE + +1E2FF +WANCHO NGUN SIGN + +1E4D0 +NAG MUNDARI LETTER O + +1E4D1 +NAG MUNDARI LETTER OP + +1E4D2 +NAG MUNDARI LETTER OL + +1E4D3 +NAG MUNDARI LETTER OY + +1E4D4 +NAG MUNDARI LETTER ONG + +1E4D5 +NAG MUNDARI LETTER A + +1E4D6 +NAG MUNDARI LETTER AJ + +1E4D7 +NAG MUNDARI LETTER AB + +1E4D8 +NAG MUNDARI LETTER ANY + +1E4D9 +NAG MUNDARI LETTER AH + +1E4DA +NAG MUNDARI LETTER I + +1E4DB +NAG MUNDARI LETTER IS + +1E4DC +NAG MUNDARI LETTER IDD + +1E4DD +NAG MUNDARI LETTER IT + +1E4DE +NAG MUNDARI LETTER IH + +1E4DF +NAG MUNDARI LETTER U + +1E4E0 +NAG MUNDARI LETTER UC + +1E4E1 +NAG MUNDARI LETTER UD + +1E4E2 +NAG MUNDARI LETTER UK + +1E4E3 +NAG MUNDARI LETTER UR + +1E4E4 +NAG MUNDARI LETTER E + +1E4E5 +NAG MUNDARI LETTER ENN + +1E4E6 +NAG MUNDARI LETTER EG + +1E4E7 +NAG MUNDARI LETTER EM + +1E4E8 +NAG MUNDARI LETTER EN + +1E4E9 +NAG MUNDARI LETTER ETT + +1E4EA +NAG MUNDARI LETTER ELL + +1E4EB +NAG MUNDARI SIGN OJOD + +1E4EC +NAG MUNDARI SIGN MUHOR + +1E4ED +NAG MUNDARI SIGN TOYOR + +1E4EE +NAG MUNDARI SIGN IKIR + +1E4EF +NAG MUNDARI SIGN SUTUH + +1E4F0 +NAG MUNDARI DIGIT ZERO + +1E4F1 +NAG MUNDARI DIGIT ONE + +1E4F2 +NAG MUNDARI DIGIT TWO + +1E4F3 +NAG MUNDARI DIGIT THREE + +1E4F4 +NAG MUNDARI DIGIT FOUR + +1E4F5 +NAG MUNDARI DIGIT FIVE + +1E4F6 +NAG MUNDARI DIGIT SIX + +1E4F7 +NAG MUNDARI DIGIT SEVEN + +1E4F8 +NAG MUNDARI DIGIT EIGHT + +1E4F9 +NAG MUNDARI DIGIT NINE + +1E5D0 +OL ONAL LETTER O + +1E5D1 +OL ONAL LETTER OM + +1E5D2 +OL ONAL LETTER ONG + +1E5D3 +OL ONAL LETTER ORR + +1E5D4 +OL ONAL LETTER OO + +1E5D5 +OL ONAL LETTER OY + +1E5D6 +OL ONAL LETTER A + +1E5D7 +OL ONAL LETTER AD + +1E5D8 +OL ONAL LETTER AB + +1E5D9 +OL ONAL LETTER AH + +1E5DA +OL ONAL LETTER AL + +1E5DB +OL ONAL LETTER AW + +1E5DC +OL ONAL LETTER I + +1E5DD +OL ONAL LETTER IT + +1E5DE +OL ONAL LETTER IP + +1E5DF +OL ONAL LETTER ITT + +1E5E0 +OL ONAL LETTER ID + +1E5E1 +OL ONAL LETTER IN + +1E5E2 +OL ONAL LETTER U + +1E5E3 +OL ONAL LETTER UK + +1E5E4 +OL ONAL LETTER UDD + +1E5E5 +OL ONAL LETTER UJ + +1E5E6 +OL ONAL LETTER UNY + +1E5E7 +OL ONAL LETTER UR + +1E5E8 +OL ONAL LETTER E + +1E5E9 +OL ONAL LETTER ES + +1E5EA +OL ONAL LETTER EH + +1E5EB +OL ONAL LETTER EC + +1E5EC +OL ONAL LETTER ENN + +1E5ED +OL ONAL LETTER EG + +1E5EE +OL ONAL SIGN MU + +1E5EF +OL ONAL SIGN IKIR + +1E5F0 +OL ONAL SIGN HODDOND + +1E5F1 +OL ONAL DIGIT ZERO + +1E5F2 +OL ONAL DIGIT ONE + +1E5F3 +OL ONAL DIGIT TWO + +1E5F4 +OL ONAL DIGIT THREE + +1E5F5 +OL ONAL DIGIT FOUR + +1E5F6 +OL ONAL DIGIT FIVE + +1E5F7 +OL ONAL DIGIT SIX + +1E5F8 +OL ONAL DIGIT SEVEN + +1E5F9 +OL ONAL DIGIT EIGHT + +1E5FA +OL ONAL DIGIT NINE + +1E5FF +OL ONAL ABBREVIATION SIGN + +1E6C0 +TAI YO LETTER LOW KO + +1E6C1 +TAI YO LETTER HIGH KO + +1E6C2 +TAI YO LETTER LOW KHO + +1E6C3 +TAI YO LETTER HIGH KHO + +1E6C4 +TAI YO LETTER GO + +1E6C5 +TAI YO LETTER NGO + +1E6C6 +TAI YO LETTER CO + +1E6C7 +TAI YO LETTER LOW XO + +1E6C8 +TAI YO LETTER HIGH XO + +1E6C9 +TAI YO LETTER LOW NYO + +1E6CA +TAI YO LETTER HIGH NYO + +1E6CB +TAI YO LETTER DO + +1E6CC +TAI YO LETTER LOW TO + +1E6CD +TAI YO LETTER HIGH TO + +1E6CE +TAI YO LETTER THO + +1E6CF +TAI YO LETTER NO + +1E6D0 +TAI YO LETTER BO + +1E6D1 +TAI YO LETTER LOW PO + +1E6D2 +TAI YO LETTER HIGH PO + +1E6D3 +TAI YO LETTER PHO + +1E6D4 +TAI YO LETTER LOW FO + +1E6D5 +TAI YO LETTER HIGH FO + +1E6D6 +TAI YO LETTER MO + +1E6D7 +TAI YO LETTER YO + +1E6D8 +TAI YO LETTER LO + +1E6D9 +TAI YO LETTER VO + +1E6DA +TAI YO LETTER LOW HO + +1E6DB +TAI YO LETTER HIGH HO + +1E6DC +TAI YO LETTER QO + +1E6DD +TAI YO LETTER LOW KVO + +1E6DE +TAI YO LETTER HIGH KVO + +1E6E0 +TAI YO LETTER AA + +1E6E1 +TAI YO LETTER I + +1E6E2 +TAI YO LETTER UE + +1E6E3 +TAI YO SIGN UE + +1E6E4 +TAI YO LETTER U + +1E6E5 +TAI YO LETTER AE + +1E6E6 +TAI YO SIGN AU + +1E6E7 +TAI YO LETTER O + +1E6E8 +TAI YO LETTER E + +1E6E9 +TAI YO LETTER IA + +1E6EA +TAI YO LETTER UEA + +1E6EB +TAI YO LETTER UA + +1E6EC +TAI YO LETTER OO + +1E6ED +TAI YO LETTER AUE + +1E6EE +TAI YO SIGN AY + +1E6EF +TAI YO SIGN ANG + +1E6F0 +TAI YO LETTER AN + +1E6F1 +TAI YO LETTER AM + +1E6F2 +TAI YO LETTER AK + +1E6F3 +TAI YO LETTER AT + +1E6F4 +TAI YO LETTER AP + +1E6F5 +TAI YO SIGN OM + +1E6FE +TAI YO SYMBOL MUEANG + +1E6FF +TAI YO XAM LAI + +1E7E0 +ETHIOPIC SYLLABLE HHYA + +1E7E1 +ETHIOPIC SYLLABLE HHYU + +1E7E2 +ETHIOPIC SYLLABLE HHYI + +1E7E3 +ETHIOPIC SYLLABLE HHYAA + +1E7E4 +ETHIOPIC SYLLABLE HHYEE + +1E7E5 +ETHIOPIC SYLLABLE HHYE + +1E7E6 +ETHIOPIC SYLLABLE HHYO + +1E7E8 +ETHIOPIC SYLLABLE GURAGE HHWA + +1E7E9 +ETHIOPIC SYLLABLE HHWI + +1E7EA +ETHIOPIC SYLLABLE HHWEE + +1E7EB +ETHIOPIC SYLLABLE HHWE + +1E7ED +ETHIOPIC SYLLABLE GURAGE MWI + +1E7EE +ETHIOPIC SYLLABLE GURAGE MWEE + +1E7F0 +ETHIOPIC SYLLABLE GURAGE QWI + +1E7F1 +ETHIOPIC SYLLABLE GURAGE QWEE + +1E7F2 +ETHIOPIC SYLLABLE GURAGE QWE + +1E7F3 +ETHIOPIC SYLLABLE GURAGE BWI + +1E7F4 +ETHIOPIC SYLLABLE GURAGE BWEE + +1E7F5 +ETHIOPIC SYLLABLE GURAGE KWI + +1E7F6 +ETHIOPIC SYLLABLE GURAGE KWEE + +1E7F7 +ETHIOPIC SYLLABLE GURAGE KWE + +1E7F8 +ETHIOPIC SYLLABLE GURAGE GWI + +1E7F9 +ETHIOPIC SYLLABLE GURAGE GWEE + +1E7FA +ETHIOPIC SYLLABLE GURAGE GWE + +1E7FB +ETHIOPIC SYLLABLE GURAGE FWI + +1E7FC +ETHIOPIC SYLLABLE GURAGE FWEE + +1E7FD +ETHIOPIC SYLLABLE GURAGE PWI + +1E7FE +ETHIOPIC SYLLABLE GURAGE PWEE + +1E800 +MENDE KIKAKUI SYLLABLE M001 KI + +1E801 +MENDE KIKAKUI SYLLABLE M002 KA + +1E802 +MENDE KIKAKUI SYLLABLE M003 KU + +1E803 +MENDE KIKAKUI SYLLABLE M065 KEE + +1E804 +MENDE KIKAKUI SYLLABLE M095 KE + +1E805 +MENDE KIKAKUI SYLLABLE M076 KOO + +1E806 +MENDE KIKAKUI SYLLABLE M048 KO + +1E807 +MENDE KIKAKUI SYLLABLE M179 KUA + +1E808 +MENDE KIKAKUI SYLLABLE M004 WI + +1E809 +MENDE KIKAKUI SYLLABLE M005 WA + +1E80A +MENDE KIKAKUI SYLLABLE M006 WU + +1E80B +MENDE KIKAKUI SYLLABLE M126 WEE + +1E80C +MENDE KIKAKUI SYLLABLE M118 WE + +1E80D +MENDE KIKAKUI SYLLABLE M114 WOO + +1E80E +MENDE KIKAKUI SYLLABLE M045 WO + +1E80F +MENDE KIKAKUI SYLLABLE M194 WUI + +1E810 +MENDE KIKAKUI SYLLABLE M143 WEI + +1E811 +MENDE KIKAKUI SYLLABLE M061 WVI + +1E812 +MENDE KIKAKUI SYLLABLE M049 WVA + +1E813 +MENDE KIKAKUI SYLLABLE M139 WVE + +1E814 +MENDE KIKAKUI SYLLABLE M007 MIN + +1E815 +MENDE KIKAKUI SYLLABLE M008 MAN + +1E816 +MENDE KIKAKUI SYLLABLE M009 MUN + +1E817 +MENDE KIKAKUI SYLLABLE M059 MEN + +1E818 +MENDE KIKAKUI SYLLABLE M094 MON + +1E819 +MENDE KIKAKUI SYLLABLE M154 MUAN + +1E81A +MENDE KIKAKUI SYLLABLE M189 MUEN + +1E81B +MENDE KIKAKUI SYLLABLE M010 BI + +1E81C +MENDE KIKAKUI SYLLABLE M011 BA + +1E81D +MENDE KIKAKUI SYLLABLE M012 BU + +1E81E +MENDE KIKAKUI SYLLABLE M150 BEE + +1E81F +MENDE KIKAKUI SYLLABLE M097 BE + +1E820 +MENDE KIKAKUI SYLLABLE M103 BOO + +1E821 +MENDE KIKAKUI SYLLABLE M138 BO + +1E822 +MENDE KIKAKUI SYLLABLE M013 I + +1E823 +MENDE KIKAKUI SYLLABLE M014 A + +1E824 +MENDE KIKAKUI SYLLABLE M015 U + +1E825 +MENDE KIKAKUI SYLLABLE M163 EE + +1E826 +MENDE KIKAKUI SYLLABLE M100 E + +1E827 +MENDE KIKAKUI SYLLABLE M165 OO + +1E828 +MENDE KIKAKUI SYLLABLE M147 O + +1E829 +MENDE KIKAKUI SYLLABLE M137 EI + +1E82A +MENDE KIKAKUI SYLLABLE M131 IN + +1E82B +MENDE KIKAKUI SYLLABLE M135 IN + +1E82C +MENDE KIKAKUI SYLLABLE M195 AN + +1E82D +MENDE KIKAKUI SYLLABLE M178 EN + +1E82E +MENDE KIKAKUI SYLLABLE M019 SI + +1E82F +MENDE KIKAKUI SYLLABLE M020 SA + +1E830 +MENDE KIKAKUI SYLLABLE M021 SU + +1E831 +MENDE KIKAKUI SYLLABLE M162 SEE + +1E832 +MENDE KIKAKUI SYLLABLE M116 SE + +1E833 +MENDE KIKAKUI SYLLABLE M136 SOO + +1E834 +MENDE KIKAKUI SYLLABLE M079 SO + +1E835 +MENDE KIKAKUI SYLLABLE M196 SIA + +1E836 +MENDE KIKAKUI SYLLABLE M025 LI + +1E837 +MENDE KIKAKUI SYLLABLE M026 LA + +1E838 +MENDE KIKAKUI SYLLABLE M027 LU + +1E839 +MENDE KIKAKUI SYLLABLE M084 LEE + +1E83A +MENDE KIKAKUI SYLLABLE M073 LE + +1E83B +MENDE KIKAKUI SYLLABLE M054 LOO + +1E83C +MENDE KIKAKUI SYLLABLE M153 LO + +1E83D +MENDE KIKAKUI SYLLABLE M110 LONG LE + +1E83E +MENDE KIKAKUI SYLLABLE M016 DI + +1E83F +MENDE KIKAKUI SYLLABLE M017 DA + +1E840 +MENDE KIKAKUI SYLLABLE M018 DU + +1E841 +MENDE KIKAKUI SYLLABLE M089 DEE + +1E842 +MENDE KIKAKUI SYLLABLE M180 DOO + +1E843 +MENDE KIKAKUI SYLLABLE M181 DO + +1E844 +MENDE KIKAKUI SYLLABLE M022 TI + +1E845 +MENDE KIKAKUI SYLLABLE M023 TA + +1E846 +MENDE KIKAKUI SYLLABLE M024 TU + +1E847 +MENDE KIKAKUI SYLLABLE M091 TEE + +1E848 +MENDE KIKAKUI SYLLABLE M055 TE + +1E849 +MENDE KIKAKUI SYLLABLE M104 TOO + +1E84A +MENDE KIKAKUI SYLLABLE M069 TO + +1E84B +MENDE KIKAKUI SYLLABLE M028 JI + +1E84C +MENDE KIKAKUI SYLLABLE M029 JA + +1E84D +MENDE KIKAKUI SYLLABLE M030 JU + +1E84E +MENDE KIKAKUI SYLLABLE M157 JEE + +1E84F +MENDE KIKAKUI SYLLABLE M113 JE + +1E850 +MENDE KIKAKUI SYLLABLE M160 JOO + +1E851 +MENDE KIKAKUI SYLLABLE M063 JO + +1E852 +MENDE KIKAKUI SYLLABLE M175 LONG JO + +1E853 +MENDE KIKAKUI SYLLABLE M031 YI + +1E854 +MENDE KIKAKUI SYLLABLE M032 YA + +1E855 +MENDE KIKAKUI SYLLABLE M033 YU + +1E856 +MENDE KIKAKUI SYLLABLE M109 YEE + +1E857 +MENDE KIKAKUI SYLLABLE M080 YE + +1E858 +MENDE KIKAKUI SYLLABLE M141 YOO + +1E859 +MENDE KIKAKUI SYLLABLE M121 YO + +1E85A +MENDE KIKAKUI SYLLABLE M034 FI + +1E85B +MENDE KIKAKUI SYLLABLE M035 FA + +1E85C +MENDE KIKAKUI SYLLABLE M036 FU + +1E85D +MENDE KIKAKUI SYLLABLE M078 FEE + +1E85E +MENDE KIKAKUI SYLLABLE M075 FE + +1E85F +MENDE KIKAKUI SYLLABLE M133 FOO + +1E860 +MENDE KIKAKUI SYLLABLE M088 FO + +1E861 +MENDE KIKAKUI SYLLABLE M197 FUA + +1E862 +MENDE KIKAKUI SYLLABLE M101 FAN + +1E863 +MENDE KIKAKUI SYLLABLE M037 NIN + +1E864 +MENDE KIKAKUI SYLLABLE M038 NAN + +1E865 +MENDE KIKAKUI SYLLABLE M039 NUN + +1E866 +MENDE KIKAKUI SYLLABLE M117 NEN + +1E867 +MENDE KIKAKUI SYLLABLE M169 NON + +1E868 +MENDE KIKAKUI SYLLABLE M176 HI + +1E869 +MENDE KIKAKUI SYLLABLE M041 HA + +1E86A +MENDE KIKAKUI SYLLABLE M186 HU + +1E86B +MENDE KIKAKUI SYLLABLE M040 HEE + +1E86C +MENDE KIKAKUI SYLLABLE M096 HE + +1E86D +MENDE KIKAKUI SYLLABLE M042 HOO + +1E86E +MENDE KIKAKUI SYLLABLE M140 HO + +1E86F +MENDE KIKAKUI SYLLABLE M083 HEEI + +1E870 +MENDE KIKAKUI SYLLABLE M128 HOOU + +1E871 +MENDE KIKAKUI SYLLABLE M053 HIN + +1E872 +MENDE KIKAKUI SYLLABLE M130 HAN + +1E873 +MENDE KIKAKUI SYLLABLE M087 HUN + +1E874 +MENDE KIKAKUI SYLLABLE M052 HEN + +1E875 +MENDE KIKAKUI SYLLABLE M193 HON + +1E876 +MENDE KIKAKUI SYLLABLE M046 HUAN + +1E877 +MENDE KIKAKUI SYLLABLE M090 NGGI + +1E878 +MENDE KIKAKUI SYLLABLE M043 NGGA + +1E879 +MENDE KIKAKUI SYLLABLE M082 NGGU + +1E87A +MENDE KIKAKUI SYLLABLE M115 NGGEE + +1E87B +MENDE KIKAKUI SYLLABLE M146 NGGE + +1E87C +MENDE KIKAKUI SYLLABLE M156 NGGOO + +1E87D +MENDE KIKAKUI SYLLABLE M120 NGGO + +1E87E +MENDE KIKAKUI SYLLABLE M159 NGGAA + +1E87F +MENDE KIKAKUI SYLLABLE M127 NGGUA + +1E880 +MENDE KIKAKUI SYLLABLE M086 LONG NGGE + +1E881 +MENDE KIKAKUI SYLLABLE M106 LONG NGGOO + +1E882 +MENDE KIKAKUI SYLLABLE M183 LONG NGGO + +1E883 +MENDE KIKAKUI SYLLABLE M155 GI + +1E884 +MENDE KIKAKUI SYLLABLE M111 GA + +1E885 +MENDE KIKAKUI SYLLABLE M168 GU + +1E886 +MENDE KIKAKUI SYLLABLE M190 GEE + +1E887 +MENDE KIKAKUI SYLLABLE M166 GUEI + +1E888 +MENDE KIKAKUI SYLLABLE M167 GUAN + +1E889 +MENDE KIKAKUI SYLLABLE M184 NGEN + +1E88A +MENDE KIKAKUI SYLLABLE M057 NGON + +1E88B +MENDE KIKAKUI SYLLABLE M177 NGUAN + +1E88C +MENDE KIKAKUI SYLLABLE M068 PI + +1E88D +MENDE KIKAKUI SYLLABLE M099 PA + +1E88E +MENDE KIKAKUI SYLLABLE M050 PU + +1E88F +MENDE KIKAKUI SYLLABLE M081 PEE + +1E890 +MENDE KIKAKUI SYLLABLE M051 PE + +1E891 +MENDE KIKAKUI SYLLABLE M102 POO + +1E892 +MENDE KIKAKUI SYLLABLE M066 PO + +1E893 +MENDE KIKAKUI SYLLABLE M145 MBI + +1E894 +MENDE KIKAKUI SYLLABLE M062 MBA + +1E895 +MENDE KIKAKUI SYLLABLE M122 MBU + +1E896 +MENDE KIKAKUI SYLLABLE M047 MBEE + +1E897 +MENDE KIKAKUI SYLLABLE M188 MBEE + +1E898 +MENDE KIKAKUI SYLLABLE M072 MBE + +1E899 +MENDE KIKAKUI SYLLABLE M172 MBO + +1E899 +MENDE KIKAKUI SYLLABLE M172 MBOO + +1E89A +MENDE KIKAKUI SYLLABLE M174 MBOO + +1E89A +MENDE KIKAKUI SYLLABLE M174 MBO + +1E89B +MENDE KIKAKUI SYLLABLE M187 MBUU + +1E89C +MENDE KIKAKUI SYLLABLE M161 LONG MBE + +1E89D +MENDE KIKAKUI SYLLABLE M105 LONG MBOO + +1E89E +MENDE KIKAKUI SYLLABLE M142 LONG MBO + +1E89F +MENDE KIKAKUI SYLLABLE M132 KPI + +1E8A0 +MENDE KIKAKUI SYLLABLE M092 KPA + +1E8A1 +MENDE KIKAKUI SYLLABLE M074 KPU + +1E8A2 +MENDE KIKAKUI SYLLABLE M044 KPEE + +1E8A3 +MENDE KIKAKUI SYLLABLE M108 KPE + +1E8A4 +MENDE KIKAKUI SYLLABLE M112 KPOO + +1E8A5 +MENDE KIKAKUI SYLLABLE M158 KPO + +1E8A6 +MENDE KIKAKUI SYLLABLE M124 GBI + +1E8A7 +MENDE KIKAKUI SYLLABLE M056 GBA + +1E8A8 +MENDE KIKAKUI SYLLABLE M148 GBU + +1E8A9 +MENDE KIKAKUI SYLLABLE M093 GBEE + +1E8AA +MENDE KIKAKUI SYLLABLE M107 GBE + +1E8AB +MENDE KIKAKUI SYLLABLE M071 GBOO + +1E8AC +MENDE KIKAKUI SYLLABLE M070 GBO + +1E8AD +MENDE KIKAKUI SYLLABLE M171 RA + +1E8AE +MENDE KIKAKUI SYLLABLE M123 NDI + +1E8AF +MENDE KIKAKUI SYLLABLE M129 NDA + +1E8B0 +MENDE KIKAKUI SYLLABLE M125 NDU + +1E8B1 +MENDE KIKAKUI SYLLABLE M191 NDEE + +1E8B2 +MENDE KIKAKUI SYLLABLE M119 NDE + +1E8B3 +MENDE KIKAKUI SYLLABLE M067 NDOO + +1E8B4 +MENDE KIKAKUI SYLLABLE M064 NDO + +1E8B5 +MENDE KIKAKUI SYLLABLE M152 NJA + +1E8B6 +MENDE KIKAKUI SYLLABLE M192 NJU + +1E8B7 +MENDE KIKAKUI SYLLABLE M149 NJEE + +1E8B8 +MENDE KIKAKUI SYLLABLE M134 NJOO + +1E8B9 +MENDE KIKAKUI SYLLABLE M182 VI + +1E8BA +MENDE KIKAKUI SYLLABLE M185 VA + +1E8BB +MENDE KIKAKUI SYLLABLE M151 VU + +1E8BC +MENDE KIKAKUI SYLLABLE M173 VEE + +1E8BD +MENDE KIKAKUI SYLLABLE M085 VE + +1E8BE +MENDE KIKAKUI SYLLABLE M144 VOO + +1E8BF +MENDE KIKAKUI SYLLABLE M077 VO + +1E8C0 +MENDE KIKAKUI SYLLABLE M164 NYIN + +1E8C1 +MENDE KIKAKUI SYLLABLE M058 NYAN + +1E8C2 +MENDE KIKAKUI SYLLABLE M170 NYUN + +1E8C3 +MENDE KIKAKUI SYLLABLE M098 NYEN + +1E8C4 +MENDE KIKAKUI SYLLABLE M060 NYON + +1E8C7 +MENDE KIKAKUI DIGIT ONE + +1E8C8 +MENDE KIKAKUI DIGIT TWO + +1E8C9 +MENDE KIKAKUI DIGIT THREE + +1E8CA +MENDE KIKAKUI DIGIT FOUR + +1E8CB +MENDE KIKAKUI DIGIT FIVE + +1E8CC +MENDE KIKAKUI DIGIT SIX + +1E8CD +MENDE KIKAKUI DIGIT SEVEN + +1E8CE +MENDE KIKAKUI DIGIT EIGHT + +1E8CF +MENDE KIKAKUI DIGIT NINE + +1E8D0 +MENDE KIKAKUI COMBINING NUMBER TEENS + +1E8D1 +MENDE KIKAKUI COMBINING NUMBER TENS + +1E8D2 +MENDE KIKAKUI COMBINING NUMBER HUNDREDS + +1E8D3 +MENDE KIKAKUI COMBINING NUMBER THOUSANDS + +1E8D4 +MENDE KIKAKUI COMBINING NUMBER TEN THOUSANDS + +1E8D5 +MENDE KIKAKUI COMBINING NUMBER HUNDRED THOUSANDS + +1E8D6 +MENDE KIKAKUI COMBINING NUMBER MILLIONS + +1E900 +ADLAM CAPITAL LETTER ALIF + +1E901 +ADLAM CAPITAL LETTER DAALI + +1E902 +ADLAM CAPITAL LETTER LAAM + +1E903 +ADLAM CAPITAL LETTER MIIM + +1E904 +ADLAM CAPITAL LETTER BA + +1E905 +ADLAM CAPITAL LETTER SINNYIIYHE + +1E906 +ADLAM CAPITAL LETTER PE + +1E907 +ADLAM CAPITAL LETTER BHE + +1E908 +ADLAM CAPITAL LETTER RA + +1E909 +ADLAM CAPITAL LETTER E + +1E90A +ADLAM CAPITAL LETTER FA + +1E90B +ADLAM CAPITAL LETTER I + +1E90C +ADLAM CAPITAL LETTER O + +1E90D +ADLAM CAPITAL LETTER DHA + +1E90E +ADLAM CAPITAL LETTER YHE + +1E90F +ADLAM CAPITAL LETTER WAW + +1E910 +ADLAM CAPITAL LETTER NUN + +1E911 +ADLAM CAPITAL LETTER KAF + +1E912 +ADLAM CAPITAL LETTER YA + +1E913 +ADLAM CAPITAL LETTER U + +1E914 +ADLAM CAPITAL LETTER JIIM + +1E915 +ADLAM CAPITAL LETTER CHI + +1E916 +ADLAM CAPITAL LETTER HA + +1E917 +ADLAM CAPITAL LETTER QAAF + +1E918 +ADLAM CAPITAL LETTER GA + +1E919 +ADLAM CAPITAL LETTER NYA + +1E91A +ADLAM CAPITAL LETTER TU + +1E91B +ADLAM CAPITAL LETTER NHA + +1E91C +ADLAM CAPITAL LETTER VA + +1E91D +ADLAM CAPITAL LETTER KHA + +1E91E +ADLAM CAPITAL LETTER GBE + +1E91F +ADLAM CAPITAL LETTER ZAL + +1E920 +ADLAM CAPITAL LETTER KPO + +1E921 +ADLAM CAPITAL LETTER SHA + +1E922 +ADLAM SMALL LETTER ALIF + +1E923 +ADLAM SMALL LETTER DAALI + +1E924 +ADLAM SMALL LETTER LAAM + +1E925 +ADLAM SMALL LETTER MIIM + +1E926 +ADLAM SMALL LETTER BA + +1E927 +ADLAM SMALL LETTER SINNYIIYHE + +1E928 +ADLAM SMALL LETTER PE + +1E929 +ADLAM SMALL LETTER BHE + +1E92A +ADLAM SMALL LETTER RA + +1E92B +ADLAM SMALL LETTER E + +1E92C +ADLAM SMALL LETTER FA + +1E92D +ADLAM SMALL LETTER I + +1E92E +ADLAM SMALL LETTER O + +1E92F +ADLAM SMALL LETTER DHA + +1E930 +ADLAM SMALL LETTER YHE + +1E931 +ADLAM SMALL LETTER WAW + +1E932 +ADLAM SMALL LETTER NUN + +1E933 +ADLAM SMALL LETTER KAF + +1E934 +ADLAM SMALL LETTER YA + +1E935 +ADLAM SMALL LETTER U + +1E936 +ADLAM SMALL LETTER JIIM + +1E937 +ADLAM SMALL LETTER CHI + +1E938 +ADLAM SMALL LETTER HA + +1E939 +ADLAM SMALL LETTER QAAF + +1E93A +ADLAM SMALL LETTER GA + +1E93B +ADLAM SMALL LETTER NYA + +1E93C +ADLAM SMALL LETTER TU + +1E93D +ADLAM SMALL LETTER NHA + +1E93E +ADLAM SMALL LETTER VA + +1E93F +ADLAM SMALL LETTER KHA + +1E940 +ADLAM SMALL LETTER GBE + +1E941 +ADLAM SMALL LETTER ZAL + +1E942 +ADLAM SMALL LETTER KPO + +1E943 +ADLAM SMALL LETTER SHA + +1E944 +ADLAM ALIF LENGTHENER + +1E945 +ADLAM VOWEL LENGTHENER + +1E946 +ADLAM GEMINATION MARK + +1E947 +ADLAM HAMZA + +1E948 +ADLAM CONSONANT MODIFIER + +1E949 +ADLAM GEMINATE CONSONANT MODIFIER + +1E94A +ADLAM NUKTA + +1E94B +ADLAM NASALIZATION MARK + +1E950 +ADLAM DIGIT ZERO + +1E951 +ADLAM DIGIT ONE + +1E952 +ADLAM DIGIT TWO + +1E953 +ADLAM DIGIT THREE + +1E954 +ADLAM DIGIT FOUR + +1E955 +ADLAM DIGIT FIVE + +1E956 +ADLAM DIGIT SIX + +1E957 +ADLAM DIGIT SEVEN + +1E958 +ADLAM DIGIT EIGHT + +1E959 +ADLAM DIGIT NINE + +1E95E +ADLAM INITIAL EXCLAMATION MARK + +1E95F +ADLAM INITIAL QUESTION MARK + +1EC71 +INDIC SIYAQ NUMBER ONE + +1EC72 +INDIC SIYAQ NUMBER TWO + +1EC73 +INDIC SIYAQ NUMBER THREE + +1EC74 +INDIC SIYAQ NUMBER FOUR + +1EC75 +INDIC SIYAQ NUMBER FIVE + +1EC76 +INDIC SIYAQ NUMBER SIX + +1EC77 +INDIC SIYAQ NUMBER SEVEN + +1EC78 +INDIC SIYAQ NUMBER EIGHT + +1EC79 +INDIC SIYAQ NUMBER NINE + +1EC7A +INDIC SIYAQ NUMBER TEN + +1EC7B +INDIC SIYAQ NUMBER TWENTY + +1EC7C +INDIC SIYAQ NUMBER THIRTY + +1EC7D +INDIC SIYAQ NUMBER FORTY + +1EC7E +INDIC SIYAQ NUMBER FIFTY + +1EC7F +INDIC SIYAQ NUMBER SIXTY + +1EC80 +INDIC SIYAQ NUMBER SEVENTY + +1EC81 +INDIC SIYAQ NUMBER EIGHTY + +1EC82 +INDIC SIYAQ NUMBER NINETY + +1EC83 +INDIC SIYAQ NUMBER ONE HUNDRED + +1EC84 +INDIC SIYAQ NUMBER TWO HUNDRED + +1EC85 +INDIC SIYAQ NUMBER THREE HUNDRED + +1EC86 +INDIC SIYAQ NUMBER FOUR HUNDRED + +1EC87 +INDIC SIYAQ NUMBER FIVE HUNDRED + +1EC88 +INDIC SIYAQ NUMBER SIX HUNDRED + +1EC89 +INDIC SIYAQ NUMBER SEVEN HUNDRED + +1EC8A +INDIC SIYAQ NUMBER EIGHT HUNDRED + +1EC8B +INDIC SIYAQ NUMBER NINE HUNDRED + +1EC8C +INDIC SIYAQ NUMBER ONE THOUSAND + +1EC8D +INDIC SIYAQ NUMBER TWO THOUSAND + +1EC8E +INDIC SIYAQ NUMBER THREE THOUSAND + +1EC8F +INDIC SIYAQ NUMBER FOUR THOUSAND + +1EC90 +INDIC SIYAQ NUMBER FIVE THOUSAND + +1EC91 +INDIC SIYAQ NUMBER SIX THOUSAND + +1EC92 +INDIC SIYAQ NUMBER SEVEN THOUSAND + +1EC93 +INDIC SIYAQ NUMBER EIGHT THOUSAND + +1EC94 +INDIC SIYAQ NUMBER NINE THOUSAND + +1EC95 +INDIC SIYAQ NUMBER TEN THOUSAND + +1EC96 +INDIC SIYAQ NUMBER TWENTY THOUSAND + +1EC97 +INDIC SIYAQ NUMBER THIRTY THOUSAND + +1EC98 +INDIC SIYAQ NUMBER FORTY THOUSAND + +1EC99 +INDIC SIYAQ NUMBER FIFTY THOUSAND + +1EC9A +INDIC SIYAQ NUMBER SIXTY THOUSAND + +1EC9B +INDIC SIYAQ NUMBER SEVENTY THOUSAND + +1EC9C +INDIC SIYAQ NUMBER EIGHTY THOUSAND + +1EC9D +INDIC SIYAQ NUMBER NINETY THOUSAND + +1EC9E +INDIC SIYAQ NUMBER LAKH + +1EC9F +INDIC SIYAQ NUMBER LAKHAN + +1ECA0 +INDIC SIYAQ LAKH MARK + +1ECA1 +INDIC SIYAQ NUMBER KAROR + +1ECA2 +INDIC SIYAQ NUMBER KARORAN + +1ECA3 +INDIC SIYAQ NUMBER PREFIXED ONE + +1ECA4 +INDIC SIYAQ NUMBER PREFIXED TWO + +1ECA5 +INDIC SIYAQ NUMBER PREFIXED THREE + +1ECA6 +INDIC SIYAQ NUMBER PREFIXED FOUR + +1ECA7 +INDIC SIYAQ NUMBER PREFIXED FIVE + +1ECA8 +INDIC SIYAQ NUMBER PREFIXED SIX + +1ECA9 +INDIC SIYAQ NUMBER PREFIXED SEVEN + +1ECAA +INDIC SIYAQ NUMBER PREFIXED EIGHT + +1ECAB +INDIC SIYAQ NUMBER PREFIXED NINE + +1ECAC +INDIC SIYAQ PLACEHOLDER + +1ECAD +INDIC SIYAQ FRACTION ONE QUARTER + +1ECAE +INDIC SIYAQ FRACTION ONE HALF + +1ECAF +INDIC SIYAQ FRACTION THREE QUARTERS + +1ECB0 +INDIC SIYAQ RUPEE MARK + +1ECB1 +INDIC SIYAQ NUMBER ALTERNATE ONE + +1ECB2 +INDIC SIYAQ NUMBER ALTERNATE TWO + +1ECB3 +INDIC SIYAQ NUMBER ALTERNATE TEN THOUSAND + +1ECB4 +INDIC SIYAQ ALTERNATE LAKH MARK + +1ED01 +OTTOMAN SIYAQ NUMBER ONE + +1ED02 +OTTOMAN SIYAQ NUMBER TWO + +1ED03 +OTTOMAN SIYAQ NUMBER THREE + +1ED04 +OTTOMAN SIYAQ NUMBER FOUR + +1ED05 +OTTOMAN SIYAQ NUMBER FIVE + +1ED06 +OTTOMAN SIYAQ NUMBER SIX + +1ED07 +OTTOMAN SIYAQ NUMBER SEVEN + +1ED08 +OTTOMAN SIYAQ NUMBER EIGHT + +1ED09 +OTTOMAN SIYAQ NUMBER NINE + +1ED0A +OTTOMAN SIYAQ NUMBER TEN + +1ED0B +OTTOMAN SIYAQ NUMBER TWENTY + +1ED0C +OTTOMAN SIYAQ NUMBER THIRTY + +1ED0D +OTTOMAN SIYAQ NUMBER FORTY + +1ED0E +OTTOMAN SIYAQ NUMBER FIFTY + +1ED0F +OTTOMAN SIYAQ NUMBER SIXTY + +1ED10 +OTTOMAN SIYAQ NUMBER SEVENTY + +1ED11 +OTTOMAN SIYAQ NUMBER EIGHTY + +1ED12 +OTTOMAN SIYAQ NUMBER NINETY + +1ED13 +OTTOMAN SIYAQ NUMBER ONE HUNDRED + +1ED14 +OTTOMAN SIYAQ NUMBER TWO HUNDRED + +1ED15 +OTTOMAN SIYAQ NUMBER THREE HUNDRED + +1ED16 +OTTOMAN SIYAQ NUMBER FOUR HUNDRED + +1ED17 +OTTOMAN SIYAQ NUMBER FIVE HUNDRED + +1ED18 +OTTOMAN SIYAQ NUMBER SIX HUNDRED + +1ED19 +OTTOMAN SIYAQ NUMBER SEVEN HUNDRED + +1ED1A +OTTOMAN SIYAQ NUMBER EIGHT HUNDRED + +1ED1B +OTTOMAN SIYAQ NUMBER NINE HUNDRED + +1ED1C +OTTOMAN SIYAQ NUMBER ONE THOUSAND + +1ED1D +OTTOMAN SIYAQ NUMBER TWO THOUSAND + +1ED1E +OTTOMAN SIYAQ NUMBER THREE THOUSAND + +1ED1F +OTTOMAN SIYAQ NUMBER FOUR THOUSAND + +1ED20 +OTTOMAN SIYAQ NUMBER FIVE THOUSAND + +1ED21 +OTTOMAN SIYAQ NUMBER SIX THOUSAND + +1ED22 +OTTOMAN SIYAQ NUMBER SEVEN THOUSAND + +1ED23 +OTTOMAN SIYAQ NUMBER EIGHT THOUSAND + +1ED24 +OTTOMAN SIYAQ NUMBER NINE THOUSAND + +1ED25 +OTTOMAN SIYAQ NUMBER TEN THOUSAND + +1ED26 +OTTOMAN SIYAQ NUMBER TWENTY THOUSAND + +1ED27 +OTTOMAN SIYAQ NUMBER THIRTY THOUSAND + +1ED28 +OTTOMAN SIYAQ NUMBER FORTY THOUSAND + +1ED29 +OTTOMAN SIYAQ NUMBER FIFTY THOUSAND + +1ED2A +OTTOMAN SIYAQ NUMBER SIXTY THOUSAND + +1ED2B +OTTOMAN SIYAQ NUMBER SEVENTY THOUSAND + +1ED2C +OTTOMAN SIYAQ NUMBER EIGHTY THOUSAND + +1ED2D +OTTOMAN SIYAQ NUMBER NINETY THOUSAND + +1ED2E +OTTOMAN SIYAQ MARRATAN + +1ED2F +OTTOMAN SIYAQ ALTERNATE NUMBER TWO + +1ED30 +OTTOMAN SIYAQ ALTERNATE NUMBER THREE + +1ED31 +OTTOMAN SIYAQ ALTERNATE NUMBER FOUR + +1ED32 +OTTOMAN SIYAQ ALTERNATE NUMBER FIVE + +1ED33 +OTTOMAN SIYAQ ALTERNATE NUMBER SIX + +1ED34 +OTTOMAN SIYAQ ALTERNATE NUMBER SEVEN + +1ED35 +OTTOMAN SIYAQ ALTERNATE NUMBER EIGHT + +1ED36 +OTTOMAN SIYAQ ALTERNATE NUMBER NINE + +1ED37 +OTTOMAN SIYAQ ALTERNATE NUMBER TEN + +1ED38 +OTTOMAN SIYAQ ALTERNATE NUMBER FOUR HUNDRED + +1ED39 +OTTOMAN SIYAQ ALTERNATE NUMBER SIX HUNDRED + +1ED3A +OTTOMAN SIYAQ ALTERNATE NUMBER TWO THOUSAND + +1ED3B +OTTOMAN SIYAQ ALTERNATE NUMBER TEN THOUSAND + +1ED3C +OTTOMAN SIYAQ FRACTION ONE HALF + +1ED3D +OTTOMAN SIYAQ FRACTION ONE SIXTH + +1EE00 +ARABIC MATHEMATICAL ALEF + +1EE01 +ARABIC MATHEMATICAL BEH + +1EE02 +ARABIC MATHEMATICAL JEEM + +1EE03 +ARABIC MATHEMATICAL DAL + +1EE05 +ARABIC MATHEMATICAL WAW + +1EE06 +ARABIC MATHEMATICAL ZAIN + +1EE07 +ARABIC MATHEMATICAL HAH + +1EE08 +ARABIC MATHEMATICAL TAH + +1EE09 +ARABIC MATHEMATICAL YEH + +1EE0A +ARABIC MATHEMATICAL KAF + +1EE0B +ARABIC MATHEMATICAL LAM + +1EE0C +ARABIC MATHEMATICAL MEEM + +1EE0D +ARABIC MATHEMATICAL NOON + +1EE0E +ARABIC MATHEMATICAL SEEN + +1EE0F +ARABIC MATHEMATICAL AIN + +1EE10 +ARABIC MATHEMATICAL FEH + +1EE11 +ARABIC MATHEMATICAL SAD + +1EE12 +ARABIC MATHEMATICAL QAF + +1EE13 +ARABIC MATHEMATICAL REH + +1EE14 +ARABIC MATHEMATICAL SHEEN + +1EE15 +ARABIC MATHEMATICAL TEH + +1EE16 +ARABIC MATHEMATICAL THEH + +1EE17 +ARABIC MATHEMATICAL KHAH + +1EE18 +ARABIC MATHEMATICAL THAL + +1EE19 +ARABIC MATHEMATICAL DAD + +1EE1A +ARABIC MATHEMATICAL ZAH + +1EE1B +ARABIC MATHEMATICAL GHAIN + +1EE1C +ARABIC MATHEMATICAL DOTLESS BEH + +1EE1D +ARABIC MATHEMATICAL DOTLESS NOON + +1EE1E +ARABIC MATHEMATICAL DOTLESS FEH + +1EE1F +ARABIC MATHEMATICAL DOTLESS QAF + +1EE21 +ARABIC MATHEMATICAL INITIAL BEH + +1EE22 +ARABIC MATHEMATICAL INITIAL JEEM + +1EE24 +ARABIC MATHEMATICAL INITIAL HEH + +1EE27 +ARABIC MATHEMATICAL INITIAL HAH + +1EE29 +ARABIC MATHEMATICAL INITIAL YEH + +1EE2A +ARABIC MATHEMATICAL INITIAL KAF + +1EE2B +ARABIC MATHEMATICAL INITIAL LAM + +1EE2C +ARABIC MATHEMATICAL INITIAL MEEM + +1EE2D +ARABIC MATHEMATICAL INITIAL NOON + +1EE2E +ARABIC MATHEMATICAL INITIAL SEEN + +1EE2F +ARABIC MATHEMATICAL INITIAL AIN + +1EE30 +ARABIC MATHEMATICAL INITIAL FEH + +1EE31 +ARABIC MATHEMATICAL INITIAL SAD + +1EE32 +ARABIC MATHEMATICAL INITIAL QAF + +1EE34 +ARABIC MATHEMATICAL INITIAL SHEEN + +1EE35 +ARABIC MATHEMATICAL INITIAL TEH + +1EE36 +ARABIC MATHEMATICAL INITIAL THEH + +1EE37 +ARABIC MATHEMATICAL INITIAL KHAH + +1EE39 +ARABIC MATHEMATICAL INITIAL DAD + +1EE3B +ARABIC MATHEMATICAL INITIAL GHAIN + +1EE42 +ARABIC MATHEMATICAL TAILED JEEM + +1EE47 +ARABIC MATHEMATICAL TAILED HAH + +1EE49 +ARABIC MATHEMATICAL TAILED YEH + +1EE4B +ARABIC MATHEMATICAL TAILED LAM + +1EE4D +ARABIC MATHEMATICAL TAILED NOON + +1EE4E +ARABIC MATHEMATICAL TAILED SEEN + +1EE4F +ARABIC MATHEMATICAL TAILED AIN + +1EE51 +ARABIC MATHEMATICAL TAILED SAD + +1EE52 +ARABIC MATHEMATICAL TAILED QAF + +1EE54 +ARABIC MATHEMATICAL TAILED SHEEN + +1EE57 +ARABIC MATHEMATICAL TAILED KHAH + +1EE59 +ARABIC MATHEMATICAL TAILED DAD + +1EE5B +ARABIC MATHEMATICAL TAILED GHAIN + +1EE5D +ARABIC MATHEMATICAL TAILED DOTLESS NOON + +1EE5F +ARABIC MATHEMATICAL TAILED DOTLESS QAF + +1EE61 +ARABIC MATHEMATICAL STRETCHED BEH + +1EE62 +ARABIC MATHEMATICAL STRETCHED JEEM + +1EE64 +ARABIC MATHEMATICAL STRETCHED HEH + +1EE67 +ARABIC MATHEMATICAL STRETCHED HAH + +1EE68 +ARABIC MATHEMATICAL STRETCHED TAH + +1EE69 +ARABIC MATHEMATICAL STRETCHED YEH + +1EE6A +ARABIC MATHEMATICAL STRETCHED KAF + +1EE6C +ARABIC MATHEMATICAL STRETCHED MEEM + +1EE6D +ARABIC MATHEMATICAL STRETCHED NOON + +1EE6E +ARABIC MATHEMATICAL STRETCHED SEEN + +1EE6F +ARABIC MATHEMATICAL STRETCHED AIN + +1EE70 +ARABIC MATHEMATICAL STRETCHED FEH + +1EE71 +ARABIC MATHEMATICAL STRETCHED SAD + +1EE72 +ARABIC MATHEMATICAL STRETCHED QAF + +1EE74 +ARABIC MATHEMATICAL STRETCHED SHEEN + +1EE75 +ARABIC MATHEMATICAL STRETCHED TEH + +1EE76 +ARABIC MATHEMATICAL STRETCHED THEH + +1EE77 +ARABIC MATHEMATICAL STRETCHED KHAH + +1EE79 +ARABIC MATHEMATICAL STRETCHED DAD + +1EE7A +ARABIC MATHEMATICAL STRETCHED ZAH + +1EE7B +ARABIC MATHEMATICAL STRETCHED GHAIN + +1EE7C +ARABIC MATHEMATICAL STRETCHED DOTLESS BEH + +1EE7E +ARABIC MATHEMATICAL STRETCHED DOTLESS FEH + +1EE80 +ARABIC MATHEMATICAL LOOPED ALEF + +1EE81 +ARABIC MATHEMATICAL LOOPED BEH + +1EE82 +ARABIC MATHEMATICAL LOOPED JEEM + +1EE83 +ARABIC MATHEMATICAL LOOPED DAL + +1EE84 +ARABIC MATHEMATICAL LOOPED HEH + +1EE85 +ARABIC MATHEMATICAL LOOPED WAW + +1EE86 +ARABIC MATHEMATICAL LOOPED ZAIN + +1EE87 +ARABIC MATHEMATICAL LOOPED HAH + +1EE88 +ARABIC MATHEMATICAL LOOPED TAH + +1EE89 +ARABIC MATHEMATICAL LOOPED YEH + +1EE8B +ARABIC MATHEMATICAL LOOPED LAM + +1EE8C +ARABIC MATHEMATICAL LOOPED MEEM + +1EE8D +ARABIC MATHEMATICAL LOOPED NOON + +1EE8E +ARABIC MATHEMATICAL LOOPED SEEN + +1EE8F +ARABIC MATHEMATICAL LOOPED AIN + +1EE90 +ARABIC MATHEMATICAL LOOPED FEH + +1EE91 +ARABIC MATHEMATICAL LOOPED SAD + +1EE92 +ARABIC MATHEMATICAL LOOPED QAF + +1EE93 +ARABIC MATHEMATICAL LOOPED REH + +1EE94 +ARABIC MATHEMATICAL LOOPED SHEEN + +1EE95 +ARABIC MATHEMATICAL LOOPED TEH + +1EE96 +ARABIC MATHEMATICAL LOOPED THEH + +1EE97 +ARABIC MATHEMATICAL LOOPED KHAH + +1EE98 +ARABIC MATHEMATICAL LOOPED THAL + +1EE99 +ARABIC MATHEMATICAL LOOPED DAD + +1EE9A +ARABIC MATHEMATICAL LOOPED ZAH + +1EE9B +ARABIC MATHEMATICAL LOOPED GHAIN + +1EEA1 +ARABIC MATHEMATICAL DOUBLE-STRUCK BEH + +1EEA2 +ARABIC MATHEMATICAL DOUBLE-STRUCK JEEM + +1EEA3 +ARABIC MATHEMATICAL DOUBLE-STRUCK DAL + +1EEA5 +ARABIC MATHEMATICAL DOUBLE-STRUCK WAW + +1EEA6 +ARABIC MATHEMATICAL DOUBLE-STRUCK ZAIN + +1EEA7 +ARABIC MATHEMATICAL DOUBLE-STRUCK HAH + +1EEA8 +ARABIC MATHEMATICAL DOUBLE-STRUCK TAH + +1EEA9 +ARABIC MATHEMATICAL DOUBLE-STRUCK YEH + +1EEAB +ARABIC MATHEMATICAL DOUBLE-STRUCK LAM + +1EEAC +ARABIC MATHEMATICAL DOUBLE-STRUCK MEEM + +1EEAD +ARABIC MATHEMATICAL DOUBLE-STRUCK NOON + +1EEAE +ARABIC MATHEMATICAL DOUBLE-STRUCK SEEN + +1EEAF +ARABIC MATHEMATICAL DOUBLE-STRUCK AIN + +1EEB0 +ARABIC MATHEMATICAL DOUBLE-STRUCK FEH + +1EEB1 +ARABIC MATHEMATICAL DOUBLE-STRUCK SAD + +1EEB2 +ARABIC MATHEMATICAL DOUBLE-STRUCK QAF + +1EEB3 +ARABIC MATHEMATICAL DOUBLE-STRUCK REH + +1EEB4 +ARABIC MATHEMATICAL DOUBLE-STRUCK SHEEN + +1EEB5 +ARABIC MATHEMATICAL DOUBLE-STRUCK TEH + +1EEB6 +ARABIC MATHEMATICAL DOUBLE-STRUCK THEH + +1EEB7 +ARABIC MATHEMATICAL DOUBLE-STRUCK KHAH + +1EEB8 +ARABIC MATHEMATICAL DOUBLE-STRUCK THAL + +1EEB9 +ARABIC MATHEMATICAL DOUBLE-STRUCK DAD + +1EEBA +ARABIC MATHEMATICAL DOUBLE-STRUCK ZAH + +1EEBB +ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN + +1EEF0 +ARABIC MATHEMATICAL OPERATOR MEEM WITH HAH WITH TATWEEL + +1EEF1 +ARABIC MATHEMATICAL OPERATOR HAH WITH DAL + +1F000 +MAHJONG TILE EAST WIND + +1F001 +MAHJONG TILE SOUTH WIND + +1F002 +MAHJONG TILE WEST WIND + +1F003 +MAHJONG TILE NORTH WIND + +1F004 +MAHJONG TILE RED DRAGON + +1F005 +MAHJONG TILE GREEN DRAGON + +1F006 +MAHJONG TILE WHITE DRAGON + +1F007 +MAHJONG TILE ONE OF CHARACTERS + +1F008 +MAHJONG TILE TWO OF CHARACTERS + +1F009 +MAHJONG TILE THREE OF CHARACTERS + +1F00A +MAHJONG TILE FOUR OF CHARACTERS + +1F00B +MAHJONG TILE FIVE OF CHARACTERS + +1F00C +MAHJONG TILE SIX OF CHARACTERS + +1F00D +MAHJONG TILE SEVEN OF CHARACTERS + +1F00E +MAHJONG TILE EIGHT OF CHARACTERS + +1F00F +MAHJONG TILE NINE OF CHARACTERS + +1F010 +MAHJONG TILE ONE OF BAMBOOS + +1F011 +MAHJONG TILE TWO OF BAMBOOS + +1F012 +MAHJONG TILE THREE OF BAMBOOS + +1F013 +MAHJONG TILE FOUR OF BAMBOOS + +1F014 +MAHJONG TILE FIVE OF BAMBOOS + +1F015 +MAHJONG TILE SIX OF BAMBOOS + +1F016 +MAHJONG TILE SEVEN OF BAMBOOS + +1F017 +MAHJONG TILE EIGHT OF BAMBOOS + +1F018 +MAHJONG TILE NINE OF BAMBOOS + +1F019 +MAHJONG TILE ONE OF CIRCLES + +1F01A +MAHJONG TILE TWO OF CIRCLES + +1F01B +MAHJONG TILE THREE OF CIRCLES + +1F01C +MAHJONG TILE FOUR OF CIRCLES + +1F01D +MAHJONG TILE FIVE OF CIRCLES + +1F01E +MAHJONG TILE SIX OF CIRCLES + +1F01F +MAHJONG TILE SEVEN OF CIRCLES + +1F020 +MAHJONG TILE EIGHT OF CIRCLES + +1F021 +MAHJONG TILE NINE OF CIRCLES + +1F022 +MAHJONG TILE PLUM + +1F023 +MAHJONG TILE ORCHID + +1F024 +MAHJONG TILE BAMBOO + +1F025 +MAHJONG TILE CHRYSANTHEMUM + +1F026 +MAHJONG TILE SPRING + +1F027 +MAHJONG TILE SUMMER + +1F028 +MAHJONG TILE AUTUMN + +1F029 +MAHJONG TILE WINTER + +1F02A +MAHJONG TILE JOKER + +1F02B +MAHJONG TILE BACK + +1F030 +DOMINO TILE HORIZONTAL BACK + +1F031 +DOMINO TILE HORIZONTAL-00-00 + +1F032 +DOMINO TILE HORIZONTAL-00-01 + +1F033 +DOMINO TILE HORIZONTAL-00-02 + +1F034 +DOMINO TILE HORIZONTAL-00-03 + +1F035 +DOMINO TILE HORIZONTAL-00-04 + +1F036 +DOMINO TILE HORIZONTAL-00-05 + +1F037 +DOMINO TILE HORIZONTAL-00-06 + +1F038 +DOMINO TILE HORIZONTAL-01-00 + +1F039 +DOMINO TILE HORIZONTAL-01-01 + +1F03A +DOMINO TILE HORIZONTAL-01-02 + +1F03B +DOMINO TILE HORIZONTAL-01-03 + +1F03C +DOMINO TILE HORIZONTAL-01-04 + +1F03D +DOMINO TILE HORIZONTAL-01-05 + +1F03E +DOMINO TILE HORIZONTAL-01-06 + +1F03F +DOMINO TILE HORIZONTAL-02-00 + +1F040 +DOMINO TILE HORIZONTAL-02-01 + +1F041 +DOMINO TILE HORIZONTAL-02-02 + +1F042 +DOMINO TILE HORIZONTAL-02-03 + +1F043 +DOMINO TILE HORIZONTAL-02-04 + +1F044 +DOMINO TILE HORIZONTAL-02-05 + +1F045 +DOMINO TILE HORIZONTAL-02-06 + +1F046 +DOMINO TILE HORIZONTAL-03-00 + +1F047 +DOMINO TILE HORIZONTAL-03-01 + +1F048 +DOMINO TILE HORIZONTAL-03-02 + +1F049 +DOMINO TILE HORIZONTAL-03-03 + +1F04A +DOMINO TILE HORIZONTAL-03-04 + +1F04B +DOMINO TILE HORIZONTAL-03-05 + +1F04C +DOMINO TILE HORIZONTAL-03-06 + +1F04D +DOMINO TILE HORIZONTAL-04-00 + +1F04E +DOMINO TILE HORIZONTAL-04-01 + +1F04F +DOMINO TILE HORIZONTAL-04-02 + +1F050 +DOMINO TILE HORIZONTAL-04-03 + +1F051 +DOMINO TILE HORIZONTAL-04-04 + +1F052 +DOMINO TILE HORIZONTAL-04-05 + +1F053 +DOMINO TILE HORIZONTAL-04-06 + +1F054 +DOMINO TILE HORIZONTAL-05-00 + +1F055 +DOMINO TILE HORIZONTAL-05-01 + +1F056 +DOMINO TILE HORIZONTAL-05-02 + +1F057 +DOMINO TILE HORIZONTAL-05-03 + +1F058 +DOMINO TILE HORIZONTAL-05-04 + +1F059 +DOMINO TILE HORIZONTAL-05-05 + +1F05A +DOMINO TILE HORIZONTAL-05-06 + +1F05B +DOMINO TILE HORIZONTAL-06-00 + +1F05C +DOMINO TILE HORIZONTAL-06-01 + +1F05D +DOMINO TILE HORIZONTAL-06-02 + +1F05E +DOMINO TILE HORIZONTAL-06-03 + +1F05F +DOMINO TILE HORIZONTAL-06-04 + +1F060 +DOMINO TILE HORIZONTAL-06-05 + +1F061 +DOMINO TILE HORIZONTAL-06-06 + +1F062 +DOMINO TILE VERTICAL BACK + +1F063 +DOMINO TILE VERTICAL-00-00 + +1F064 +DOMINO TILE VERTICAL-00-01 + +1F065 +DOMINO TILE VERTICAL-00-02 + +1F066 +DOMINO TILE VERTICAL-00-03 + +1F067 +DOMINO TILE VERTICAL-00-04 + +1F068 +DOMINO TILE VERTICAL-00-05 + +1F069 +DOMINO TILE VERTICAL-00-06 + +1F06A +DOMINO TILE VERTICAL-01-00 + +1F06B +DOMINO TILE VERTICAL-01-01 + +1F06C +DOMINO TILE VERTICAL-01-02 + +1F06D +DOMINO TILE VERTICAL-01-03 + +1F06E +DOMINO TILE VERTICAL-01-04 + +1F06F +DOMINO TILE VERTICAL-01-05 + +1F070 +DOMINO TILE VERTICAL-01-06 + +1F071 +DOMINO TILE VERTICAL-02-00 + +1F072 +DOMINO TILE VERTICAL-02-01 + +1F073 +DOMINO TILE VERTICAL-02-02 + +1F074 +DOMINO TILE VERTICAL-02-03 + +1F075 +DOMINO TILE VERTICAL-02-04 + +1F076 +DOMINO TILE VERTICAL-02-05 + +1F077 +DOMINO TILE VERTICAL-02-06 + +1F078 +DOMINO TILE VERTICAL-03-00 + +1F079 +DOMINO TILE VERTICAL-03-01 + +1F07A +DOMINO TILE VERTICAL-03-02 + +1F07B +DOMINO TILE VERTICAL-03-03 + +1F07C +DOMINO TILE VERTICAL-03-04 + +1F07D +DOMINO TILE VERTICAL-03-05 + +1F07E +DOMINO TILE VERTICAL-03-06 + +1F07F +DOMINO TILE VERTICAL-04-00 + +1F080 +DOMINO TILE VERTICAL-04-01 + +1F081 +DOMINO TILE VERTICAL-04-02 + +1F082 +DOMINO TILE VERTICAL-04-03 + +1F083 +DOMINO TILE VERTICAL-04-04 + +1F084 +DOMINO TILE VERTICAL-04-05 + +1F085 +DOMINO TILE VERTICAL-04-06 + +1F086 +DOMINO TILE VERTICAL-05-00 + +1F087 +DOMINO TILE VERTICAL-05-01 + +1F088 +DOMINO TILE VERTICAL-05-02 + +1F089 +DOMINO TILE VERTICAL-05-03 + +1F08A +DOMINO TILE VERTICAL-05-04 + +1F08B +DOMINO TILE VERTICAL-05-05 + +1F08C +DOMINO TILE VERTICAL-05-06 + +1F08D +DOMINO TILE VERTICAL-06-00 + +1F08E +DOMINO TILE VERTICAL-06-01 + +1F08F +DOMINO TILE VERTICAL-06-02 + +1F090 +DOMINO TILE VERTICAL-06-03 + +1F091 +DOMINO TILE VERTICAL-06-04 + +1F092 +DOMINO TILE VERTICAL-06-05 + +1F093 +DOMINO TILE VERTICAL-06-06 + +1F0A0 +PLAYING CARD BACK + +1F0A1 +PLAYING CARD ACE OF SPADES + +1F0A2 +PLAYING CARD TWO OF SPADES + +1F0A3 +PLAYING CARD THREE OF SPADES + +1F0A4 +PLAYING CARD FOUR OF SPADES + +1F0A5 +PLAYING CARD FIVE OF SPADES + +1F0A6 +PLAYING CARD SIX OF SPADES + +1F0A7 +PLAYING CARD SEVEN OF SPADES + +1F0A8 +PLAYING CARD EIGHT OF SPADES + +1F0A9 +PLAYING CARD NINE OF SPADES + +1F0AA +PLAYING CARD TEN OF SPADES + +1F0AB +PLAYING CARD JACK OF SPADES + +1F0AC +PLAYING CARD KNIGHT OF SPADES + +1F0AD +PLAYING CARD QUEEN OF SPADES + +1F0AE +PLAYING CARD KING OF SPADES + +1F0B1 +PLAYING CARD ACE OF HEARTS + +1F0B2 +PLAYING CARD TWO OF HEARTS + +1F0B3 +PLAYING CARD THREE OF HEARTS + +1F0B4 +PLAYING CARD FOUR OF HEARTS + +1F0B5 +PLAYING CARD FIVE OF HEARTS + +1F0B6 +PLAYING CARD SIX OF HEARTS + +1F0B7 +PLAYING CARD SEVEN OF HEARTS + +1F0B8 +PLAYING CARD EIGHT OF HEARTS + +1F0B9 +PLAYING CARD NINE OF HEARTS + +1F0BA +PLAYING CARD TEN OF HEARTS + +1F0BB +PLAYING CARD JACK OF HEARTS + +1F0BC +PLAYING CARD KNIGHT OF HEARTS + +1F0BD +PLAYING CARD QUEEN OF HEARTS + +1F0BE +PLAYING CARD KING OF HEARTS + +1F0BF +PLAYING CARD RED JOKER + +1F0C1 +PLAYING CARD ACE OF DIAMONDS + +1F0C2 +PLAYING CARD TWO OF DIAMONDS + +1F0C3 +PLAYING CARD THREE OF DIAMONDS + +1F0C4 +PLAYING CARD FOUR OF DIAMONDS + +1F0C5 +PLAYING CARD FIVE OF DIAMONDS + +1F0C6 +PLAYING CARD SIX OF DIAMONDS + +1F0C7 +PLAYING CARD SEVEN OF DIAMONDS + +1F0C8 +PLAYING CARD EIGHT OF DIAMONDS + +1F0C9 +PLAYING CARD NINE OF DIAMONDS + +1F0CA +PLAYING CARD TEN OF DIAMONDS + +1F0CB +PLAYING CARD JACK OF DIAMONDS + +1F0CC +PLAYING CARD KNIGHT OF DIAMONDS + +1F0CD +PLAYING CARD QUEEN OF DIAMONDS + +1F0CE +PLAYING CARD KING OF DIAMONDS + +1F0CF +PLAYING CARD BLACK JOKER + +1F0D1 +PLAYING CARD ACE OF CLUBS + +1F0D2 +PLAYING CARD TWO OF CLUBS + +1F0D3 +PLAYING CARD THREE OF CLUBS + +1F0D4 +PLAYING CARD FOUR OF CLUBS + +1F0D5 +PLAYING CARD FIVE OF CLUBS + +1F0D6 +PLAYING CARD SIX OF CLUBS + +1F0D7 +PLAYING CARD SEVEN OF CLUBS + +1F0D8 +PLAYING CARD EIGHT OF CLUBS + +1F0D9 +PLAYING CARD NINE OF CLUBS + +1F0DA +PLAYING CARD TEN OF CLUBS + +1F0DB +PLAYING CARD JACK OF CLUBS + +1F0DC +PLAYING CARD KNIGHT OF CLUBS + +1F0DD +PLAYING CARD QUEEN OF CLUBS + +1F0DE +PLAYING CARD KING OF CLUBS + +1F0DF +PLAYING CARD WHITE JOKER + +1F0E0 +PLAYING CARD FOOL + +1F0E1 +PLAYING CARD TRUMP-1 + +1F0E2 +PLAYING CARD TRUMP-2 + +1F0E3 +PLAYING CARD TRUMP-3 + +1F0E4 +PLAYING CARD TRUMP-4 + +1F0E5 +PLAYING CARD TRUMP-5 + +1F0E6 +PLAYING CARD TRUMP-6 + +1F0E7 +PLAYING CARD TRUMP-7 + +1F0E8 +PLAYING CARD TRUMP-8 + +1F0E9 +PLAYING CARD TRUMP-9 + +1F0EA +PLAYING CARD TRUMP-10 + +1F0EB +PLAYING CARD TRUMP-11 + +1F0EC +PLAYING CARD TRUMP-12 + +1F0ED +PLAYING CARD TRUMP-13 + +1F0EE +PLAYING CARD TRUMP-14 + +1F0EF +PLAYING CARD TRUMP-15 + +1F0F0 +PLAYING CARD TRUMP-16 + +1F0F1 +PLAYING CARD TRUMP-17 + +1F0F2 +PLAYING CARD TRUMP-18 + +1F0F3 +PLAYING CARD TRUMP-19 + +1F0F4 +PLAYING CARD TRUMP-20 + +1F0F5 +PLAYING CARD TRUMP-21 + +1F100 +DIGIT ZERO FULL STOP + +1F101 +DIGIT ZERO COMMA + +1F102 +DIGIT ONE COMMA + +1F103 +DIGIT TWO COMMA + +1F104 +DIGIT THREE COMMA + +1F105 +DIGIT FOUR COMMA + +1F106 +DIGIT FIVE COMMA + +1F107 +DIGIT SIX COMMA + +1F108 +DIGIT SEVEN COMMA + +1F109 +DIGIT EIGHT COMMA + +1F10A +DIGIT NINE COMMA + +1F10B +DINGBAT CIRCLED SANS-SERIF DIGIT ZERO + +1F10C +DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ZERO + +1F10D +CIRCLED ZERO WITH SLASH + +1F10E +CIRCLED ANTICLOCKWISE ARROW + +1F10F +CIRCLED DOLLAR SIGN WITH OVERLAID BACKSLASH + +1F110 +PARENTHESIZED LATIN CAPITAL LETTER A + +1F111 +PARENTHESIZED LATIN CAPITAL LETTER B + +1F112 +PARENTHESIZED LATIN CAPITAL LETTER C + +1F113 +PARENTHESIZED LATIN CAPITAL LETTER D + +1F114 +PARENTHESIZED LATIN CAPITAL LETTER E + +1F115 +PARENTHESIZED LATIN CAPITAL LETTER F + +1F116 +PARENTHESIZED LATIN CAPITAL LETTER G + +1F117 +PARENTHESIZED LATIN CAPITAL LETTER H + +1F118 +PARENTHESIZED LATIN CAPITAL LETTER I + +1F119 +PARENTHESIZED LATIN CAPITAL LETTER J + +1F11A +PARENTHESIZED LATIN CAPITAL LETTER K + +1F11B +PARENTHESIZED LATIN CAPITAL LETTER L + +1F11C +PARENTHESIZED LATIN CAPITAL LETTER M + +1F11D +PARENTHESIZED LATIN CAPITAL LETTER N + +1F11E +PARENTHESIZED LATIN CAPITAL LETTER O + +1F11F +PARENTHESIZED LATIN CAPITAL LETTER P + +1F120 +PARENTHESIZED LATIN CAPITAL LETTER Q + +1F121 +PARENTHESIZED LATIN CAPITAL LETTER R + +1F122 +PARENTHESIZED LATIN CAPITAL LETTER S + +1F123 +PARENTHESIZED LATIN CAPITAL LETTER T + +1F124 +PARENTHESIZED LATIN CAPITAL LETTER U + +1F125 +PARENTHESIZED LATIN CAPITAL LETTER V + +1F126 +PARENTHESIZED LATIN CAPITAL LETTER W + +1F127 +PARENTHESIZED LATIN CAPITAL LETTER X + +1F128 +PARENTHESIZED LATIN CAPITAL LETTER Y + +1F129 +PARENTHESIZED LATIN CAPITAL LETTER Z + +1F12A +TORTOISE SHELL BRACKETED LATIN CAPITAL LETTER S + +1F12B +CIRCLED ITALIC LATIN CAPITAL LETTER C + +1F12C +CIRCLED ITALIC LATIN CAPITAL LETTER R + +1F12D +CIRCLED CD + +1F12E +CIRCLED WZ + +1F12F +COPYLEFT SYMBOL + +1F130 +SQUARED LATIN CAPITAL LETTER A + +1F131 +SQUARED LATIN CAPITAL LETTER B + +1F132 +SQUARED LATIN CAPITAL LETTER C + +1F133 +SQUARED LATIN CAPITAL LETTER D + +1F134 +SQUARED LATIN CAPITAL LETTER E + +1F135 +SQUARED LATIN CAPITAL LETTER F + +1F136 +SQUARED LATIN CAPITAL LETTER G + +1F137 +SQUARED LATIN CAPITAL LETTER H + +1F138 +SQUARED LATIN CAPITAL LETTER I + +1F139 +SQUARED LATIN CAPITAL LETTER J + +1F13A +SQUARED LATIN CAPITAL LETTER K + +1F13B +SQUARED LATIN CAPITAL LETTER L + +1F13C +SQUARED LATIN CAPITAL LETTER M + +1F13D +SQUARED LATIN CAPITAL LETTER N + +1F13E +SQUARED LATIN CAPITAL LETTER O + +1F13F +SQUARED LATIN CAPITAL LETTER P + +1F140 +SQUARED LATIN CAPITAL LETTER Q + +1F141 +SQUARED LATIN CAPITAL LETTER R + +1F142 +SQUARED LATIN CAPITAL LETTER S + +1F143 +SQUARED LATIN CAPITAL LETTER T + +1F144 +SQUARED LATIN CAPITAL LETTER U + +1F145 +SQUARED LATIN CAPITAL LETTER V + +1F146 +SQUARED LATIN CAPITAL LETTER W + +1F147 +SQUARED LATIN CAPITAL LETTER X + +1F148 +SQUARED LATIN CAPITAL LETTER Y + +1F149 +SQUARED LATIN CAPITAL LETTER Z + +1F14A +SQUARED HV + +1F14B +SQUARED MV + +1F14C +SQUARED SD + +1F14D +SQUARED SS + +1F14E +SQUARED PPV + +1F14F +SQUARED WC + +1F150 +NEGATIVE CIRCLED LATIN CAPITAL LETTER A + +1F151 +NEGATIVE CIRCLED LATIN CAPITAL LETTER B + +1F152 +NEGATIVE CIRCLED LATIN CAPITAL LETTER C + +1F153 +NEGATIVE CIRCLED LATIN CAPITAL LETTER D + +1F154 +NEGATIVE CIRCLED LATIN CAPITAL LETTER E + +1F155 +NEGATIVE CIRCLED LATIN CAPITAL LETTER F + +1F156 +NEGATIVE CIRCLED LATIN CAPITAL LETTER G + +1F157 +NEGATIVE CIRCLED LATIN CAPITAL LETTER H + +1F158 +NEGATIVE CIRCLED LATIN CAPITAL LETTER I + +1F159 +NEGATIVE CIRCLED LATIN CAPITAL LETTER J + +1F15A +NEGATIVE CIRCLED LATIN CAPITAL LETTER K + +1F15B +NEGATIVE CIRCLED LATIN CAPITAL LETTER L + +1F15C +NEGATIVE CIRCLED LATIN CAPITAL LETTER M + +1F15D +NEGATIVE CIRCLED LATIN CAPITAL LETTER N + +1F15E +NEGATIVE CIRCLED LATIN CAPITAL LETTER O + +1F15F +NEGATIVE CIRCLED LATIN CAPITAL LETTER P + +1F160 +NEGATIVE CIRCLED LATIN CAPITAL LETTER Q + +1F161 +NEGATIVE CIRCLED LATIN CAPITAL LETTER R + +1F162 +NEGATIVE CIRCLED LATIN CAPITAL LETTER S + +1F163 +NEGATIVE CIRCLED LATIN CAPITAL LETTER T + +1F164 +NEGATIVE CIRCLED LATIN CAPITAL LETTER U + +1F165 +NEGATIVE CIRCLED LATIN CAPITAL LETTER V + +1F166 +NEGATIVE CIRCLED LATIN CAPITAL LETTER W + +1F167 +NEGATIVE CIRCLED LATIN CAPITAL LETTER X + +1F168 +NEGATIVE CIRCLED LATIN CAPITAL LETTER Y + +1F169 +NEGATIVE CIRCLED LATIN CAPITAL LETTER Z + +1F16A +RAISED MC SIGN + +1F16B +RAISED MD SIGN + +1F16C +RAISED MR SIGN + +1F16D +CIRCLED CC + +1F16E +CIRCLED C WITH OVERLAID BACKSLASH + +1F16F +CIRCLED HUMAN FIGURE + +1F170 +NEGATIVE SQUARED LATIN CAPITAL LETTER A + +1F171 +NEGATIVE SQUARED LATIN CAPITAL LETTER B + +1F172 +NEGATIVE SQUARED LATIN CAPITAL LETTER C + +1F173 +NEGATIVE SQUARED LATIN CAPITAL LETTER D + +1F174 +NEGATIVE SQUARED LATIN CAPITAL LETTER E + +1F175 +NEGATIVE SQUARED LATIN CAPITAL LETTER F + +1F176 +NEGATIVE SQUARED LATIN CAPITAL LETTER G + +1F177 +NEGATIVE SQUARED LATIN CAPITAL LETTER H + +1F178 +NEGATIVE SQUARED LATIN CAPITAL LETTER I + +1F179 +NEGATIVE SQUARED LATIN CAPITAL LETTER J + +1F17A +NEGATIVE SQUARED LATIN CAPITAL LETTER K + +1F17B +NEGATIVE SQUARED LATIN CAPITAL LETTER L + +1F17C +NEGATIVE SQUARED LATIN CAPITAL LETTER M + +1F17D +NEGATIVE SQUARED LATIN CAPITAL LETTER N + +1F17E +NEGATIVE SQUARED LATIN CAPITAL LETTER O + +1F17F +NEGATIVE SQUARED LATIN CAPITAL LETTER P + +1F180 +NEGATIVE SQUARED LATIN CAPITAL LETTER Q + +1F181 +NEGATIVE SQUARED LATIN CAPITAL LETTER R + +1F182 +NEGATIVE SQUARED LATIN CAPITAL LETTER S + +1F183 +NEGATIVE SQUARED LATIN CAPITAL LETTER T + +1F184 +NEGATIVE SQUARED LATIN CAPITAL LETTER U + +1F185 +NEGATIVE SQUARED LATIN CAPITAL LETTER V + +1F186 +NEGATIVE SQUARED LATIN CAPITAL LETTER W + +1F187 +NEGATIVE SQUARED LATIN CAPITAL LETTER X + +1F188 +NEGATIVE SQUARED LATIN CAPITAL LETTER Y + +1F189 +NEGATIVE SQUARED LATIN CAPITAL LETTER Z + +1F18A +CROSSED NEGATIVE SQUARED LATIN CAPITAL LETTER P + +1F18B +NEGATIVE SQUARED IC + +1F18C +NEGATIVE SQUARED PA + +1F18D +NEGATIVE SQUARED SA + +1F18E +NEGATIVE SQUARED AB + +1F18F +NEGATIVE SQUARED WC + +1F190 +SQUARE DJ + +1F191 +SQUARED CL + +1F192 +SQUARED COOL + +1F193 +SQUARED FREE + +1F194 +SQUARED ID + +1F195 +SQUARED NEW + +1F196 +SQUARED NG + +1F197 +SQUARED OK + +1F198 +SQUARED SOS + +1F199 +SQUARED UP WITH EXCLAMATION MARK + +1F19A +SQUARED VS + +1F19B +SQUARED THREE D + +1F19C +SQUARED SECOND SCREEN + +1F19D +SQUARED TWO K + +1F19E +SQUARED FOUR K + +1F19F +SQUARED EIGHT K + +1F1A0 +SQUARED FIVE POINT ONE + +1F1A1 +SQUARED SEVEN POINT ONE + +1F1A2 +SQUARED TWENTY-TWO POINT TWO + +1F1A3 +SQUARED SIXTY P + +1F1A4 +SQUARED ONE HUNDRED TWENTY P + +1F1A5 +SQUARED LATIN SMALL LETTER D + +1F1A6 +SQUARED HC + +1F1A7 +SQUARED HDR + +1F1A8 +SQUARED HI-RES + +1F1A9 +SQUARED LOSSLESS + +1F1AA +SQUARED SHV + +1F1AB +SQUARED UHD + +1F1AC +SQUARED VOD + +1F1AD +MASK WORK SYMBOL + +1F1E6 +REGIONAL INDICATOR SYMBOL LETTER A + +1F1E7 +REGIONAL INDICATOR SYMBOL LETTER B + +1F1E8 +REGIONAL INDICATOR SYMBOL LETTER C + +1F1E9 +REGIONAL INDICATOR SYMBOL LETTER D + +1F1EA +REGIONAL INDICATOR SYMBOL LETTER E + +1F1EB +REGIONAL INDICATOR SYMBOL LETTER F + +1F1EC +REGIONAL INDICATOR SYMBOL LETTER G + +1F1ED +REGIONAL INDICATOR SYMBOL LETTER H + +1F1EE +REGIONAL INDICATOR SYMBOL LETTER I + +1F1EF +REGIONAL INDICATOR SYMBOL LETTER J + +1F1F0 +REGIONAL INDICATOR SYMBOL LETTER K + +1F1F1 +REGIONAL INDICATOR SYMBOL LETTER L + +1F1F2 +REGIONAL INDICATOR SYMBOL LETTER M + +1F1F3 +REGIONAL INDICATOR SYMBOL LETTER N + +1F1F4 +REGIONAL INDICATOR SYMBOL LETTER O + +1F1F5 +REGIONAL INDICATOR SYMBOL LETTER P + +1F1F6 +REGIONAL INDICATOR SYMBOL LETTER Q + +1F1F7 +REGIONAL INDICATOR SYMBOL LETTER R + +1F1F8 +REGIONAL INDICATOR SYMBOL LETTER S + +1F1F9 +REGIONAL INDICATOR SYMBOL LETTER T + +1F1FA +REGIONAL INDICATOR SYMBOL LETTER U + +1F1FB +REGIONAL INDICATOR SYMBOL LETTER V + +1F1FC +REGIONAL INDICATOR SYMBOL LETTER W + +1F1FD +REGIONAL INDICATOR SYMBOL LETTER X + +1F1FE +REGIONAL INDICATOR SYMBOL LETTER Y + +1F1FF +REGIONAL INDICATOR SYMBOL LETTER Z + +1F200 +SQUARE HIRAGANA HOKA + +1F201 +SQUARED KATAKANA KOKO + +1F202 +SQUARED KATAKANA SA + +1F210 +SQUARED CJK UNIFIED IDEOGRAPH-624B + +1F211 +SQUARED CJK UNIFIED IDEOGRAPH-5B57 + +1F212 +SQUARED CJK UNIFIED IDEOGRAPH-53CC + +1F213 +SQUARED KATAKANA DE + +1F214 +SQUARED CJK UNIFIED IDEOGRAPH-4E8C + +1F215 +SQUARED CJK UNIFIED IDEOGRAPH-591A + +1F216 +SQUARED CJK UNIFIED IDEOGRAPH-89E3 + +1F217 +SQUARED CJK UNIFIED IDEOGRAPH-5929 + +1F218 +SQUARED CJK UNIFIED IDEOGRAPH-4EA4 + +1F219 +SQUARED CJK UNIFIED IDEOGRAPH-6620 + +1F21A +SQUARED CJK UNIFIED IDEOGRAPH-7121 + +1F21B +SQUARED CJK UNIFIED IDEOGRAPH-6599 + +1F21C +SQUARED CJK UNIFIED IDEOGRAPH-524D + +1F21D +SQUARED CJK UNIFIED IDEOGRAPH-5F8C + +1F21E +SQUARED CJK UNIFIED IDEOGRAPH-518D + +1F21F +SQUARED CJK UNIFIED IDEOGRAPH-65B0 + +1F220 +SQUARED CJK UNIFIED IDEOGRAPH-521D + +1F221 +SQUARED CJK UNIFIED IDEOGRAPH-7D42 + +1F222 +SQUARED CJK UNIFIED IDEOGRAPH-751F + +1F223 +SQUARED CJK UNIFIED IDEOGRAPH-8CA9 + +1F224 +SQUARED CJK UNIFIED IDEOGRAPH-58F0 + +1F225 +SQUARED CJK UNIFIED IDEOGRAPH-5439 + +1F226 +SQUARED CJK UNIFIED IDEOGRAPH-6F14 + +1F227 +SQUARED CJK UNIFIED IDEOGRAPH-6295 + +1F228 +SQUARED CJK UNIFIED IDEOGRAPH-6355 + +1F229 +SQUARED CJK UNIFIED IDEOGRAPH-4E00 + +1F22A +SQUARED CJK UNIFIED IDEOGRAPH-4E09 + +1F22B +SQUARED CJK UNIFIED IDEOGRAPH-904A + +1F22C +SQUARED CJK UNIFIED IDEOGRAPH-5DE6 + +1F22D +SQUARED CJK UNIFIED IDEOGRAPH-4E2D + +1F22E +SQUARED CJK UNIFIED IDEOGRAPH-53F3 + +1F22F +SQUARED CJK UNIFIED IDEOGRAPH-6307 + +1F230 +SQUARED CJK UNIFIED IDEOGRAPH-8D70 + +1F231 +SQUARED CJK UNIFIED IDEOGRAPH-6253 + +1F232 +SQUARED CJK UNIFIED IDEOGRAPH-7981 + +1F233 +SQUARED CJK UNIFIED IDEOGRAPH-7A7A + +1F234 +SQUARED CJK UNIFIED IDEOGRAPH-5408 + +1F235 +SQUARED CJK UNIFIED IDEOGRAPH-6E80 + +1F236 +SQUARED CJK UNIFIED IDEOGRAPH-6709 + +1F237 +SQUARED CJK UNIFIED IDEOGRAPH-6708 + +1F238 +SQUARED CJK UNIFIED IDEOGRAPH-7533 + +1F239 +SQUARED CJK UNIFIED IDEOGRAPH-5272 + +1F23A +SQUARED CJK UNIFIED IDEOGRAPH-55B6 + +1F23B +SQUARED CJK UNIFIED IDEOGRAPH-914D + +1F240 +TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672C + +1F241 +TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-4E09 + +1F242 +TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-4E8C + +1F243 +TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-5B89 + +1F244 +TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-70B9 + +1F245 +TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6253 + +1F246 +TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-76D7 + +1F247 +TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-52DD + +1F248 +TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557 + +1F250 +CIRCLED IDEOGRAPH ADVANTAGE + +1F251 +CIRCLED IDEOGRAPH ACCEPT + +1F260 +ROUNDED SYMBOL FOR FU + +1F261 +ROUNDED SYMBOL FOR LU + +1F262 +ROUNDED SYMBOL FOR SHOU + +1F263 +ROUNDED SYMBOL FOR XI + +1F264 +ROUNDED SYMBOL FOR SHUANGXI + +1F265 +ROUNDED SYMBOL FOR CAI + +1F300 +CYCLONE + +1F301 +FOGGY + +1F302 +CLOSED UMBRELLA + +1F303 +NIGHT WITH STARS + +1F304 +SUNRISE OVER MOUNTAINS + +1F305 +SUNRISE + +1F306 +CITYSCAPE AT DUSK + +1F307 +SUNSET OVER BUILDINGS + +1F308 +RAINBOW + +1F309 +BRIDGE AT NIGHT + +1F30A +WATER WAVE + +1F30B +VOLCANO + +1F30C +MILKY WAY + +1F30D +EARTH GLOBE EUROPE-AFRICA + +1F30E +EARTH GLOBE AMERICAS + +1F30F +EARTH GLOBE ASIA-AUSTRALIA + +1F310 +GLOBE WITH MERIDIANS + +1F311 +NEW MOON SYMBOL + +1F312 +WAXING CRESCENT MOON SYMBOL + +1F313 +FIRST QUARTER MOON SYMBOL + +1F314 +WAXING GIBBOUS MOON SYMBOL + +1F315 +FULL MOON SYMBOL + +1F316 +WANING GIBBOUS MOON SYMBOL + +1F317 +LAST QUARTER MOON SYMBOL + +1F318 +WANING CRESCENT MOON SYMBOL + +1F319 +CRESCENT MOON + +1F31A +NEW MOON WITH FACE + +1F31B +FIRST QUARTER MOON WITH FACE + +1F31C +LAST QUARTER MOON WITH FACE + +1F31D +FULL MOON WITH FACE + +1F31E +SUN WITH FACE + +1F31F +GLOWING STAR + +1F320 +SHOOTING STAR + +1F321 +THERMOMETER + +1F322 +BLACK DROPLET + +1F323 +WHITE SUN + +1F324 +WHITE SUN WITH SMALL CLOUD + +1F325 +WHITE SUN BEHIND CLOUD + +1F326 +WHITE SUN BEHIND CLOUD WITH RAIN + +1F327 +CLOUD WITH RAIN + +1F328 +CLOUD WITH SNOW + +1F329 +CLOUD WITH LIGHTNING + +1F32A +CLOUD WITH TORNADO + +1F32B +FOG + +1F32C +WIND BLOWING FACE + +1F32D +HOT DOG + +1F32E +TACO + +1F32F +BURRITO + +1F330 +CHESTNUT + +1F331 +SEEDLING + +1F332 +EVERGREEN TREE + +1F333 +DECIDUOUS TREE + +1F334 +PALM TREE + +1F335 +CACTUS + +1F336 +HOT PEPPER + +1F337 +TULIP + +1F338 +CHERRY BLOSSOM + +1F339 +ROSE + +1F33A +HIBISCUS + +1F33B +SUNFLOWER + +1F33C +BLOSSOM + +1F33D +EAR OF MAIZE + +1F33E +EAR OF RICE + +1F33F +HERB + +1F340 +FOUR LEAF CLOVER + +1F341 +MAPLE LEAF + +1F342 +FALLEN LEAF + +1F343 +LEAF FLUTTERING IN WIND + +1F344 +MUSHROOM + +1F345 +TOMATO + +1F346 +AUBERGINE + +1F347 +GRAPES + +1F348 +MELON + +1F349 +WATERMELON + +1F34A +TANGERINE + +1F34B +LEMON + +1F34C +BANANA + +1F34D +PINEAPPLE + +1F34E +RED APPLE + +1F34F +GREEN APPLE + +1F350 +PEAR + +1F351 +PEACH + +1F352 +CHERRIES + +1F353 +STRAWBERRY + +1F354 +HAMBURGER + +1F355 +SLICE OF PIZZA + +1F356 +MEAT ON BONE + +1F357 +POULTRY LEG + +1F358 +RICE CRACKER + +1F359 +RICE BALL + +1F35A +COOKED RICE + +1F35B +CURRY AND RICE + +1F35C +STEAMING BOWL + +1F35D +SPAGHETTI + +1F35E +BREAD + +1F35F +FRENCH FRIES + +1F360 +ROASTED SWEET POTATO + +1F361 +DANGO + +1F362 +ODEN + +1F363 +SUSHI + +1F364 +FRIED SHRIMP + +1F365 +FISH CAKE WITH SWIRL DESIGN + +1F366 +SOFT ICE CREAM + +1F367 +SHAVED ICE + +1F368 +ICE CREAM + +1F369 +DOUGHNUT + +1F36A +COOKIE + +1F36B +CHOCOLATE BAR + +1F36C +CANDY + +1F36D +LOLLIPOP + +1F36E +CUSTARD + +1F36F +HONEY POT + +1F370 +SHORTCAKE + +1F371 +BENTO BOX + +1F372 +POT OF FOOD + +1F373 +COOKING + +1F374 +FORK AND KNIFE + +1F375 +TEACUP WITHOUT HANDLE + +1F376 +SAKE BOTTLE AND CUP + +1F377 +WINE GLASS + +1F378 +COCKTAIL GLASS + +1F379 +TROPICAL DRINK + +1F37A +BEER MUG + +1F37B +CLINKING BEER MUGS + +1F37C +BABY BOTTLE + +1F37D +FORK AND KNIFE WITH PLATE + +1F37E +BOTTLE WITH POPPING CORK + +1F37F +POPCORN + +1F380 +RIBBON + +1F381 +WRAPPED PRESENT + +1F382 +BIRTHDAY CAKE + +1F383 +JACK-O-LANTERN + +1F384 +CHRISTMAS TREE + +1F385 +FATHER CHRISTMAS + +1F386 +FIREWORKS + +1F387 +FIREWORK SPARKLER + +1F388 +BALLOON + +1F389 +PARTY POPPER + +1F38A +CONFETTI BALL + +1F38B +TANABATA TREE + +1F38C +CROSSED FLAGS + +1F38D +PINE DECORATION + +1F38E +JAPANESE DOLLS + +1F38F +CARP STREAMER + +1F390 +WIND CHIME + +1F391 +MOON VIEWING CEREMONY + +1F392 +SCHOOL SATCHEL + +1F393 +GRADUATION CAP + +1F394 +HEART WITH TIP ON THE LEFT + +1F395 +BOUQUET OF FLOWERS + +1F396 +MILITARY MEDAL + +1F397 +REMINDER RIBBON + +1F398 +MUSICAL KEYBOARD WITH JACKS + +1F399 +STUDIO MICROPHONE + +1F39A +LEVEL SLIDER + +1F39B +CONTROL KNOBS + +1F39C +BEAMED ASCENDING MUSICAL NOTES + +1F39D +BEAMED DESCENDING MUSICAL NOTES + +1F39E +FILM FRAMES + +1F39F +ADMISSION TICKETS + +1F3A0 +CAROUSEL HORSE + +1F3A1 +FERRIS WHEEL + +1F3A2 +ROLLER COASTER + +1F3A3 +FISHING POLE AND FISH + +1F3A4 +MICROPHONE + +1F3A5 +MOVIE CAMERA + +1F3A6 +CINEMA + +1F3A7 +HEADPHONE + +1F3A8 +ARTIST PALETTE + +1F3A9 +TOP HAT + +1F3AA +CIRCUS TENT + +1F3AB +TICKET + +1F3AC +CLAPPER BOARD + +1F3AD +PERFORMING ARTS + +1F3AE +VIDEO GAME + +1F3AF +DIRECT HIT + +1F3B0 +SLOT MACHINE + +1F3B1 +BILLIARDS + +1F3B2 +GAME DIE + +1F3B3 +BOWLING + +1F3B4 +FLOWER PLAYING CARDS + +1F3B5 +MUSICAL NOTE + +1F3B6 +MULTIPLE MUSICAL NOTES + +1F3B7 +SAXOPHONE + +1F3B8 +GUITAR + +1F3B9 +MUSICAL KEYBOARD + +1F3BA +TRUMPET + +1F3BB +VIOLIN + +1F3BC +MUSICAL SCORE + +1F3BD +RUNNING SHIRT WITH SASH + +1F3BE +TENNIS RACQUET AND BALL + +1F3BF +SKI AND SKI BOOT + +1F3C0 +BASKETBALL AND HOOP + +1F3C1 +CHEQUERED FLAG + +1F3C2 +SNOWBOARDER + +1F3C3 +RUNNER + +1F3C4 +SURFER + +1F3C5 +SPORTS MEDAL + +1F3C6 +TROPHY + +1F3C7 +HORSE RACING + +1F3C8 +AMERICAN FOOTBALL + +1F3C9 +RUGBY FOOTBALL + +1F3CA +SWIMMER + +1F3CB +WEIGHT LIFTER + +1F3CC +GOLFER + +1F3CD +RACING MOTORCYCLE + +1F3CE +RACING CAR + +1F3CF +CRICKET BAT AND BALL + +1F3D0 +VOLLEYBALL + +1F3D1 +FIELD HOCKEY STICK AND BALL + +1F3D2 +ICE HOCKEY STICK AND PUCK + +1F3D3 +TABLE TENNIS PADDLE AND BALL + +1F3D4 +SNOW CAPPED MOUNTAIN + +1F3D5 +CAMPING + +1F3D6 +BEACH WITH UMBRELLA + +1F3D7 +BUILDING CONSTRUCTION + +1F3D8 +HOUSE BUILDINGS + +1F3D9 +CITYSCAPE + +1F3DA +DERELICT HOUSE BUILDING + +1F3DB +CLASSICAL BUILDING + +1F3DC +DESERT + +1F3DD +DESERT ISLAND + +1F3DE +NATIONAL PARK + +1F3DF +STADIUM + +1F3E0 +HOUSE BUILDING + +1F3E1 +HOUSE WITH GARDEN + +1F3E2 +OFFICE BUILDING + +1F3E3 +JAPANESE POST OFFICE + +1F3E4 +EUROPEAN POST OFFICE + +1F3E5 +HOSPITAL + +1F3E6 +BANK + +1F3E7 +AUTOMATED TELLER MACHINE + +1F3E8 +HOTEL + +1F3E9 +LOVE HOTEL + +1F3EA +CONVENIENCE STORE + +1F3EB +SCHOOL + +1F3EC +DEPARTMENT STORE + +1F3ED +FACTORY + +1F3EE +IZAKAYA LANTERN + +1F3EF +JAPANESE CASTLE + +1F3F0 +EUROPEAN CASTLE + +1F3F1 +WHITE PENNANT + +1F3F2 +BLACK PENNANT + +1F3F3 +WAVING WHITE FLAG + +1F3F4 +WAVING BLACK FLAG + +1F3F5 +ROSETTE + +1F3F6 +BLACK ROSETTE + +1F3F7 +LABEL + +1F3F8 +BADMINTON RACQUET AND SHUTTLECOCK + +1F3F9 +BOW AND ARROW + +1F3FA +AMPHORA + +1F3FB +EMOJI MODIFIER FITZPATRICK TYPE-1-2 + +1F3FC +EMOJI MODIFIER FITZPATRICK TYPE-3 + +1F3FD +EMOJI MODIFIER FITZPATRICK TYPE-4 + +1F3FE +EMOJI MODIFIER FITZPATRICK TYPE-5 + +1F3FF +EMOJI MODIFIER FITZPATRICK TYPE-6 + +1F400 +RAT + +1F401 +MOUSE + +1F402 +OX + +1F403 +WATER BUFFALO + +1F404 +COW + +1F405 +TIGER + +1F406 +LEOPARD + +1F407 +RABBIT + +1F408 +CAT + +1F409 +DRAGON + +1F40A +CROCODILE + +1F40B +WHALE + +1F40C +SNAIL + +1F40D +SNAKE + +1F40E +HORSE + +1F40F +RAM + +1F410 +GOAT + +1F411 +SHEEP + +1F412 +MONKEY + +1F413 +ROOSTER + +1F414 +CHICKEN + +1F415 +DOG + +1F416 +PIG + +1F417 +BOAR + +1F418 +ELEPHANT + +1F419 +OCTOPUS + +1F41A +SPIRAL SHELL + +1F41B +BUG + +1F41C +ANT + +1F41D +HONEYBEE + +1F41E +LADY BEETLE + +1F41F +FISH + +1F420 +TROPICAL FISH + +1F421 +BLOWFISH + +1F422 +TURTLE + +1F423 +HATCHING CHICK + +1F424 +BABY CHICK + +1F425 +FRONT-FACING BABY CHICK + +1F426 +BIRD + +1F427 +PENGUIN + +1F428 +KOALA + +1F429 +POODLE + +1F42A +DROMEDARY CAMEL + +1F42B +BACTRIAN CAMEL + +1F42C +DOLPHIN + +1F42D +MOUSE FACE + +1F42E +COW FACE + +1F42F +TIGER FACE + +1F430 +RABBIT FACE + +1F431 +CAT FACE + +1F432 +DRAGON FACE + +1F433 +SPOUTING WHALE + +1F434 +HORSE FACE + +1F435 +MONKEY FACE + +1F436 +DOG FACE + +1F437 +PIG FACE + +1F438 +FROG FACE + +1F439 +HAMSTER FACE + +1F43A +WOLF FACE + +1F43B +BEAR FACE + +1F43C +PANDA FACE + +1F43D +PIG NOSE + +1F43E +PAW PRINTS + +1F43F +CHIPMUNK + +1F440 +EYES + +1F441 +EYE + +1F442 +EAR + +1F443 +NOSE + +1F444 +MOUTH + +1F445 +TONGUE + +1F446 +WHITE UP POINTING BACKHAND INDEX + +1F447 +WHITE DOWN POINTING BACKHAND INDEX + +1F448 +WHITE LEFT POINTING BACKHAND INDEX + +1F449 +WHITE RIGHT POINTING BACKHAND INDEX + +1F44A +FISTED HAND SIGN + +1F44B +WAVING HAND SIGN + +1F44C +OK HAND SIGN + +1F44D +THUMBS UP SIGN + +1F44E +THUMBS DOWN SIGN + +1F44F +CLAPPING HANDS SIGN + +1F450 +OPEN HANDS SIGN + +1F451 +CROWN + +1F452 +WOMANS HAT + +1F453 +EYEGLASSES + +1F454 +NECKTIE + +1F455 +T-SHIRT + +1F456 +JEANS + +1F457 +DRESS + +1F458 +KIMONO + +1F459 +BIKINI + +1F45A +WOMANS CLOTHES + +1F45B +PURSE + +1F45C +HANDBAG + +1F45D +POUCH + +1F45E +MANS SHOE + +1F45F +ATHLETIC SHOE + +1F460 +HIGH-HEELED SHOE + +1F461 +WOMANS SANDAL + +1F462 +WOMANS BOOTS + +1F463 +FOOTPRINTS + +1F464 +BUST IN SILHOUETTE + +1F465 +BUSTS IN SILHOUETTE + +1F466 +BOY + +1F467 +GIRL + +1F468 +MAN + +1F469 +WOMAN + +1F46A +FAMILY + +1F46B +MAN AND WOMAN HOLDING HANDS + +1F46C +TWO MEN HOLDING HANDS + +1F46D +TWO WOMEN HOLDING HANDS + +1F46E +POLICE OFFICER + +1F46F +WOMAN WITH BUNNY EARS + +1F470 +BRIDE WITH VEIL + +1F471 +PERSON WITH BLOND HAIR + +1F472 +MAN WITH GUA PI MAO + +1F473 +MAN WITH TURBAN + +1F474 +OLDER MAN + +1F475 +OLDER WOMAN + +1F476 +BABY + +1F477 +CONSTRUCTION WORKER + +1F478 +PRINCESS + +1F479 +JAPANESE OGRE + +1F47A +JAPANESE GOBLIN + +1F47B +GHOST + +1F47C +BABY ANGEL + +1F47D +EXTRATERRESTRIAL ALIEN + +1F47E +ALIEN MONSTER + +1F47F +IMP + +1F480 +SKULL + +1F481 +INFORMATION DESK PERSON + +1F482 +GUARDSMAN + +1F483 +DANCER + +1F484 +LIPSTICK + +1F485 +NAIL POLISH + +1F486 +FACE MASSAGE + +1F487 +HAIRCUT + +1F488 +BARBER POLE + +1F489 +SYRINGE + +1F48A +PILL + +1F48B +KISS MARK + +1F48C +LOVE LETTER + +1F48D +RING + +1F48E +GEM STONE + +1F48F +KISS + +1F490 +BOUQUET + +1F491 +COUPLE WITH HEART + +1F492 +WEDDING + +1F493 +BEATING HEART + +1F494 +BROKEN HEART + +1F495 +TWO HEARTS + +1F496 +SPARKLING HEART + +1F497 +GROWING HEART + +1F498 +HEART WITH ARROW + +1F499 +BLUE HEART + +1F49A +GREEN HEART + +1F49B +YELLOW HEART + +1F49C +PURPLE HEART + +1F49D +HEART WITH RIBBON + +1F49E +REVOLVING HEARTS + +1F49F +HEART DECORATION + +1F4A0 +DIAMOND SHAPE WITH A DOT INSIDE + +1F4A1 +ELECTRIC LIGHT BULB + +1F4A2 +ANGER SYMBOL + +1F4A3 +BOMB + +1F4A4 +SLEEPING SYMBOL + +1F4A5 +COLLISION SYMBOL + +1F4A6 +SPLASHING SWEAT SYMBOL + +1F4A7 +DROPLET + +1F4A8 +DASH SYMBOL + +1F4A9 +PILE OF POO + +1F4AA +FLEXED BICEPS + +1F4AB +DIZZY SYMBOL + +1F4AC +SPEECH BALLOON + +1F4AD +THOUGHT BALLOON + +1F4AE +WHITE FLOWER + +1F4AF +HUNDRED POINTS SYMBOL + +1F4B0 +MONEY BAG + +1F4B1 +CURRENCY EXCHANGE + +1F4B2 +HEAVY DOLLAR SIGN + +1F4B3 +CREDIT CARD + +1F4B4 +BANKNOTE WITH YEN SIGN + +1F4B5 +BANKNOTE WITH DOLLAR SIGN + +1F4B6 +BANKNOTE WITH EURO SIGN + +1F4B7 +BANKNOTE WITH POUND SIGN + +1F4B8 +MONEY WITH WINGS + +1F4B9 +CHART WITH UPWARDS TREND AND YEN SIGN + +1F4BA +SEAT + +1F4BB +PERSONAL COMPUTER + +1F4BC +BRIEFCASE + +1F4BD +MINIDISC + +1F4BE +FLOPPY DISK + +1F4BF +OPTICAL DISC + +1F4C0 +DVD + +1F4C1 +FILE FOLDER + +1F4C2 +OPEN FILE FOLDER + +1F4C3 +PAGE WITH CURL + +1F4C4 +PAGE FACING UP + +1F4C5 +CALENDAR + +1F4C6 +TEAR-OFF CALENDAR + +1F4C7 +CARD INDEX + +1F4C8 +CHART WITH UPWARDS TREND + +1F4C9 +CHART WITH DOWNWARDS TREND + +1F4CA +BAR CHART + +1F4CB +CLIPBOARD + +1F4CC +PUSHPIN + +1F4CD +ROUND PUSHPIN + +1F4CE +PAPERCLIP + +1F4CF +STRAIGHT RULER + +1F4D0 +TRIANGULAR RULER + +1F4D1 +BOOKMARK TABS + +1F4D2 +LEDGER + +1F4D3 +NOTEBOOK + +1F4D4 +NOTEBOOK WITH DECORATIVE COVER + +1F4D5 +CLOSED BOOK + +1F4D6 +OPEN BOOK + +1F4D7 +GREEN BOOK + +1F4D8 +BLUE BOOK + +1F4D9 +ORANGE BOOK + +1F4DA +BOOKS + +1F4DB +NAME BADGE + +1F4DC +SCROLL + +1F4DD +MEMO + +1F4DE +TELEPHONE RECEIVER + +1F4DF +PAGER + +1F4E0 +FAX MACHINE + +1F4E1 +SATELLITE ANTENNA + +1F4E2 +PUBLIC ADDRESS LOUDSPEAKER + +1F4E3 +CHEERING MEGAPHONE + +1F4E4 +OUTBOX TRAY + +1F4E5 +INBOX TRAY + +1F4E6 +PACKAGE + +1F4E7 +E-MAIL SYMBOL + +1F4E8 +INCOMING ENVELOPE + +1F4E9 +ENVELOPE WITH DOWNWARDS ARROW ABOVE + +1F4EA +CLOSED MAILBOX WITH LOWERED FLAG + +1F4EB +CLOSED MAILBOX WITH RAISED FLAG + +1F4EC +OPEN MAILBOX WITH RAISED FLAG + +1F4ED +OPEN MAILBOX WITH LOWERED FLAG + +1F4EE +POSTBOX + +1F4EF +POSTAL HORN + +1F4F0 +NEWSPAPER + +1F4F1 +MOBILE PHONE + +1F4F2 +MOBILE PHONE WITH RIGHTWARDS ARROW AT LEFT + +1F4F3 +VIBRATION MODE + +1F4F4 +MOBILE PHONE OFF + +1F4F5 +NO MOBILE PHONES + +1F4F6 +ANTENNA WITH BARS + +1F4F7 +CAMERA + +1F4F8 +CAMERA WITH FLASH + +1F4F9 +VIDEO CAMERA + +1F4FA +TELEVISION + +1F4FB +RADIO + +1F4FC +VIDEOCASSETTE + +1F4FD +FILM PROJECTOR + +1F4FE +PORTABLE STEREO + +1F4FF +PRAYER BEADS + +1F500 +TWISTED RIGHTWARDS ARROWS + +1F501 +CLOCKWISE RIGHTWARDS AND LEFTWARDS OPEN CIRCLE ARROWS + +1F502 +CLOCKWISE RIGHTWARDS AND LEFTWARDS OPEN CIRCLE ARROWS WITH CIRCLED ONE OVERLAY + +1F503 +CLOCKWISE DOWNWARDS AND UPWARDS OPEN CIRCLE ARROWS + +1F504 +ANTICLOCKWISE DOWNWARDS AND UPWARDS OPEN CIRCLE ARROWS + +1F505 +LOW BRIGHTNESS SYMBOL + +1F506 +HIGH BRIGHTNESS SYMBOL + +1F507 +SPEAKER WITH CANCELLATION STROKE + +1F508 +SPEAKER + +1F509 +SPEAKER WITH ONE SOUND WAVE + +1F50A +SPEAKER WITH THREE SOUND WAVES + +1F50B +BATTERY + +1F50C +ELECTRIC PLUG + +1F50D +LEFT-POINTING MAGNIFYING GLASS + +1F50E +RIGHT-POINTING MAGNIFYING GLASS + +1F50F +LOCK WITH INK PEN + +1F510 +CLOSED LOCK WITH KEY + +1F511 +KEY + +1F512 +LOCK + +1F513 +OPEN LOCK + +1F514 +BELL + +1F515 +BELL WITH CANCELLATION STROKE + +1F516 +BOOKMARK + +1F517 +LINK SYMBOL + +1F518 +RADIO BUTTON + +1F519 +BACK WITH LEFTWARDS ARROW ABOVE + +1F51A +END WITH LEFTWARDS ARROW ABOVE + +1F51B +ON WITH EXCLAMATION MARK WITH LEFT RIGHT ARROW ABOVE + +1F51C +SOON WITH RIGHTWARDS ARROW ABOVE + +1F51D +TOP WITH UPWARDS ARROW ABOVE + +1F51E +NO ONE UNDER EIGHTEEN SYMBOL + +1F51F +KEYCAP TEN + +1F520 +INPUT SYMBOL FOR LATIN CAPITAL LETTERS + +1F521 +INPUT SYMBOL FOR LATIN SMALL LETTERS + +1F522 +INPUT SYMBOL FOR NUMBERS + +1F523 +INPUT SYMBOL FOR SYMBOLS + +1F524 +INPUT SYMBOL FOR LATIN LETTERS + +1F525 +FIRE + +1F526 +ELECTRIC TORCH + +1F527 +WRENCH + +1F528 +HAMMER + +1F529 +NUT AND BOLT + +1F52A +HOCHO + +1F52B +PISTOL + +1F52C +MICROSCOPE + +1F52D +TELESCOPE + +1F52E +CRYSTAL BALL + +1F52F +SIX POINTED STAR WITH MIDDLE DOT + +1F530 +JAPANESE SYMBOL FOR BEGINNER + +1F531 +TRIDENT EMBLEM + +1F532 +BLACK SQUARE BUTTON + +1F533 +WHITE SQUARE BUTTON + +1F534 +LARGE RED CIRCLE + +1F535 +LARGE BLUE CIRCLE + +1F536 +LARGE ORANGE DIAMOND + +1F537 +LARGE BLUE DIAMOND + +1F538 +SMALL ORANGE DIAMOND + +1F539 +SMALL BLUE DIAMOND + +1F53A +UP-POINTING RED TRIANGLE + +1F53B +DOWN-POINTING RED TRIANGLE + +1F53C +UP-POINTING SMALL RED TRIANGLE + +1F53D +DOWN-POINTING SMALL RED TRIANGLE + +1F53E +LOWER RIGHT SHADOWED WHITE CIRCLE + +1F53F +UPPER RIGHT SHADOWED WHITE CIRCLE + +1F540 +CIRCLED CROSS POMMEE + +1F541 +CROSS POMMEE WITH HALF-CIRCLE BELOW + +1F542 +CROSS POMMEE + +1F543 +NOTCHED LEFT SEMICIRCLE WITH THREE DOTS + +1F544 +NOTCHED RIGHT SEMICIRCLE WITH THREE DOTS + +1F545 +SYMBOL FOR MARKS CHAPTER + +1F546 +WHITE LATIN CROSS + +1F547 +HEAVY LATIN CROSS + +1F548 +CELTIC CROSS + +1F549 +OM SYMBOL + +1F54A +DOVE OF PEACE + +1F54B +KAABA + +1F54C +MOSQUE + +1F54D +SYNAGOGUE + +1F54E +MENORAH WITH NINE BRANCHES + +1F54F +BOWL OF HYGIEIA + +1F550 +CLOCK FACE ONE OCLOCK + +1F551 +CLOCK FACE TWO OCLOCK + +1F552 +CLOCK FACE THREE OCLOCK + +1F553 +CLOCK FACE FOUR OCLOCK + +1F554 +CLOCK FACE FIVE OCLOCK + +1F555 +CLOCK FACE SIX OCLOCK + +1F556 +CLOCK FACE SEVEN OCLOCK + +1F557 +CLOCK FACE EIGHT OCLOCK + +1F558 +CLOCK FACE NINE OCLOCK + +1F559 +CLOCK FACE TEN OCLOCK + +1F55A +CLOCK FACE ELEVEN OCLOCK + +1F55B +CLOCK FACE TWELVE OCLOCK + +1F55C +CLOCK FACE ONE-THIRTY + +1F55D +CLOCK FACE TWO-THIRTY + +1F55E +CLOCK FACE THREE-THIRTY + +1F55F +CLOCK FACE FOUR-THIRTY + +1F560 +CLOCK FACE FIVE-THIRTY + +1F561 +CLOCK FACE SIX-THIRTY + +1F562 +CLOCK FACE SEVEN-THIRTY + +1F563 +CLOCK FACE EIGHT-THIRTY + +1F564 +CLOCK FACE NINE-THIRTY + +1F565 +CLOCK FACE TEN-THIRTY + +1F566 +CLOCK FACE ELEVEN-THIRTY + +1F567 +CLOCK FACE TWELVE-THIRTY + +1F568 +RIGHT SPEAKER + +1F569 +RIGHT SPEAKER WITH ONE SOUND WAVE + +1F56A +RIGHT SPEAKER WITH THREE SOUND WAVES + +1F56B +BULLHORN + +1F56C +BULLHORN WITH SOUND WAVES + +1F56D +RINGING BELL + +1F56E +BOOK + +1F56F +CANDLE + +1F570 +MANTELPIECE CLOCK + +1F571 +BLACK SKULL AND CROSSBONES + +1F572 +NO PIRACY + +1F573 +HOLE + +1F574 +MAN IN BUSINESS SUIT LEVITATING + +1F575 +SLEUTH OR SPY + +1F576 +DARK SUNGLASSES + +1F577 +SPIDER + +1F578 +SPIDER WEB + +1F579 +JOYSTICK + +1F57A +MAN DANCING + +1F57B +LEFT HAND TELEPHONE RECEIVER + +1F57C +TELEPHONE RECEIVER WITH PAGE + +1F57D +RIGHT HAND TELEPHONE RECEIVER + +1F57E +WHITE TOUCHTONE TELEPHONE + +1F57F +BLACK TOUCHTONE TELEPHONE + +1F580 +TELEPHONE ON TOP OF MODEM + +1F581 +CLAMSHELL MOBILE PHONE + +1F582 +BACK OF ENVELOPE + +1F583 +STAMPED ENVELOPE + +1F584 +ENVELOPE WITH LIGHTNING + +1F585 +FLYING ENVELOPE + +1F586 +PEN OVER STAMPED ENVELOPE + +1F587 +LINKED PAPERCLIPS + +1F588 +BLACK PUSHPIN + +1F589 +LOWER LEFT PENCIL + +1F58A +LOWER LEFT BALLPOINT PEN + +1F58B +LOWER LEFT FOUNTAIN PEN + +1F58C +LOWER LEFT PAINTBRUSH + +1F58D +LOWER LEFT CRAYON + +1F58E +LEFT WRITING HAND + +1F58F +TURNED OK HAND SIGN + +1F590 +RAISED HAND WITH FINGERS SPLAYED + +1F591 +REVERSED RAISED HAND WITH FINGERS SPLAYED + +1F592 +REVERSED THUMBS UP SIGN + +1F593 +REVERSED THUMBS DOWN SIGN + +1F594 +REVERSED VICTORY HAND + +1F595 +REVERSED HAND WITH MIDDLE FINGER EXTENDED + +1F596 +RAISED HAND WITH PART BETWEEN MIDDLE AND RING FINGERS + +1F597 +WHITE DOWN POINTING LEFT HAND INDEX + +1F598 +SIDEWAYS WHITE LEFT POINTING INDEX + +1F599 +SIDEWAYS WHITE RIGHT POINTING INDEX + +1F59A +SIDEWAYS BLACK LEFT POINTING INDEX + +1F59B +SIDEWAYS BLACK RIGHT POINTING INDEX + +1F59C +BLACK LEFT POINTING BACKHAND INDEX + +1F59D +BLACK RIGHT POINTING BACKHAND INDEX + +1F59E +SIDEWAYS WHITE UP POINTING INDEX + +1F59F +SIDEWAYS WHITE DOWN POINTING INDEX + +1F5A0 +SIDEWAYS BLACK UP POINTING INDEX + +1F5A1 +SIDEWAYS BLACK DOWN POINTING INDEX + +1F5A2 +BLACK UP POINTING BACKHAND INDEX + +1F5A3 +BLACK DOWN POINTING BACKHAND INDEX + +1F5A4 +BLACK HEART + +1F5A5 +DESKTOP COMPUTER + +1F5A6 +KEYBOARD AND MOUSE + +1F5A7 +THREE NETWORKED COMPUTERS + +1F5A8 +PRINTER + +1F5A9 +POCKET CALCULATOR + +1F5AA +BLACK HARD SHELL FLOPPY DISK + +1F5AB +WHITE HARD SHELL FLOPPY DISK + +1F5AC +SOFT SHELL FLOPPY DISK + +1F5AD +TAPE CARTRIDGE + +1F5AE +WIRED KEYBOARD + +1F5AF +ONE BUTTON MOUSE + +1F5B0 +TWO BUTTON MOUSE + +1F5B1 +THREE BUTTON MOUSE + +1F5B2 +TRACKBALL + +1F5B3 +OLD PERSONAL COMPUTER + +1F5B4 +HARD DISK + +1F5B5 +SCREEN + +1F5B6 +PRINTER ICON + +1F5B7 +FAX ICON + +1F5B8 +OPTICAL DISC ICON + +1F5B9 +DOCUMENT WITH TEXT + +1F5BA +DOCUMENT WITH TEXT AND PICTURE + +1F5BB +DOCUMENT WITH PICTURE + +1F5BC +FRAME WITH PICTURE + +1F5BD +FRAME WITH TILES + +1F5BE +FRAME WITH AN X + +1F5BF +BLACK FOLDER + +1F5C0 +FOLDER + +1F5C1 +OPEN FOLDER + +1F5C2 +CARD INDEX DIVIDERS + +1F5C3 +CARD FILE BOX + +1F5C4 +FILE CABINET + +1F5C5 +EMPTY NOTE + +1F5C6 +EMPTY NOTE PAGE + +1F5C7 +EMPTY NOTE PAD + +1F5C8 +NOTE + +1F5C9 +NOTE PAGE + +1F5CA +NOTE PAD + +1F5CB +EMPTY DOCUMENT + +1F5CC +EMPTY PAGE + +1F5CD +EMPTY PAGES + +1F5CE +DOCUMENT + +1F5CF +PAGE + +1F5D0 +PAGES + +1F5D1 +WASTEBASKET + +1F5D2 +SPIRAL NOTE PAD + +1F5D3 +SPIRAL CALENDAR PAD + +1F5D4 +DESKTOP WINDOW + +1F5D5 +MINIMIZE + +1F5D6 +MAXIMIZE + +1F5D7 +OVERLAP + +1F5D8 +CLOCKWISE RIGHT AND LEFT SEMICIRCLE ARROWS + +1F5D9 +CANCELLATION X + +1F5DA +INCREASE FONT SIZE SYMBOL + +1F5DB +DECREASE FONT SIZE SYMBOL + +1F5DC +COMPRESSION + +1F5DD +OLD KEY + +1F5DE +ROLLED-UP NEWSPAPER + +1F5DF +PAGE WITH CIRCLED TEXT + +1F5E0 +STOCK CHART + +1F5E1 +DAGGER KNIFE + +1F5E2 +LIPS + +1F5E3 +SPEAKING HEAD IN SILHOUETTE + +1F5E4 +THREE RAYS ABOVE + +1F5E5 +THREE RAYS BELOW + +1F5E6 +THREE RAYS LEFT + +1F5E7 +THREE RAYS RIGHT + +1F5E8 +LEFT SPEECH BUBBLE + +1F5E9 +RIGHT SPEECH BUBBLE + +1F5EA +TWO SPEECH BUBBLES + +1F5EB +THREE SPEECH BUBBLES + +1F5EC +LEFT THOUGHT BUBBLE + +1F5ED +RIGHT THOUGHT BUBBLE + +1F5EE +LEFT ANGER BUBBLE + +1F5EF +RIGHT ANGER BUBBLE + +1F5F0 +MOOD BUBBLE + +1F5F1 +LIGHTNING MOOD BUBBLE + +1F5F2 +LIGHTNING MOOD + +1F5F3 +BALLOT BOX WITH BALLOT + +1F5F4 +BALLOT SCRIPT X + +1F5F5 +BALLOT BOX WITH SCRIPT X + +1F5F6 +BALLOT BOLD SCRIPT X + +1F5F7 +BALLOT BOX WITH BOLD SCRIPT X + +1F5F8 +LIGHT CHECK MARK + +1F5F9 +BALLOT BOX WITH BOLD CHECK + +1F5FA +WORLD MAP + +1F5FB +MOUNT FUJI + +1F5FC +TOKYO TOWER + +1F5FD +STATUE OF LIBERTY + +1F5FE +SILHOUETTE OF JAPAN + +1F5FF +MOYAI + +1F600 +GRINNING FACE + +1F601 +GRINNING FACE WITH SMILING EYES + +1F602 +FACE WITH TEARS OF JOY + +1F603 +SMILING FACE WITH OPEN MOUTH + +1F604 +SMILING FACE WITH OPEN MOUTH AND SMILING EYES + +1F605 +SMILING FACE WITH OPEN MOUTH AND COLD SWEAT + +1F606 +SMILING FACE WITH OPEN MOUTH AND TIGHTLY-CLOSED EYES + +1F607 +SMILING FACE WITH HALO + +1F608 +SMILING FACE WITH HORNS + +1F609 +WINKING FACE + +1F60A +SMILING FACE WITH SMILING EYES + +1F60B +FACE SAVOURING DELICIOUS FOOD + +1F60C +RELIEVED FACE + +1F60D +SMILING FACE WITH HEART-SHAPED EYES + +1F60E +SMILING FACE WITH SUNGLASSES + +1F60F +SMIRKING FACE + +1F610 +NEUTRAL FACE + +1F611 +EXPRESSIONLESS FACE + +1F612 +UNAMUSED FACE + +1F613 +FACE WITH COLD SWEAT + +1F614 +PENSIVE FACE + +1F615 +CONFUSED FACE + +1F616 +CONFOUNDED FACE + +1F617 +KISSING FACE + +1F618 +FACE THROWING A KISS + +1F619 +KISSING FACE WITH SMILING EYES + +1F61A +KISSING FACE WITH CLOSED EYES + +1F61B +FACE WITH STUCK-OUT TONGUE + +1F61C +FACE WITH STUCK-OUT TONGUE AND WINKING EYE + +1F61D +FACE WITH STUCK-OUT TONGUE AND TIGHTLY-CLOSED EYES + +1F61E +DISAPPOINTED FACE + +1F61F +WORRIED FACE + +1F620 +ANGRY FACE + +1F621 +POUTING FACE + +1F622 +CRYING FACE + +1F623 +PERSEVERING FACE + +1F624 +FACE WITH LOOK OF TRIUMPH + +1F625 +DISAPPOINTED BUT RELIEVED FACE + +1F626 +FROWNING FACE WITH OPEN MOUTH + +1F627 +ANGUISHED FACE + +1F628 +FEARFUL FACE + +1F629 +WEARY FACE + +1F62A +SLEEPY FACE + +1F62B +TIRED FACE + +1F62C +GRIMACING FACE + +1F62D +LOUDLY CRYING FACE + +1F62E +FACE WITH OPEN MOUTH + +1F62F +HUSHED FACE + +1F630 +FACE WITH OPEN MOUTH AND COLD SWEAT + +1F631 +FACE SCREAMING IN FEAR + +1F632 +ASTONISHED FACE + +1F633 +FLUSHED FACE + +1F634 +SLEEPING FACE + +1F635 +DIZZY FACE + +1F636 +FACE WITHOUT MOUTH + +1F637 +FACE WITH MEDICAL MASK + +1F638 +GRINNING CAT FACE WITH SMILING EYES + +1F639 +CAT FACE WITH TEARS OF JOY + +1F63A +SMILING CAT FACE WITH OPEN MOUTH + +1F63B +SMILING CAT FACE WITH HEART-SHAPED EYES + +1F63C +CAT FACE WITH WRY SMILE + +1F63D +KISSING CAT FACE WITH CLOSED EYES + +1F63E +POUTING CAT FACE + +1F63F +CRYING CAT FACE + +1F640 +WEARY CAT FACE + +1F641 +SLIGHTLY FROWNING FACE + +1F642 +SLIGHTLY SMILING FACE + +1F643 +UPSIDE-DOWN FACE + +1F644 +FACE WITH ROLLING EYES + +1F645 +FACE WITH NO GOOD GESTURE + +1F646 +FACE WITH OK GESTURE + +1F647 +PERSON BOWING DEEPLY + +1F648 +SEE-NO-EVIL MONKEY + +1F649 +HEAR-NO-EVIL MONKEY + +1F64A +SPEAK-NO-EVIL MONKEY + +1F64B +HAPPY PERSON RAISING ONE HAND + +1F64C +PERSON RAISING BOTH HANDS IN CELEBRATION + +1F64D +PERSON FROWNING + +1F64E +PERSON WITH POUTING FACE + +1F64F +PERSON WITH FOLDED HANDS + +1F650 +NORTH WEST POINTING LEAF + +1F651 +SOUTH WEST POINTING LEAF + +1F652 +NORTH EAST POINTING LEAF + +1F653 +SOUTH EAST POINTING LEAF + +1F654 +TURNED NORTH WEST POINTING LEAF + +1F655 +TURNED SOUTH WEST POINTING LEAF + +1F656 +TURNED NORTH EAST POINTING LEAF + +1F657 +TURNED SOUTH EAST POINTING LEAF + +1F658 +NORTH WEST POINTING VINE LEAF + +1F659 +SOUTH WEST POINTING VINE LEAF + +1F65A +NORTH EAST POINTING VINE LEAF + +1F65B +SOUTH EAST POINTING VINE LEAF + +1F65C +HEAVY NORTH WEST POINTING VINE LEAF + +1F65D +HEAVY SOUTH WEST POINTING VINE LEAF + +1F65E +HEAVY NORTH EAST POINTING VINE LEAF + +1F65F +HEAVY SOUTH EAST POINTING VINE LEAF + +1F660 +NORTH WEST POINTING BUD + +1F661 +SOUTH WEST POINTING BUD + +1F662 +NORTH EAST POINTING BUD + +1F663 +SOUTH EAST POINTING BUD + +1F664 +HEAVY NORTH WEST POINTING BUD + +1F665 +HEAVY SOUTH WEST POINTING BUD + +1F666 +HEAVY NORTH EAST POINTING BUD + +1F667 +HEAVY SOUTH EAST POINTING BUD + +1F668 +HOLLOW QUILT SQUARE ORNAMENT + +1F669 +HOLLOW QUILT SQUARE ORNAMENT IN BLACK SQUARE + +1F66A +SOLID QUILT SQUARE ORNAMENT + +1F66B +SOLID QUILT SQUARE ORNAMENT IN BLACK SQUARE + +1F66C +LEFTWARDS ROCKET + +1F66D +UPWARDS ROCKET + +1F66E +RIGHTWARDS ROCKET + +1F66F +DOWNWARDS ROCKET + +1F670 +SCRIPT LIGATURE ET ORNAMENT + +1F671 +HEAVY SCRIPT LIGATURE ET ORNAMENT + +1F672 +LIGATURE OPEN ET ORNAMENT + +1F673 +HEAVY LIGATURE OPEN ET ORNAMENT + +1F674 +HEAVY AMPERSAND ORNAMENT + +1F675 +SWASH AMPERSAND ORNAMENT + +1F676 +SANS-SERIF HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT + +1F677 +SANS-SERIF HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT + +1F678 +SANS-SERIF HEAVY LOW DOUBLE COMMA QUOTATION MARK ORNAMENT + +1F679 +HEAVY INTERROBANG ORNAMENT + +1F67A +SANS-SERIF INTERROBANG ORNAMENT + +1F67B +HEAVY SANS-SERIF INTERROBANG ORNAMENT + +1F67C +VERY HEAVY SOLIDUS + +1F67D +VERY HEAVY REVERSE SOLIDUS + +1F67E +CHECKER BOARD + +1F67F +REVERSE CHECKER BOARD + +1F680 +ROCKET + +1F681 +HELICOPTER + +1F682 +STEAM LOCOMOTIVE + +1F683 +RAILWAY CAR + +1F684 +HIGH-SPEED TRAIN + +1F685 +HIGH-SPEED TRAIN WITH BULLET NOSE + +1F686 +TRAIN + +1F687 +METRO + +1F688 +LIGHT RAIL + +1F689 +STATION + +1F68A +TRAM + +1F68B +TRAM CAR + +1F68C +BUS + +1F68D +ONCOMING BUS + +1F68E +TROLLEYBUS + +1F68F +BUS STOP + +1F690 +MINIBUS + +1F691 +AMBULANCE + +1F692 +FIRE ENGINE + +1F693 +POLICE CAR + +1F694 +ONCOMING POLICE CAR + +1F695 +TAXI + +1F696 +ONCOMING TAXI + +1F697 +AUTOMOBILE + +1F698 +ONCOMING AUTOMOBILE + +1F699 +RECREATIONAL VEHICLE + +1F69A +DELIVERY TRUCK + +1F69B +ARTICULATED LORRY + +1F69C +TRACTOR + +1F69D +MONORAIL + +1F69E +MOUNTAIN RAILWAY + +1F69F +SUSPENSION RAILWAY + +1F6A0 +MOUNTAIN CABLEWAY + +1F6A1 +AERIAL TRAMWAY + +1F6A2 +SHIP + +1F6A3 +ROWBOAT + +1F6A4 +SPEEDBOAT + +1F6A5 +HORIZONTAL TRAFFIC LIGHT + +1F6A6 +VERTICAL TRAFFIC LIGHT + +1F6A7 +CONSTRUCTION SIGN + +1F6A8 +POLICE CARS REVOLVING LIGHT + +1F6A9 +TRIANGULAR FLAG ON POST + +1F6AA +DOOR + +1F6AB +NO ENTRY SIGN + +1F6AC +SMOKING SYMBOL + +1F6AD +NO SMOKING SYMBOL + +1F6AE +PUT LITTER IN ITS PLACE SYMBOL + +1F6AF +DO NOT LITTER SYMBOL + +1F6B0 +POTABLE WATER SYMBOL + +1F6B1 +NON-POTABLE WATER SYMBOL + +1F6B2 +BICYCLE + +1F6B3 +NO BICYCLES + +1F6B4 +BICYCLIST + +1F6B5 +MOUNTAIN BICYCLIST + +1F6B6 +PEDESTRIAN + +1F6B7 +NO PEDESTRIANS + +1F6B8 +CHILDREN CROSSING + +1F6B9 +MENS SYMBOL + +1F6BA +WOMENS SYMBOL + +1F6BB +RESTROOM + +1F6BC +BABY SYMBOL + +1F6BD +TOILET + +1F6BE +WATER CLOSET + +1F6BF +SHOWER + +1F6C0 +BATH + +1F6C1 +BATHTUB + +1F6C2 +PASSPORT CONTROL + +1F6C3 +CUSTOMS + +1F6C4 +BAGGAGE CLAIM + +1F6C5 +LEFT LUGGAGE + +1F6C6 +TRIANGLE WITH ROUNDED CORNERS + +1F6C7 +PROHIBITED SIGN + +1F6C8 +CIRCLED INFORMATION SOURCE + +1F6C9 +BOYS SYMBOL + +1F6CA +GIRLS SYMBOL + +1F6CB +COUCH AND LAMP + +1F6CC +SLEEPING ACCOMMODATION + +1F6CD +SHOPPING BAGS + +1F6CE +BELLHOP BELL + +1F6CF +BED + +1F6D0 +PLACE OF WORSHIP + +1F6D1 +OCTAGONAL SIGN + +1F6D2 +SHOPPING TROLLEY + +1F6D3 +STUPA + +1F6D4 +PAGODA + +1F6D5 +HINDU TEMPLE + +1F6D6 +HUT + +1F6D7 +ELEVATOR + +1F6D8 +LANDSLIDE + +1F6DC +WIRELESS + +1F6DD +PLAYGROUND SLIDE + +1F6DE +WHEEL + +1F6DF +RING BUOY + +1F6E0 +HAMMER AND WRENCH + +1F6E1 +SHIELD + +1F6E2 +OIL DRUM + +1F6E3 +MOTORWAY + +1F6E4 +RAILWAY TRACK + +1F6E5 +MOTOR BOAT + +1F6E6 +UP-POINTING MILITARY AIRPLANE + +1F6E7 +UP-POINTING AIRPLANE + +1F6E8 +UP-POINTING SMALL AIRPLANE + +1F6E9 +SMALL AIRPLANE + +1F6EA +NORTHEAST-POINTING AIRPLANE + +1F6EB +AIRPLANE DEPARTURE + +1F6EC +AIRPLANE ARRIVING + +1F6F0 +SATELLITE + +1F6F1 +ONCOMING FIRE ENGINE + +1F6F2 +DIESEL LOCOMOTIVE + +1F6F3 +PASSENGER SHIP + +1F6F4 +SCOOTER + +1F6F5 +MOTOR SCOOTER + +1F6F6 +CANOE + +1F6F7 +SLED + +1F6F8 +FLYING SAUCER + +1F6F9 +SKATEBOARD + +1F6FA +AUTO RICKSHAW + +1F6FB +PICKUP TRUCK + +1F6FC +ROLLER SKATE + +1F700 +ALCHEMICAL SYMBOL FOR QUINTESSENCE + +1F701 +ALCHEMICAL SYMBOL FOR AIR + +1F702 +ALCHEMICAL SYMBOL FOR FIRE + +1F703 +ALCHEMICAL SYMBOL FOR EARTH + +1F704 +ALCHEMICAL SYMBOL FOR WATER + +1F705 +ALCHEMICAL SYMBOL FOR AQUAFORTIS + +1F706 +ALCHEMICAL SYMBOL FOR AQUA REGIA + +1F707 +ALCHEMICAL SYMBOL FOR AQUA REGIA-2 + +1F708 +ALCHEMICAL SYMBOL FOR AQUA VITAE + +1F709 +ALCHEMICAL SYMBOL FOR AQUA VITAE-2 + +1F70A +ALCHEMICAL SYMBOL FOR VINEGAR + +1F70B +ALCHEMICAL SYMBOL FOR VINEGAR-2 + +1F70C +ALCHEMICAL SYMBOL FOR VINEGAR-3 + +1F70D +ALCHEMICAL SYMBOL FOR SULFUR + +1F70E +ALCHEMICAL SYMBOL FOR PHILOSOPHERS SULFUR + +1F70F +ALCHEMICAL SYMBOL FOR BLACK SULFUR + +1F710 +ALCHEMICAL SYMBOL FOR MERCURY SUBLIMATE + +1F711 +ALCHEMICAL SYMBOL FOR MERCURY SUBLIMATE-2 + +1F712 +ALCHEMICAL SYMBOL FOR MERCURY SUBLIMATE-3 + +1F713 +ALCHEMICAL SYMBOL FOR CINNABAR + +1F714 +ALCHEMICAL SYMBOL FOR SALT + +1F715 +ALCHEMICAL SYMBOL FOR NITRE + +1F716 +ALCHEMICAL SYMBOL FOR VITRIOL + +1F717 +ALCHEMICAL SYMBOL FOR VITRIOL-2 + +1F718 +ALCHEMICAL SYMBOL FOR ROCK SALT + +1F719 +ALCHEMICAL SYMBOL FOR ROCK SALT-2 + +1F71A +ALCHEMICAL SYMBOL FOR GOLD + +1F71B +ALCHEMICAL SYMBOL FOR SILVER + +1F71C +ALCHEMICAL SYMBOL FOR IRON ORE + +1F71D +ALCHEMICAL SYMBOL FOR IRON ORE-2 + +1F71E +ALCHEMICAL SYMBOL FOR CROCUS OF IRON + +1F71F +ALCHEMICAL SYMBOL FOR REGULUS OF IRON + +1F720 +ALCHEMICAL SYMBOL FOR COPPER ORE + +1F721 +ALCHEMICAL SYMBOL FOR IRON-COPPER ORE + +1F722 +ALCHEMICAL SYMBOL FOR SUBLIMATE OF COPPER + +1F723 +ALCHEMICAL SYMBOL FOR CROCUS OF COPPER + +1F724 +ALCHEMICAL SYMBOL FOR CROCUS OF COPPER-2 + +1F725 +ALCHEMICAL SYMBOL FOR COPPER ANTIMONIATE + +1F726 +ALCHEMICAL SYMBOL FOR SALT OF COPPER ANTIMONIATE + +1F727 +ALCHEMICAL SYMBOL FOR SUBLIMATE OF SALT OF COPPER + +1F728 +ALCHEMICAL SYMBOL FOR VERDIGRIS + +1F729 +ALCHEMICAL SYMBOL FOR TIN ORE + +1F72A +ALCHEMICAL SYMBOL FOR LEAD ORE + +1F72B +ALCHEMICAL SYMBOL FOR ANTIMONY ORE + +1F72C +ALCHEMICAL SYMBOL FOR SUBLIMATE OF ANTIMONY + +1F72D +ALCHEMICAL SYMBOL FOR SALT OF ANTIMONY + +1F72E +ALCHEMICAL SYMBOL FOR SUBLIMATE OF SALT OF ANTIMONY + +1F72F +ALCHEMICAL SYMBOL FOR VINEGAR OF ANTIMONY + +1F730 +ALCHEMICAL SYMBOL FOR REGULUS OF ANTIMONY + +1F731 +ALCHEMICAL SYMBOL FOR REGULUS OF ANTIMONY-2 + +1F732 +ALCHEMICAL SYMBOL FOR REGULUS + +1F733 +ALCHEMICAL SYMBOL FOR REGULUS-2 + +1F734 +ALCHEMICAL SYMBOL FOR REGULUS-3 + +1F735 +ALCHEMICAL SYMBOL FOR REGULUS-4 + +1F736 +ALCHEMICAL SYMBOL FOR ALKALI + +1F737 +ALCHEMICAL SYMBOL FOR ALKALI-2 + +1F738 +ALCHEMICAL SYMBOL FOR MARCASITE + +1F739 +ALCHEMICAL SYMBOL FOR SAL-AMMONIAC + +1F73A +ALCHEMICAL SYMBOL FOR ARSENIC + +1F73B +ALCHEMICAL SYMBOL FOR REALGAR + +1F73C +ALCHEMICAL SYMBOL FOR REALGAR-2 + +1F73D +ALCHEMICAL SYMBOL FOR AURIPIGMENT + +1F73E +ALCHEMICAL SYMBOL FOR BISMUTH ORE + +1F73F +ALCHEMICAL SYMBOL FOR TARTAR + +1F740 +ALCHEMICAL SYMBOL FOR TARTAR-2 + +1F741 +ALCHEMICAL SYMBOL FOR QUICK LIME + +1F742 +ALCHEMICAL SYMBOL FOR BORAX + +1F743 +ALCHEMICAL SYMBOL FOR BORAX-2 + +1F744 +ALCHEMICAL SYMBOL FOR BORAX-3 + +1F745 +ALCHEMICAL SYMBOL FOR ALUM + +1F746 +ALCHEMICAL SYMBOL FOR OIL + +1F747 +ALCHEMICAL SYMBOL FOR SPIRIT + +1F748 +ALCHEMICAL SYMBOL FOR TINCTURE + +1F749 +ALCHEMICAL SYMBOL FOR GUM + +1F74A +ALCHEMICAL SYMBOL FOR WAX + +1F74B +ALCHEMICAL SYMBOL FOR POWDER + +1F74C +ALCHEMICAL SYMBOL FOR CALX + +1F74D +ALCHEMICAL SYMBOL FOR TUTTY + +1F74E +ALCHEMICAL SYMBOL FOR CAPUT MORTUUM + +1F74F +ALCHEMICAL SYMBOL FOR SCEPTER OF JOVE + +1F750 +ALCHEMICAL SYMBOL FOR CADUCEUS + +1F751 +ALCHEMICAL SYMBOL FOR TRIDENT + +1F752 +ALCHEMICAL SYMBOL FOR STARRED TRIDENT + +1F753 +ALCHEMICAL SYMBOL FOR LODESTONE + +1F754 +ALCHEMICAL SYMBOL FOR SOAP + +1F755 +ALCHEMICAL SYMBOL FOR URINE + +1F756 +ALCHEMICAL SYMBOL FOR HORSE DUNG + +1F757 +ALCHEMICAL SYMBOL FOR ASHES + +1F758 +ALCHEMICAL SYMBOL FOR POT ASHES + +1F759 +ALCHEMICAL SYMBOL FOR BRICK + +1F75A +ALCHEMICAL SYMBOL FOR POWDERED BRICK + +1F75B +ALCHEMICAL SYMBOL FOR AMALGAM + +1F75C +ALCHEMICAL SYMBOL FOR STRATUM SUPER STRATUM + +1F75D +ALCHEMICAL SYMBOL FOR STRATUM SUPER STRATUM-2 + +1F75E +ALCHEMICAL SYMBOL FOR SUBLIMATION + +1F75F +ALCHEMICAL SYMBOL FOR PRECIPITATE + +1F760 +ALCHEMICAL SYMBOL FOR DISTILL + +1F761 +ALCHEMICAL SYMBOL FOR DISSOLVE + +1F762 +ALCHEMICAL SYMBOL FOR DISSOLVE-2 + +1F763 +ALCHEMICAL SYMBOL FOR PURIFY + +1F764 +ALCHEMICAL SYMBOL FOR PUTREFACTION + +1F765 +ALCHEMICAL SYMBOL FOR CRUCIBLE + +1F766 +ALCHEMICAL SYMBOL FOR CRUCIBLE-2 + +1F767 +ALCHEMICAL SYMBOL FOR CRUCIBLE-3 + +1F768 +ALCHEMICAL SYMBOL FOR CRUCIBLE-4 + +1F769 +ALCHEMICAL SYMBOL FOR CRUCIBLE-5 + +1F76A +ALCHEMICAL SYMBOL FOR ALEMBIC + +1F76B +ALCHEMICAL SYMBOL FOR BATH OF MARY + +1F76C +ALCHEMICAL SYMBOL FOR BATH OF VAPOURS + +1F76D +ALCHEMICAL SYMBOL FOR RETORT + +1F76E +ALCHEMICAL SYMBOL FOR HOUR + +1F76F +ALCHEMICAL SYMBOL FOR NIGHT + +1F770 +ALCHEMICAL SYMBOL FOR DAY-NIGHT + +1F771 +ALCHEMICAL SYMBOL FOR MONTH + +1F772 +ALCHEMICAL SYMBOL FOR HALF DRAM + +1F773 +ALCHEMICAL SYMBOL FOR HALF OUNCE + +1F774 +LOT OF FORTUNE + +1F775 +OCCULTATION + +1F776 +LUNAR ECLIPSE + +1F777 +VESTA FORM TWO + +1F778 +ASTRAEA FORM TWO + +1F779 +HYGIEA FORM TWO + +1F77A +PARTHENOPE FORM TWO + +1F77B +HAUMEA + +1F77C +MAKEMAKE + +1F77D +GONGGONG + +1F77E +QUAOAR + +1F77F +ORCUS + +1F780 +BLACK LEFT-POINTING ISOSCELES RIGHT TRIANGLE + +1F781 +BLACK UP-POINTING ISOSCELES RIGHT TRIANGLE + +1F782 +BLACK RIGHT-POINTING ISOSCELES RIGHT TRIANGLE + +1F783 +BLACK DOWN-POINTING ISOSCELES RIGHT TRIANGLE + +1F784 +BLACK SLIGHTLY SMALL CIRCLE + +1F785 +MEDIUM BOLD WHITE CIRCLE + +1F786 +BOLD WHITE CIRCLE + +1F787 +HEAVY WHITE CIRCLE + +1F788 +VERY HEAVY WHITE CIRCLE + +1F789 +EXTREMELY HEAVY WHITE CIRCLE + +1F78A +WHITE CIRCLE CONTAINING BLACK SMALL CIRCLE + +1F78B +ROUND TARGET + +1F78C +BLACK TINY SQUARE + +1F78D +BLACK SLIGHTLY SMALL SQUARE + +1F78E +LIGHT WHITE SQUARE + +1F78F +MEDIUM WHITE SQUARE + +1F790 +BOLD WHITE SQUARE + +1F791 +HEAVY WHITE SQUARE + +1F792 +VERY HEAVY WHITE SQUARE + +1F793 +EXTREMELY HEAVY WHITE SQUARE + +1F794 +WHITE SQUARE CONTAINING BLACK VERY SMALL SQUARE + +1F795 +WHITE SQUARE CONTAINING BLACK MEDIUM SQUARE + +1F796 +SQUARE TARGET + +1F797 +BLACK TINY DIAMOND + +1F798 +BLACK VERY SMALL DIAMOND + +1F799 +BLACK MEDIUM SMALL DIAMOND + +1F79A +WHITE DIAMOND CONTAINING BLACK VERY SMALL DIAMOND + +1F79B +WHITE DIAMOND CONTAINING BLACK MEDIUM DIAMOND + +1F79C +DIAMOND TARGET + +1F79D +BLACK TINY LOZENGE + +1F79E +BLACK VERY SMALL LOZENGE + +1F79F +BLACK MEDIUM SMALL LOZENGE + +1F7A0 +WHITE LOZENGE CONTAINING BLACK SMALL LOZENGE + +1F7A1 +THIN GREEK CROSS + +1F7A2 +LIGHT GREEK CROSS + +1F7A3 +MEDIUM GREEK CROSS + +1F7A4 +BOLD GREEK CROSS + +1F7A5 +VERY BOLD GREEK CROSS + +1F7A6 +VERY HEAVY GREEK CROSS + +1F7A7 +EXTREMELY HEAVY GREEK CROSS + +1F7A8 +THIN SALTIRE + +1F7A9 +LIGHT SALTIRE + +1F7AA +MEDIUM SALTIRE + +1F7AB +BOLD SALTIRE + +1F7AC +HEAVY SALTIRE + +1F7AD +VERY HEAVY SALTIRE + +1F7AE +EXTREMELY HEAVY SALTIRE + +1F7AF +LIGHT FIVE SPOKED ASTERISK + +1F7B0 +MEDIUM FIVE SPOKED ASTERISK + +1F7B1 +BOLD FIVE SPOKED ASTERISK + +1F7B2 +HEAVY FIVE SPOKED ASTERISK + +1F7B3 +VERY HEAVY FIVE SPOKED ASTERISK + +1F7B4 +EXTREMELY HEAVY FIVE SPOKED ASTERISK + +1F7B5 +LIGHT SIX SPOKED ASTERISK + +1F7B6 +MEDIUM SIX SPOKED ASTERISK + +1F7B7 +BOLD SIX SPOKED ASTERISK + +1F7B8 +HEAVY SIX SPOKED ASTERISK + +1F7B9 +VERY HEAVY SIX SPOKED ASTERISK + +1F7BA +EXTREMELY HEAVY SIX SPOKED ASTERISK + +1F7BB +LIGHT EIGHT SPOKED ASTERISK + +1F7BC +MEDIUM EIGHT SPOKED ASTERISK + +1F7BD +BOLD EIGHT SPOKED ASTERISK + +1F7BE +HEAVY EIGHT SPOKED ASTERISK + +1F7BF +VERY HEAVY EIGHT SPOKED ASTERISK + +1F7C0 +LIGHT THREE POINTED BLACK STAR + +1F7C1 +MEDIUM THREE POINTED BLACK STAR + +1F7C2 +THREE POINTED BLACK STAR + +1F7C3 +MEDIUM THREE POINTED PINWHEEL STAR + +1F7C4 +LIGHT FOUR POINTED BLACK STAR + +1F7C5 +MEDIUM FOUR POINTED BLACK STAR + +1F7C6 +FOUR POINTED BLACK STAR + +1F7C7 +MEDIUM FOUR POINTED PINWHEEL STAR + +1F7C8 +REVERSE LIGHT FOUR POINTED PINWHEEL STAR + +1F7C9 +LIGHT FIVE POINTED BLACK STAR + +1F7CA +HEAVY FIVE POINTED BLACK STAR + +1F7CB +MEDIUM SIX POINTED BLACK STAR + +1F7CC +HEAVY SIX POINTED BLACK STAR + +1F7CD +SIX POINTED PINWHEEL STAR + +1F7CE +MEDIUM EIGHT POINTED BLACK STAR + +1F7CF +HEAVY EIGHT POINTED BLACK STAR + +1F7D0 +VERY HEAVY EIGHT POINTED BLACK STAR + +1F7D1 +HEAVY EIGHT POINTED PINWHEEL STAR + +1F7D2 +LIGHT TWELVE POINTED BLACK STAR + +1F7D3 +HEAVY TWELVE POINTED BLACK STAR + +1F7D4 +HEAVY TWELVE POINTED PINWHEEL STAR + +1F7D5 +CIRCLED TRIANGLE + +1F7D6 +NEGATIVE CIRCLED TRIANGLE + +1F7D7 +CIRCLED SQUARE + +1F7D8 +NEGATIVE CIRCLED SQUARE + +1F7D9 +NINE POINTED WHITE STAR + +1F7E0 +LARGE ORANGE CIRCLE + +1F7E1 +LARGE YELLOW CIRCLE + +1F7E2 +LARGE GREEN CIRCLE + +1F7E3 +LARGE PURPLE CIRCLE + +1F7E4 +LARGE BROWN CIRCLE + +1F7E5 +LARGE RED SQUARE + +1F7E6 +LARGE BLUE SQUARE + +1F7E7 +LARGE ORANGE SQUARE + +1F7E8 +LARGE YELLOW SQUARE + +1F7E9 +LARGE GREEN SQUARE + +1F7EA +LARGE PURPLE SQUARE + +1F7EB +LARGE BROWN SQUARE + +1F7F0 +HEAVY EQUALS SIGN + +1F800 +LEFTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD + +1F801 +UPWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD + +1F802 +RIGHTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD + +1F803 +DOWNWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD + +1F804 +LEFTWARDS ARROW WITH MEDIUM TRIANGLE ARROWHEAD + +1F805 +UPWARDS ARROW WITH MEDIUM TRIANGLE ARROWHEAD + +1F806 +RIGHTWARDS ARROW WITH MEDIUM TRIANGLE ARROWHEAD + +1F807 +DOWNWARDS ARROW WITH MEDIUM TRIANGLE ARROWHEAD + +1F808 +LEFTWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD + +1F809 +UPWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD + +1F80A +RIGHTWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD + +1F80B +DOWNWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD + +1F810 +LEFTWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD + +1F811 +UPWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD + +1F812 +RIGHTWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD + +1F813 +DOWNWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD + +1F814 +LEFTWARDS ARROW WITH EQUILATERAL ARROWHEAD + +1F815 +UPWARDS ARROW WITH EQUILATERAL ARROWHEAD + +1F816 +RIGHTWARDS ARROW WITH EQUILATERAL ARROWHEAD + +1F817 +DOWNWARDS ARROW WITH EQUILATERAL ARROWHEAD + +1F818 +HEAVY LEFTWARDS ARROW WITH EQUILATERAL ARROWHEAD + +1F819 +HEAVY UPWARDS ARROW WITH EQUILATERAL ARROWHEAD + +1F81A +HEAVY RIGHTWARDS ARROW WITH EQUILATERAL ARROWHEAD + +1F81B +HEAVY DOWNWARDS ARROW WITH EQUILATERAL ARROWHEAD + +1F81C +HEAVY LEFTWARDS ARROW WITH LARGE EQUILATERAL ARROWHEAD + +1F81D +HEAVY UPWARDS ARROW WITH LARGE EQUILATERAL ARROWHEAD + +1F81E +HEAVY RIGHTWARDS ARROW WITH LARGE EQUILATERAL ARROWHEAD + +1F81F +HEAVY DOWNWARDS ARROW WITH LARGE EQUILATERAL ARROWHEAD + +1F820 +LEFTWARDS TRIANGLE-HEADED ARROW WITH NARROW SHAFT + +1F821 +UPWARDS TRIANGLE-HEADED ARROW WITH NARROW SHAFT + +1F822 +RIGHTWARDS TRIANGLE-HEADED ARROW WITH NARROW SHAFT + +1F823 +DOWNWARDS TRIANGLE-HEADED ARROW WITH NARROW SHAFT + +1F824 +LEFTWARDS TRIANGLE-HEADED ARROW WITH MEDIUM SHAFT + +1F825 +UPWARDS TRIANGLE-HEADED ARROW WITH MEDIUM SHAFT + +1F826 +RIGHTWARDS TRIANGLE-HEADED ARROW WITH MEDIUM SHAFT + +1F827 +DOWNWARDS TRIANGLE-HEADED ARROW WITH MEDIUM SHAFT + +1F828 +LEFTWARDS TRIANGLE-HEADED ARROW WITH BOLD SHAFT + +1F829 +UPWARDS TRIANGLE-HEADED ARROW WITH BOLD SHAFT + +1F82A +RIGHTWARDS TRIANGLE-HEADED ARROW WITH BOLD SHAFT + +1F82B +DOWNWARDS TRIANGLE-HEADED ARROW WITH BOLD SHAFT + +1F82C +LEFTWARDS TRIANGLE-HEADED ARROW WITH HEAVY SHAFT + +1F82D +UPWARDS TRIANGLE-HEADED ARROW WITH HEAVY SHAFT + +1F82E +RIGHTWARDS TRIANGLE-HEADED ARROW WITH HEAVY SHAFT + +1F82F +DOWNWARDS TRIANGLE-HEADED ARROW WITH HEAVY SHAFT + +1F830 +LEFTWARDS TRIANGLE-HEADED ARROW WITH VERY HEAVY SHAFT + +1F831 +UPWARDS TRIANGLE-HEADED ARROW WITH VERY HEAVY SHAFT + +1F832 +RIGHTWARDS TRIANGLE-HEADED ARROW WITH VERY HEAVY SHAFT + +1F833 +DOWNWARDS TRIANGLE-HEADED ARROW WITH VERY HEAVY SHAFT + +1F834 +LEFTWARDS FINGER-POST ARROW + +1F835 +UPWARDS FINGER-POST ARROW + +1F836 +RIGHTWARDS FINGER-POST ARROW + +1F837 +DOWNWARDS FINGER-POST ARROW + +1F838 +LEFTWARDS SQUARED ARROW + +1F839 +UPWARDS SQUARED ARROW + +1F83A +RIGHTWARDS SQUARED ARROW + +1F83B +DOWNWARDS SQUARED ARROW + +1F83C +LEFTWARDS COMPRESSED ARROW + +1F83D +UPWARDS COMPRESSED ARROW + +1F83E +RIGHTWARDS COMPRESSED ARROW + +1F83F +DOWNWARDS COMPRESSED ARROW + +1F840 +LEFTWARDS HEAVY COMPRESSED ARROW + +1F841 +UPWARDS HEAVY COMPRESSED ARROW + +1F842 +RIGHTWARDS HEAVY COMPRESSED ARROW + +1F843 +DOWNWARDS HEAVY COMPRESSED ARROW + +1F844 +LEFTWARDS HEAVY ARROW + +1F845 +UPWARDS HEAVY ARROW + +1F846 +RIGHTWARDS HEAVY ARROW + +1F847 +DOWNWARDS HEAVY ARROW + +1F850 +LEFTWARDS SANS-SERIF ARROW + +1F851 +UPWARDS SANS-SERIF ARROW + +1F852 +RIGHTWARDS SANS-SERIF ARROW + +1F853 +DOWNWARDS SANS-SERIF ARROW + +1F854 +NORTH WEST SANS-SERIF ARROW + +1F855 +NORTH EAST SANS-SERIF ARROW + +1F856 +SOUTH EAST SANS-SERIF ARROW + +1F857 +SOUTH WEST SANS-SERIF ARROW + +1F858 +LEFT RIGHT SANS-SERIF ARROW + +1F859 +UP DOWN SANS-SERIF ARROW + +1F860 +WIDE-HEADED LEFTWARDS LIGHT BARB ARROW + +1F861 +WIDE-HEADED UPWARDS LIGHT BARB ARROW + +1F862 +WIDE-HEADED RIGHTWARDS LIGHT BARB ARROW + +1F863 +WIDE-HEADED DOWNWARDS LIGHT BARB ARROW + +1F864 +WIDE-HEADED NORTH WEST LIGHT BARB ARROW + +1F865 +WIDE-HEADED NORTH EAST LIGHT BARB ARROW + +1F866 +WIDE-HEADED SOUTH EAST LIGHT BARB ARROW + +1F867 +WIDE-HEADED SOUTH WEST LIGHT BARB ARROW + +1F868 +WIDE-HEADED LEFTWARDS BARB ARROW + +1F869 +WIDE-HEADED UPWARDS BARB ARROW + +1F86A +WIDE-HEADED RIGHTWARDS BARB ARROW + +1F86B +WIDE-HEADED DOWNWARDS BARB ARROW + +1F86C +WIDE-HEADED NORTH WEST BARB ARROW + +1F86D +WIDE-HEADED NORTH EAST BARB ARROW + +1F86E +WIDE-HEADED SOUTH EAST BARB ARROW + +1F86F +WIDE-HEADED SOUTH WEST BARB ARROW + +1F870 +WIDE-HEADED LEFTWARDS MEDIUM BARB ARROW + +1F871 +WIDE-HEADED UPWARDS MEDIUM BARB ARROW + +1F872 +WIDE-HEADED RIGHTWARDS MEDIUM BARB ARROW + +1F873 +WIDE-HEADED DOWNWARDS MEDIUM BARB ARROW + +1F874 +WIDE-HEADED NORTH WEST MEDIUM BARB ARROW + +1F875 +WIDE-HEADED NORTH EAST MEDIUM BARB ARROW + +1F876 +WIDE-HEADED SOUTH EAST MEDIUM BARB ARROW + +1F877 +WIDE-HEADED SOUTH WEST MEDIUM BARB ARROW + +1F878 +WIDE-HEADED LEFTWARDS HEAVY BARB ARROW + +1F879 +WIDE-HEADED UPWARDS HEAVY BARB ARROW + +1F87A +WIDE-HEADED RIGHTWARDS HEAVY BARB ARROW + +1F87B +WIDE-HEADED DOWNWARDS HEAVY BARB ARROW + +1F87C +WIDE-HEADED NORTH WEST HEAVY BARB ARROW + +1F87D +WIDE-HEADED NORTH EAST HEAVY BARB ARROW + +1F87E +WIDE-HEADED SOUTH EAST HEAVY BARB ARROW + +1F87F +WIDE-HEADED SOUTH WEST HEAVY BARB ARROW + +1F880 +WIDE-HEADED LEFTWARDS VERY HEAVY BARB ARROW + +1F881 +WIDE-HEADED UPWARDS VERY HEAVY BARB ARROW + +1F882 +WIDE-HEADED RIGHTWARDS VERY HEAVY BARB ARROW + +1F883 +WIDE-HEADED DOWNWARDS VERY HEAVY BARB ARROW + +1F884 +WIDE-HEADED NORTH WEST VERY HEAVY BARB ARROW + +1F885 +WIDE-HEADED NORTH EAST VERY HEAVY BARB ARROW + +1F886 +WIDE-HEADED SOUTH EAST VERY HEAVY BARB ARROW + +1F887 +WIDE-HEADED SOUTH WEST VERY HEAVY BARB ARROW + +1F890 +LEFTWARDS TRIANGLE ARROWHEAD + +1F891 +UPWARDS TRIANGLE ARROWHEAD + +1F892 +RIGHTWARDS TRIANGLE ARROWHEAD + +1F893 +DOWNWARDS TRIANGLE ARROWHEAD + +1F894 +LEFTWARDS WHITE ARROW WITHIN TRIANGLE ARROWHEAD + +1F895 +UPWARDS WHITE ARROW WITHIN TRIANGLE ARROWHEAD + +1F896 +RIGHTWARDS WHITE ARROW WITHIN TRIANGLE ARROWHEAD + +1F897 +DOWNWARDS WHITE ARROW WITHIN TRIANGLE ARROWHEAD + +1F898 +LEFTWARDS ARROW WITH NOTCHED TAIL + +1F899 +UPWARDS ARROW WITH NOTCHED TAIL + +1F89A +RIGHTWARDS ARROW WITH NOTCHED TAIL + +1F89B +DOWNWARDS ARROW WITH NOTCHED TAIL + +1F89C +HEAVY ARROW SHAFT WIDTH ONE + +1F89D +HEAVY ARROW SHAFT WIDTH TWO THIRDS + +1F89E +HEAVY ARROW SHAFT WIDTH ONE HALF + +1F89F +HEAVY ARROW SHAFT WIDTH ONE THIRD + +1F8A0 +LEFTWARDS BOTTOM-SHADED WHITE ARROW + +1F8A1 +RIGHTWARDS BOTTOM SHADED WHITE ARROW + +1F8A2 +LEFTWARDS TOP SHADED WHITE ARROW + +1F8A3 +RIGHTWARDS TOP SHADED WHITE ARROW + +1F8A4 +LEFTWARDS LEFT-SHADED WHITE ARROW + +1F8A5 +RIGHTWARDS RIGHT-SHADED WHITE ARROW + +1F8A6 +LEFTWARDS RIGHT-SHADED WHITE ARROW + +1F8A7 +RIGHTWARDS LEFT-SHADED WHITE ARROW + +1F8A8 +LEFTWARDS BACK-TILTED SHADOWED WHITE ARROW + +1F8A9 +RIGHTWARDS BACK-TILTED SHADOWED WHITE ARROW + +1F8AA +LEFTWARDS FRONT-TILTED SHADOWED WHITE ARROW + +1F8AB +RIGHTWARDS FRONT-TILTED SHADOWED WHITE ARROW + +1F8AC +WHITE ARROW SHAFT WIDTH ONE + +1F8AD +WHITE ARROW SHAFT WIDTH TWO THIRDS + +1F8B0 +ARROW POINTING UPWARDS THEN NORTH WEST + +1F8B1 +ARROW POINTING RIGHTWARDS THEN CURVING SOUTH WEST + +1F8B2 +RIGHTWARDS ARROW WITH LOWER HOOK + +1F8B3 +DOWNWARDS BLACK ARROW TO BAR + +1F8B4 +NEGATIVE SQUARED LEFTWARDS ARROW + +1F8B5 +NEGATIVE SQUARED UPWARDS ARROW + +1F8B6 +NEGATIVE SQUARED RIGHTWARDS ARROW + +1F8B7 +NEGATIVE SQUARED DOWNWARDS ARROW + +1F8B8 +NORTH WEST ARROW FROM BAR + +1F8B9 +NORTH EAST ARROW FROM BAR + +1F8BA +SOUTH EAST ARROW FROM BAR + +1F8BB +SOUTH WEST ARROW FROM BAR + +1F8C0 +LEFTWARDS ARROW FROM DOWNWARDS ARROW + +1F8C1 +RIGHTWARDS ARROW FROM DOWNWARDS ARROW + +1F8D0 +LONG RIGHTWARDS ARROW OVER LONG LEFTWARDS ARROW + +1F8D1 +LONG RIGHTWARDS HARPOON OVER LONG LEFTWARDS HARPOON + +1F8D2 +LONG RIGHTWARDS HARPOON ABOVE SHORT LEFTWARDS HARPOON + +1F8D3 +SHORT RIGHTWARDS HARPOON ABOVE LONG LEFTWARDS HARPOON + +1F8D4 +LONG LEFTWARDS HARPOON ABOVE SHORT RIGHTWARDS HARPOON + +1F8D5 +SHORT LEFTWARDS HARPOON ABOVE LONG RIGHTWARDS HARPOON + +1F8D6 +LONG RIGHTWARDS ARROW THROUGH X + +1F8D7 +LONG RIGHTWARDS ARROW WITH DOUBLE SLASH + +1F8D8 +LONG LEFT RIGHT ARROW WITH DEPENDENT LOBE + +1F900 +CIRCLED CROSS FORMEE WITH FOUR DOTS + +1F901 +CIRCLED CROSS FORMEE WITH TWO DOTS + +1F902 +CIRCLED CROSS FORMEE + +1F903 +LEFT HALF CIRCLE WITH FOUR DOTS + +1F904 +LEFT HALF CIRCLE WITH THREE DOTS + +1F905 +LEFT HALF CIRCLE WITH TWO DOTS + +1F906 +LEFT HALF CIRCLE WITH DOT + +1F907 +LEFT HALF CIRCLE + +1F908 +DOWNWARD FACING HOOK + +1F909 +DOWNWARD FACING NOTCHED HOOK + +1F90A +DOWNWARD FACING HOOK WITH DOT + +1F90B +DOWNWARD FACING NOTCHED HOOK WITH DOT + +1F90C +PINCHED FINGERS + +1F90D +WHITE HEART + +1F90E +BROWN HEART + +1F90F +PINCHING HAND + +1F910 +ZIPPER-MOUTH FACE + +1F911 +MONEY-MOUTH FACE + +1F912 +FACE WITH THERMOMETER + +1F913 +NERD FACE + +1F914 +THINKING FACE + +1F915 +FACE WITH HEAD-BANDAGE + +1F916 +ROBOT FACE + +1F917 +HUGGING FACE + +1F918 +SIGN OF THE HORNS + +1F919 +CALL ME HAND + +1F91A +RAISED BACK OF HAND + +1F91B +LEFT-FACING FIST + +1F91C +RIGHT-FACING FIST + +1F91D +HANDSHAKE + +1F91E +HAND WITH INDEX AND MIDDLE FINGERS CROSSED + +1F91F +I LOVE YOU HAND SIGN + +1F920 +FACE WITH COWBOY HAT + +1F921 +CLOWN FACE + +1F922 +NAUSEATED FACE + +1F923 +ROLLING ON THE FLOOR LAUGHING + +1F924 +DROOLING FACE + +1F925 +LYING FACE + +1F926 +FACE PALM + +1F927 +SNEEZING FACE + +1F928 +FACE WITH ONE EYEBROW RAISED + +1F929 +GRINNING FACE WITH STAR EYES + +1F92A +GRINNING FACE WITH ONE LARGE AND ONE SMALL EYE + +1F92B +FACE WITH FINGER COVERING CLOSED LIPS + +1F92C +SERIOUS FACE WITH SYMBOLS COVERING MOUTH + +1F92D +SMILING FACE WITH SMILING EYES AND HAND COVERING MOUTH + +1F92E +FACE WITH OPEN MOUTH VOMITING + +1F92F +SHOCKED FACE WITH EXPLODING HEAD + +1F930 +PREGNANT WOMAN + +1F931 +BREAST-FEEDING + +1F932 +PALMS UP TOGETHER + +1F933 +SELFIE + +1F934 +PRINCE + +1F935 +MAN IN TUXEDO + +1F936 +MOTHER CHRISTMAS + +1F937 +SHRUG + +1F938 +PERSON DOING CARTWHEEL + +1F939 +JUGGLING + +1F93A +FENCER + +1F93B +MODERN PENTATHLON + +1F93C +WRESTLERS + +1F93D +WATER POLO + +1F93E +HANDBALL + +1F93F +DIVING MASK + +1F940 +WILTED FLOWER + +1F941 +DRUM WITH DRUMSTICKS + +1F942 +CLINKING GLASSES + +1F943 +TUMBLER GLASS + +1F944 +SPOON + +1F945 +GOAL NET + +1F946 +RIFLE + +1F947 +FIRST PLACE MEDAL + +1F948 +SECOND PLACE MEDAL + +1F949 +THIRD PLACE MEDAL + +1F94A +BOXING GLOVE + +1F94B +MARTIAL ARTS UNIFORM + +1F94C +CURLING STONE + +1F94D +LACROSSE STICK AND BALL + +1F94E +SOFTBALL + +1F94F +FLYING DISC + +1F950 +CROISSANT + +1F951 +AVOCADO + +1F952 +CUCUMBER + +1F953 +BACON + +1F954 +POTATO + +1F955 +CARROT + +1F956 +BAGUETTE BREAD + +1F957 +GREEN SALAD + +1F958 +SHALLOW PAN OF FOOD + +1F959 +STUFFED FLATBREAD + +1F95A +EGG + +1F95B +GLASS OF MILK + +1F95C +PEANUTS + +1F95D +KIWIFRUIT + +1F95E +PANCAKES + +1F95F +DUMPLING + +1F960 +FORTUNE COOKIE + +1F961 +TAKEOUT BOX + +1F962 +CHOPSTICKS + +1F963 +BOWL WITH SPOON + +1F964 +CUP WITH STRAW + +1F965 +COCONUT + +1F966 +BROCCOLI + +1F967 +PIE + +1F968 +PRETZEL + +1F969 +CUT OF MEAT + +1F96A +SANDWICH + +1F96B +CANNED FOOD + +1F96C +LEAFY GREEN + +1F96D +MANGO + +1F96E +MOON CAKE + +1F96F +BAGEL + +1F970 +SMILING FACE WITH SMILING EYES AND THREE HEARTS + +1F971 +YAWNING FACE + +1F972 +SMILING FACE WITH TEAR + +1F973 +FACE WITH PARTY HORN AND PARTY HAT + +1F974 +FACE WITH UNEVEN EYES AND WAVY MOUTH + +1F975 +OVERHEATED FACE + +1F976 +FREEZING FACE + +1F977 +NINJA + +1F978 +DISGUISED FACE + +1F979 +FACE HOLDING BACK TEARS + +1F97A +FACE WITH PLEADING EYES + +1F97B +SARI + +1F97C +LAB COAT + +1F97D +GOGGLES + +1F97E +HIKING BOOT + +1F97F +FLAT SHOE + +1F980 +CRAB + +1F981 +LION FACE + +1F982 +SCORPION + +1F983 +TURKEY + +1F984 +UNICORN FACE + +1F985 +EAGLE + +1F986 +DUCK + +1F987 +BAT + +1F988 +SHARK + +1F989 +OWL + +1F98A +FOX FACE + +1F98B +BUTTERFLY + +1F98C +DEER + +1F98D +GORILLA + +1F98E +LIZARD + +1F98F +RHINOCEROS + +1F990 +SHRIMP + +1F991 +SQUID + +1F992 +GIRAFFE FACE + +1F993 +ZEBRA FACE + +1F994 +HEDGEHOG + +1F995 +SAUROPOD + +1F996 +T-REX + +1F997 +CRICKET + +1F998 +KANGAROO + +1F999 +LLAMA + +1F99A +PEACOCK + +1F99B +HIPPOPOTAMUS + +1F99C +PARROT + +1F99D +RACCOON + +1F99E +LOBSTER + +1F99F +MOSQUITO + +1F9A0 +MICROBE + +1F9A1 +BADGER + +1F9A2 +SWAN + +1F9A3 +MAMMOTH + +1F9A4 +DODO + +1F9A5 +SLOTH + +1F9A6 +OTTER + +1F9A7 +ORANGUTAN + +1F9A8 +SKUNK + +1F9A9 +FLAMINGO + +1F9AA +OYSTER + +1F9AB +BEAVER + +1F9AC +BISON + +1F9AD +SEAL + +1F9AE +GUIDE DOG + +1F9AF +PROBING CANE + +1F9B0 +EMOJI COMPONENT RED HAIR + +1F9B1 +EMOJI COMPONENT CURLY HAIR + +1F9B2 +EMOJI COMPONENT BALD + +1F9B3 +EMOJI COMPONENT WHITE HAIR + +1F9B4 +BONE + +1F9B5 +LEG + +1F9B6 +FOOT + +1F9B7 +TOOTH + +1F9B8 +SUPERHERO + +1F9B9 +SUPERVILLAIN + +1F9BA +SAFETY VEST + +1F9BB +EAR WITH HEARING AID + +1F9BC +MOTORIZED WHEELCHAIR + +1F9BD +MANUAL WHEELCHAIR + +1F9BE +MECHANICAL ARM + +1F9BF +MECHANICAL LEG + +1F9C0 +CHEESE WEDGE + +1F9C1 +CUPCAKE + +1F9C2 +SALT SHAKER + +1F9C3 +BEVERAGE BOX + +1F9C4 +GARLIC + +1F9C5 +ONION + +1F9C6 +FALAFEL + +1F9C7 +WAFFLE + +1F9C8 +BUTTER + +1F9C9 +MATE DRINK + +1F9CA +ICE CUBE + +1F9CB +BUBBLE TEA + +1F9CC +TROLL + +1F9CD +STANDING PERSON + +1F9CE +KNEELING PERSON + +1F9CF +DEAF PERSON + +1F9D0 +FACE WITH MONOCLE + +1F9D1 +ADULT + +1F9D2 +CHILD + +1F9D3 +OLDER ADULT + +1F9D4 +BEARDED PERSON + +1F9D5 +PERSON WITH HEADSCARF + +1F9D6 +PERSON IN STEAMY ROOM + +1F9D7 +PERSON CLIMBING + +1F9D8 +PERSON IN LOTUS POSITION + +1F9D9 +MAGE + +1F9DA +FAIRY + +1F9DB +VAMPIRE + +1F9DC +MERPERSON + +1F9DD +ELF + +1F9DE +GENIE + +1F9DF +ZOMBIE + +1F9E0 +BRAIN + +1F9E1 +ORANGE HEART + +1F9E2 +BILLED CAP + +1F9E3 +SCARF + +1F9E4 +GLOVES + +1F9E5 +COAT + +1F9E6 +SOCKS + +1F9E7 +RED GIFT ENVELOPE + +1F9E8 +FIRECRACKER + +1F9E9 +JIGSAW PUZZLE PIECE + +1F9EA +TEST TUBE + +1F9EB +PETRI DISH + +1F9EC +DNA DOUBLE HELIX + +1F9ED +COMPASS + +1F9EE +ABACUS + +1F9EF +FIRE EXTINGUISHER + +1F9F0 +TOOLBOX + +1F9F1 +BRICK + +1F9F2 +MAGNET + +1F9F3 +LUGGAGE + +1F9F4 +LOTION BOTTLE + +1F9F5 +SPOOL OF THREAD + +1F9F6 +BALL OF YARN + +1F9F7 +SAFETY PIN + +1F9F8 +TEDDY BEAR + +1F9F9 +BROOM + +1F9FA +BASKET + +1F9FB +ROLL OF PAPER + +1F9FC +BAR OF SOAP + +1F9FD +SPONGE + +1F9FE +RECEIPT + +1F9FF +NAZAR AMULET + +1FA00 +NEUTRAL CHESS KING + +1FA01 +NEUTRAL CHESS QUEEN + +1FA02 +NEUTRAL CHESS ROOK + +1FA03 +NEUTRAL CHESS BISHOP + +1FA04 +NEUTRAL CHESS KNIGHT + +1FA05 +NEUTRAL CHESS PAWN + +1FA06 +WHITE CHESS KNIGHT ROTATED FORTY-FIVE DEGREES + +1FA07 +BLACK CHESS KNIGHT ROTATED FORTY-FIVE DEGREES + +1FA08 +NEUTRAL CHESS KNIGHT ROTATED FORTY-FIVE DEGREES + +1FA09 +WHITE CHESS KING ROTATED NINETY DEGREES + +1FA0A +WHITE CHESS QUEEN ROTATED NINETY DEGREES + +1FA0B +WHITE CHESS ROOK ROTATED NINETY DEGREES + +1FA0C +WHITE CHESS BISHOP ROTATED NINETY DEGREES + +1FA0D +WHITE CHESS KNIGHT ROTATED NINETY DEGREES + +1FA0E +WHITE CHESS PAWN ROTATED NINETY DEGREES + +1FA0F +BLACK CHESS KING ROTATED NINETY DEGREES + +1FA10 +BLACK CHESS QUEEN ROTATED NINETY DEGREES + +1FA11 +BLACK CHESS ROOK ROTATED NINETY DEGREES + +1FA12 +BLACK CHESS BISHOP ROTATED NINETY DEGREES + +1FA13 +BLACK CHESS KNIGHT ROTATED NINETY DEGREES + +1FA14 +BLACK CHESS PAWN ROTATED NINETY DEGREES + +1FA15 +NEUTRAL CHESS KING ROTATED NINETY DEGREES + +1FA16 +NEUTRAL CHESS QUEEN ROTATED NINETY DEGREES + +1FA17 +NEUTRAL CHESS ROOK ROTATED NINETY DEGREES + +1FA18 +NEUTRAL CHESS BISHOP ROTATED NINETY DEGREES + +1FA19 +NEUTRAL CHESS KNIGHT ROTATED NINETY DEGREES + +1FA1A +NEUTRAL CHESS PAWN ROTATED NINETY DEGREES + +1FA1B +WHITE CHESS KNIGHT ROTATED ONE HUNDRED THIRTY-FIVE DEGREES + +1FA1C +BLACK CHESS KNIGHT ROTATED ONE HUNDRED THIRTY-FIVE DEGREES + +1FA1D +NEUTRAL CHESS KNIGHT ROTATED ONE HUNDRED THIRTY-FIVE DEGREES + +1FA1E +WHITE CHESS TURNED KING + +1FA1F +WHITE CHESS TURNED QUEEN + +1FA20 +WHITE CHESS TURNED ROOK + +1FA21 +WHITE CHESS TURNED BISHOP + +1FA22 +WHITE CHESS TURNED KNIGHT + +1FA23 +WHITE CHESS TURNED PAWN + +1FA24 +BLACK CHESS TURNED KING + +1FA25 +BLACK CHESS TURNED QUEEN + +1FA26 +BLACK CHESS TURNED ROOK + +1FA27 +BLACK CHESS TURNED BISHOP + +1FA28 +BLACK CHESS TURNED KNIGHT + +1FA29 +BLACK CHESS TURNED PAWN + +1FA2A +NEUTRAL CHESS TURNED KING + +1FA2B +NEUTRAL CHESS TURNED QUEEN + +1FA2C +NEUTRAL CHESS TURNED ROOK + +1FA2D +NEUTRAL CHESS TURNED BISHOP + +1FA2E +NEUTRAL CHESS TURNED KNIGHT + +1FA2F +NEUTRAL CHESS TURNED PAWN + +1FA30 +WHITE CHESS KNIGHT ROTATED TWO HUNDRED TWENTY-FIVE DEGREES + +1FA31 +BLACK CHESS KNIGHT ROTATED TWO HUNDRED TWENTY-FIVE DEGREES + +1FA32 +NEUTRAL CHESS KNIGHT ROTATED TWO HUNDRED TWENTY-FIVE DEGREES + +1FA33 +WHITE CHESS KING ROTATED TWO HUNDRED SEVENTY DEGREES + +1FA34 +WHITE CHESS QUEEN ROTATED TWO HUNDRED SEVENTY DEGREES + +1FA35 +WHITE CHESS ROOK ROTATED TWO HUNDRED SEVENTY DEGREES + +1FA36 +WHITE CHESS BISHOP ROTATED TWO HUNDRED SEVENTY DEGREES + +1FA37 +WHITE CHESS KNIGHT ROTATED TWO HUNDRED SEVENTY DEGREES + +1FA38 +WHITE CHESS PAWN ROTATED TWO HUNDRED SEVENTY DEGREES + +1FA39 +BLACK CHESS KING ROTATED TWO HUNDRED SEVENTY DEGREES + +1FA3A +BLACK CHESS QUEEN ROTATED TWO HUNDRED SEVENTY DEGREES + +1FA3B +BLACK CHESS ROOK ROTATED TWO HUNDRED SEVENTY DEGREES + +1FA3C +BLACK CHESS BISHOP ROTATED TWO HUNDRED SEVENTY DEGREES + +1FA3D +BLACK CHESS KNIGHT ROTATED TWO HUNDRED SEVENTY DEGREES + +1FA3E +BLACK CHESS PAWN ROTATED TWO HUNDRED SEVENTY DEGREES + +1FA3F +NEUTRAL CHESS KING ROTATED TWO HUNDRED SEVENTY DEGREES + +1FA40 +NEUTRAL CHESS QUEEN ROTATED TWO HUNDRED SEVENTY DEGREES + +1FA41 +NEUTRAL CHESS ROOK ROTATED TWO HUNDRED SEVENTY DEGREES + +1FA42 +NEUTRAL CHESS BISHOP ROTATED TWO HUNDRED SEVENTY DEGREES + +1FA43 +NEUTRAL CHESS KNIGHT ROTATED TWO HUNDRED SEVENTY DEGREES + +1FA44 +NEUTRAL CHESS PAWN ROTATED TWO HUNDRED SEVENTY DEGREES + +1FA45 +WHITE CHESS KNIGHT ROTATED THREE HUNDRED FIFTEEN DEGREES + +1FA46 +BLACK CHESS KNIGHT ROTATED THREE HUNDRED FIFTEEN DEGREES + +1FA47 +NEUTRAL CHESS KNIGHT ROTATED THREE HUNDRED FIFTEEN DEGREES + +1FA48 +WHITE CHESS EQUIHOPPER + +1FA49 +BLACK CHESS EQUIHOPPER + +1FA4A +NEUTRAL CHESS EQUIHOPPER + +1FA4B +WHITE CHESS EQUIHOPPER ROTATED NINETY DEGREES + +1FA4C +BLACK CHESS EQUIHOPPER ROTATED NINETY DEGREES + +1FA4D +NEUTRAL CHESS EQUIHOPPER ROTATED NINETY DEGREES + +1FA4E +WHITE CHESS KNIGHT-QUEEN + +1FA4F +WHITE CHESS KNIGHT-ROOK + +1FA50 +WHITE CHESS KNIGHT-BISHOP + +1FA51 +BLACK CHESS KNIGHT-QUEEN + +1FA52 +BLACK CHESS KNIGHT-ROOK + +1FA53 +BLACK CHESS KNIGHT-BISHOP + +1FA54 +WHITE CHESS FERZ + +1FA55 +WHITE CHESS ALFIL + +1FA56 +BLACK CHESS FERZ + +1FA57 +BLACK CHESS ALFIL + +1FA60 +XIANGQI RED GENERAL + +1FA61 +XIANGQI RED MANDARIN + +1FA62 +XIANGQI RED ELEPHANT + +1FA63 +XIANGQI RED HORSE + +1FA64 +XIANGQI RED CHARIOT + +1FA65 +XIANGQI RED CANNON + +1FA66 +XIANGQI RED SOLDIER + +1FA67 +XIANGQI BLACK GENERAL + +1FA68 +XIANGQI BLACK MANDARIN + +1FA69 +XIANGQI BLACK ELEPHANT + +1FA6A +XIANGQI BLACK HORSE + +1FA6B +XIANGQI BLACK CHARIOT + +1FA6C +XIANGQI BLACK CANNON + +1FA6D +XIANGQI BLACK SOLDIER + +1FA70 +BALLET SHOES + +1FA71 +ONE-PIECE SWIMSUIT + +1FA72 +BRIEFS + +1FA73 +SHORTS + +1FA74 +THONG SANDAL + +1FA75 +LIGHT BLUE HEART + +1FA76 +GREY HEART + +1FA77 +PINK HEART + +1FA78 +DROP OF BLOOD + +1FA79 +ADHESIVE BANDAGE + +1FA7A +STETHOSCOPE + +1FA7B +X-RAY + +1FA7C +CRUTCH + +1FA80 +YO-YO + +1FA81 +KITE + +1FA82 +PARACHUTE + +1FA83 +BOOMERANG + +1FA84 +MAGIC WAND + +1FA85 +PINATA + +1FA86 +NESTING DOLLS + +1FA87 +MARACAS + +1FA88 +FLUTE + +1FA89 +HARP + +1FA8A +TROMBONE + +1FA8E +TREASURE CHEST + +1FA8F +SHOVEL + +1FA90 +RINGED PLANET + +1FA91 +CHAIR + +1FA92 +RAZOR + +1FA93 +AXE + +1FA94 +DIYA LAMP + +1FA95 +BANJO + +1FA96 +MILITARY HELMET + +1FA97 +ACCORDION + +1FA98 +LONG DRUM + +1FA99 +COIN + +1FA9A +CARPENTRY SAW + +1FA9B +SCREWDRIVER + +1FA9C +LADDER + +1FA9D +HOOK + +1FA9E +MIRROR + +1FA9F +WINDOW + +1FAA0 +PLUNGER + +1FAA1 +SEWING NEEDLE + +1FAA2 +KNOT + +1FAA3 +BUCKET + +1FAA4 +MOUSE TRAP + +1FAA5 +TOOTHBRUSH + +1FAA6 +HEADSTONE + +1FAA7 +PLACARD + +1FAA8 +ROCK + +1FAA9 +MIRROR BALL + +1FAAA +IDENTIFICATION CARD + +1FAAB +LOW BATTERY + +1FAAC +HAMSA + +1FAAD +FOLDING HAND FAN + +1FAAE +HAIR PICK + +1FAAF +KHANDA + +1FAB0 +FLY + +1FAB1 +WORM + +1FAB2 +BEETLE + +1FAB3 +COCKROACH + +1FAB4 +POTTED PLANT + +1FAB5 +WOOD + +1FAB6 +FEATHER + +1FAB7 +LOTUS + +1FAB8 +CORAL + +1FAB9 +EMPTY NEST + +1FABA +NEST WITH EGGS + +1FABB +HYACINTH + +1FABC +JELLYFISH + +1FABD +WING + +1FABE +LEAFLESS TREE + +1FABF +GOOSE + +1FAC0 +ANATOMICAL HEART + +1FAC1 +LUNGS + +1FAC2 +PEOPLE HUGGING + +1FAC3 +PREGNANT MAN + +1FAC4 +PREGNANT PERSON + +1FAC5 +PERSON WITH CROWN + +1FAC6 +FINGERPRINT + +1FAC8 +HAIRY CREATURE + +1FACD +ORCA + +1FACE +MOOSE + +1FACF +DONKEY + +1FAD0 +BLUEBERRIES + +1FAD1 +BELL PEPPER + +1FAD2 +OLIVE + +1FAD3 +FLATBREAD + +1FAD4 +TAMALE + +1FAD5 +FONDUE + +1FAD6 +TEAPOT + +1FAD7 +POURING LIQUID + +1FAD8 +BEANS + +1FAD9 +JAR + +1FADA +GINGER ROOT + +1FADB +PEA POD + +1FADC +ROOT VEGETABLE + +1FADF +SPLATTER + +1FAE0 +MELTING FACE + +1FAE1 +SALUTING FACE + +1FAE2 +FACE WITH OPEN EYES AND HAND OVER MOUTH + +1FAE3 +FACE WITH PEEKING EYE + +1FAE4 +FACE WITH DIAGONAL MOUTH + +1FAE5 +DOTTED LINE FACE + +1FAE6 +BITING LIP + +1FAE7 +BUBBLES + +1FAE8 +SHAKING FACE + +1FAE9 +FACE WITH BAGS UNDER EYES + +1FAEA +DISTORTED FACE + +1FAEF +FIGHT CLOUD + +1FAF0 +HAND WITH INDEX FINGER AND THUMB CROSSED + +1FAF1 +RIGHTWARDS HAND + +1FAF2 +LEFTWARDS HAND + +1FAF3 +PALM DOWN HAND + +1FAF4 +PALM UP HAND + +1FAF5 +INDEX POINTING AT THE VIEWER + +1FAF6 +HEART HANDS + +1FAF7 +LEFTWARDS PUSHING HAND + +1FAF8 +RIGHTWARDS PUSHING HAND + +1FB00 +BLOCK SEXTANT-1 + +1FB01 +BLOCK SEXTANT-2 + +1FB02 +BLOCK SEXTANT-12 + +1FB03 +BLOCK SEXTANT-3 + +1FB04 +BLOCK SEXTANT-13 + +1FB05 +BLOCK SEXTANT-23 + +1FB06 +BLOCK SEXTANT-123 + +1FB07 +BLOCK SEXTANT-4 + +1FB08 +BLOCK SEXTANT-14 + +1FB09 +BLOCK SEXTANT-24 + +1FB0A +BLOCK SEXTANT-124 + +1FB0B +BLOCK SEXTANT-34 + +1FB0C +BLOCK SEXTANT-134 + +1FB0D +BLOCK SEXTANT-234 + +1FB0E +BLOCK SEXTANT-1234 + +1FB0F +BLOCK SEXTANT-5 + +1FB10 +BLOCK SEXTANT-15 + +1FB11 +BLOCK SEXTANT-25 + +1FB12 +BLOCK SEXTANT-125 + +1FB13 +BLOCK SEXTANT-35 + +1FB14 +BLOCK SEXTANT-235 + +1FB15 +BLOCK SEXTANT-1235 + +1FB16 +BLOCK SEXTANT-45 + +1FB17 +BLOCK SEXTANT-145 + +1FB18 +BLOCK SEXTANT-245 + +1FB19 +BLOCK SEXTANT-1245 + +1FB1A +BLOCK SEXTANT-345 + +1FB1B +BLOCK SEXTANT-1345 + +1FB1C +BLOCK SEXTANT-2345 + +1FB1D +BLOCK SEXTANT-12345 + +1FB1E +BLOCK SEXTANT-6 + +1FB1F +BLOCK SEXTANT-16 + +1FB20 +BLOCK SEXTANT-26 + +1FB21 +BLOCK SEXTANT-126 + +1FB22 +BLOCK SEXTANT-36 + +1FB23 +BLOCK SEXTANT-136 + +1FB24 +BLOCK SEXTANT-236 + +1FB25 +BLOCK SEXTANT-1236 + +1FB26 +BLOCK SEXTANT-46 + +1FB27 +BLOCK SEXTANT-146 + +1FB28 +BLOCK SEXTANT-1246 + +1FB29 +BLOCK SEXTANT-346 + +1FB2A +BLOCK SEXTANT-1346 + +1FB2B +BLOCK SEXTANT-2346 + +1FB2C +BLOCK SEXTANT-12346 + +1FB2D +BLOCK SEXTANT-56 + +1FB2E +BLOCK SEXTANT-156 + +1FB2F +BLOCK SEXTANT-256 + +1FB30 +BLOCK SEXTANT-1256 + +1FB31 +BLOCK SEXTANT-356 + +1FB32 +BLOCK SEXTANT-1356 + +1FB33 +BLOCK SEXTANT-2356 + +1FB34 +BLOCK SEXTANT-12356 + +1FB35 +BLOCK SEXTANT-456 + +1FB36 +BLOCK SEXTANT-1456 + +1FB37 +BLOCK SEXTANT-2456 + +1FB38 +BLOCK SEXTANT-12456 + +1FB39 +BLOCK SEXTANT-3456 + +1FB3A +BLOCK SEXTANT-13456 + +1FB3B +BLOCK SEXTANT-23456 + +1FB3C +LOWER LEFT BLOCK DIAGONAL LOWER MIDDLE LEFT TO LOWER CENTRE + +1FB3D +LOWER LEFT BLOCK DIAGONAL LOWER MIDDLE LEFT TO LOWER RIGHT + +1FB3E +LOWER LEFT BLOCK DIAGONAL UPPER MIDDLE LEFT TO LOWER CENTRE + +1FB3F +LOWER LEFT BLOCK DIAGONAL UPPER MIDDLE LEFT TO LOWER RIGHT + +1FB40 +LOWER LEFT BLOCK DIAGONAL UPPER LEFT TO LOWER CENTRE + +1FB41 +LOWER RIGHT BLOCK DIAGONAL UPPER MIDDLE LEFT TO UPPER CENTRE + +1FB42 +LOWER RIGHT BLOCK DIAGONAL UPPER MIDDLE LEFT TO UPPER RIGHT + +1FB43 +LOWER RIGHT BLOCK DIAGONAL LOWER MIDDLE LEFT TO UPPER CENTRE + +1FB44 +LOWER RIGHT BLOCK DIAGONAL LOWER MIDDLE LEFT TO UPPER RIGHT + +1FB45 +LOWER RIGHT BLOCK DIAGONAL LOWER LEFT TO UPPER CENTRE + +1FB46 +LOWER RIGHT BLOCK DIAGONAL LOWER MIDDLE LEFT TO UPPER MIDDLE RIGHT + +1FB47 +LOWER RIGHT BLOCK DIAGONAL LOWER CENTRE TO LOWER MIDDLE RIGHT + +1FB48 +LOWER RIGHT BLOCK DIAGONAL LOWER LEFT TO LOWER MIDDLE RIGHT + +1FB49 +LOWER RIGHT BLOCK DIAGONAL LOWER CENTRE TO UPPER MIDDLE RIGHT + +1FB4A +LOWER RIGHT BLOCK DIAGONAL LOWER LEFT TO UPPER MIDDLE RIGHT + +1FB4B +LOWER RIGHT BLOCK DIAGONAL LOWER CENTRE TO UPPER RIGHT + +1FB4C +LOWER LEFT BLOCK DIAGONAL UPPER CENTRE TO UPPER MIDDLE RIGHT + +1FB4D +LOWER LEFT BLOCK DIAGONAL UPPER LEFT TO UPPER MIDDLE RIGHT + +1FB4E +LOWER LEFT BLOCK DIAGONAL UPPER CENTRE TO LOWER MIDDLE RIGHT + +1FB4F +LOWER LEFT BLOCK DIAGONAL UPPER LEFT TO LOWER MIDDLE RIGHT + +1FB50 +LOWER LEFT BLOCK DIAGONAL UPPER CENTRE TO LOWER RIGHT + +1FB51 +LOWER LEFT BLOCK DIAGONAL UPPER MIDDLE LEFT TO LOWER MIDDLE RIGHT + +1FB52 +UPPER RIGHT BLOCK DIAGONAL LOWER MIDDLE LEFT TO LOWER CENTRE + +1FB53 +UPPER RIGHT BLOCK DIAGONAL LOWER MIDDLE LEFT TO LOWER RIGHT + +1FB54 +UPPER RIGHT BLOCK DIAGONAL UPPER MIDDLE LEFT TO LOWER CENTRE + +1FB55 +UPPER RIGHT BLOCK DIAGONAL UPPER MIDDLE LEFT TO LOWER RIGHT + +1FB56 +UPPER RIGHT BLOCK DIAGONAL UPPER LEFT TO LOWER CENTRE + +1FB57 +UPPER LEFT BLOCK DIAGONAL UPPER MIDDLE LEFT TO UPPER CENTRE + +1FB58 +UPPER LEFT BLOCK DIAGONAL UPPER MIDDLE LEFT TO UPPER RIGHT + +1FB59 +UPPER LEFT BLOCK DIAGONAL LOWER MIDDLE LEFT TO UPPER CENTRE + +1FB5A +UPPER LEFT BLOCK DIAGONAL LOWER MIDDLE LEFT TO UPPER RIGHT + +1FB5B +UPPER LEFT BLOCK DIAGONAL LOWER LEFT TO UPPER CENTRE + +1FB5C +UPPER LEFT BLOCK DIAGONAL LOWER MIDDLE LEFT TO UPPER MIDDLE RIGHT + +1FB5D +UPPER LEFT BLOCK DIAGONAL LOWER CENTRE TO LOWER MIDDLE RIGHT + +1FB5E +UPPER LEFT BLOCK DIAGONAL LOWER LEFT TO LOWER MIDDLE RIGHT + +1FB5F +UPPER LEFT BLOCK DIAGONAL LOWER CENTRE TO UPPER MIDDLE RIGHT + +1FB60 +UPPER LEFT BLOCK DIAGONAL LOWER LEFT TO UPPER MIDDLE RIGHT + +1FB61 +UPPER LEFT BLOCK DIAGONAL LOWER CENTRE TO UPPER RIGHT + +1FB62 +UPPER RIGHT BLOCK DIAGONAL UPPER CENTRE TO UPPER MIDDLE RIGHT + +1FB63 +UPPER RIGHT BLOCK DIAGONAL UPPER LEFT TO UPPER MIDDLE RIGHT + +1FB64 +UPPER RIGHT BLOCK DIAGONAL UPPER CENTRE TO LOWER MIDDLE RIGHT + +1FB65 +UPPER RIGHT BLOCK DIAGONAL UPPER LEFT TO LOWER MIDDLE RIGHT + +1FB66 +UPPER RIGHT BLOCK DIAGONAL UPPER CENTRE TO LOWER RIGHT + +1FB67 +UPPER RIGHT BLOCK DIAGONAL UPPER MIDDLE LEFT TO LOWER MIDDLE RIGHT + +1FB68 +UPPER AND RIGHT AND LOWER TRIANGULAR THREE QUARTERS BLOCK + +1FB69 +LEFT AND LOWER AND RIGHT TRIANGULAR THREE QUARTERS BLOCK + +1FB6A +UPPER AND LEFT AND LOWER TRIANGULAR THREE QUARTERS BLOCK + +1FB6B +LEFT AND UPPER AND RIGHT TRIANGULAR THREE QUARTERS BLOCK + +1FB6C +LEFT TRIANGULAR ONE QUARTER BLOCK + +1FB6D +UPPER TRIANGULAR ONE QUARTER BLOCK + +1FB6E +RIGHT TRIANGULAR ONE QUARTER BLOCK + +1FB6F +LOWER TRIANGULAR ONE QUARTER BLOCK + +1FB70 +VERTICAL ONE EIGHTH BLOCK-2 + +1FB71 +VERTICAL ONE EIGHTH BLOCK-3 + +1FB72 +VERTICAL ONE EIGHTH BLOCK-4 + +1FB73 +VERTICAL ONE EIGHTH BLOCK-5 + +1FB74 +VERTICAL ONE EIGHTH BLOCK-6 + +1FB75 +VERTICAL ONE EIGHTH BLOCK-7 + +1FB76 +HORIZONTAL ONE EIGHTH BLOCK-2 + +1FB77 +HORIZONTAL ONE EIGHTH BLOCK-3 + +1FB78 +HORIZONTAL ONE EIGHTH BLOCK-4 + +1FB79 +HORIZONTAL ONE EIGHTH BLOCK-5 + +1FB7A +HORIZONTAL ONE EIGHTH BLOCK-6 + +1FB7B +HORIZONTAL ONE EIGHTH BLOCK-7 + +1FB7C +LEFT AND LOWER ONE EIGHTH BLOCK + +1FB7D +LEFT AND UPPER ONE EIGHTH BLOCK + +1FB7E +RIGHT AND UPPER ONE EIGHTH BLOCK + +1FB7F +RIGHT AND LOWER ONE EIGHTH BLOCK + +1FB80 +UPPER AND LOWER ONE EIGHTH BLOCK + +1FB81 +HORIZONTAL ONE EIGHTH BLOCK-1358 + +1FB82 +UPPER ONE QUARTER BLOCK + +1FB83 +UPPER THREE EIGHTHS BLOCK + +1FB84 +UPPER FIVE EIGHTHS BLOCK + +1FB85 +UPPER THREE QUARTERS BLOCK + +1FB86 +UPPER SEVEN EIGHTHS BLOCK + +1FB87 +RIGHT ONE QUARTER BLOCK + +1FB88 +RIGHT THREE EIGHTHS BLOCK + +1FB89 +RIGHT FIVE EIGHTHS BLOCK + +1FB8A +RIGHT THREE QUARTERS BLOCK + +1FB8B +RIGHT SEVEN EIGHTHS BLOCK + +1FB8C +LEFT HALF MEDIUM SHADE + +1FB8D +RIGHT HALF MEDIUM SHADE + +1FB8E +UPPER HALF MEDIUM SHADE + +1FB8F +LOWER HALF MEDIUM SHADE + +1FB90 +INVERSE MEDIUM SHADE + +1FB91 +UPPER HALF BLOCK AND LOWER HALF INVERSE MEDIUM SHADE + +1FB92 +UPPER HALF INVERSE MEDIUM SHADE AND LOWER HALF BLOCK + +1FB94 +LEFT HALF INVERSE MEDIUM SHADE AND RIGHT HALF BLOCK + +1FB95 +CHECKER BOARD FILL + +1FB96 +INVERSE CHECKER BOARD FILL + +1FB97 +HEAVY HORIZONTAL FILL + +1FB98 +UPPER LEFT TO LOWER RIGHT FILL + +1FB99 +UPPER RIGHT TO LOWER LEFT FILL + +1FB9A +UPPER AND LOWER TRIANGULAR HALF BLOCK + +1FB9B +LEFT AND RIGHT TRIANGULAR HALF BLOCK + +1FB9C +UPPER LEFT TRIANGULAR MEDIUM SHADE + +1FB9D +UPPER RIGHT TRIANGULAR MEDIUM SHADE + +1FB9E +LOWER RIGHT TRIANGULAR MEDIUM SHADE + +1FB9F +LOWER LEFT TRIANGULAR MEDIUM SHADE + +1FBA0 +BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE LEFT + +1FBA1 +BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE RIGHT + +1FBA2 +BOX DRAWINGS LIGHT DIAGONAL MIDDLE LEFT TO LOWER CENTRE + +1FBA3 +BOX DRAWINGS LIGHT DIAGONAL MIDDLE RIGHT TO LOWER CENTRE + +1FBA4 +BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE LEFT TO LOWER CENTRE + +1FBA5 +BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE RIGHT TO LOWER CENTRE + +1FBA6 +BOX DRAWINGS LIGHT DIAGONAL MIDDLE LEFT TO LOWER CENTRE TO MIDDLE RIGHT + +1FBA7 +BOX DRAWINGS LIGHT DIAGONAL MIDDLE LEFT TO UPPER CENTRE TO MIDDLE RIGHT + +1FBA8 +BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE LEFT AND MIDDLE RIGHT TO LOWER CENTRE + +1FBA9 +BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE RIGHT AND MIDDLE LEFT TO LOWER CENTRE + +1FBAA +BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE RIGHT TO LOWER CENTRE TO MIDDLE LEFT + +1FBAB +BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE LEFT TO LOWER CENTRE TO MIDDLE RIGHT + +1FBAC +BOX DRAWINGS LIGHT DIAGONAL MIDDLE LEFT TO UPPER CENTRE TO MIDDLE RIGHT TO LOWER CENTRE + +1FBAD +BOX DRAWINGS LIGHT DIAGONAL MIDDLE RIGHT TO UPPER CENTRE TO MIDDLE LEFT TO LOWER CENTRE + +1FBAE +BOX DRAWINGS LIGHT DIAGONAL DIAMOND + +1FBAF +BOX DRAWINGS LIGHT HORIZONTAL WITH VERTICAL STROKE + +1FBB0 +ARROWHEAD-SHAPED POINTER + +1FBB1 +INVERSE CHECK MARK + +1FBB2 +LEFT HALF RUNNING MAN + +1FBB3 +RIGHT HALF RUNNING MAN + +1FBB4 +INVERSE DOWNWARDS ARROW WITH TIP LEFTWARDS + +1FBB5 +LEFTWARDS ARROW AND UPPER AND LOWER ONE EIGHTH BLOCK + +1FBB6 +RIGHTWARDS ARROW AND UPPER AND LOWER ONE EIGHTH BLOCK + +1FBB7 +DOWNWARDS ARROW AND RIGHT ONE EIGHTH BLOCK + +1FBB8 +UPWARDS ARROW AND RIGHT ONE EIGHTH BLOCK + +1FBB9 +LEFT HALF FOLDER + +1FBBA +RIGHT HALF FOLDER + +1FBBB +VOIDED GREEK CROSS + +1FBBC +RIGHT OPEN SQUARED DOT + +1FBBD +NEGATIVE DIAGONAL CROSS + +1FBBE +NEGATIVE DIAGONAL MIDDLE RIGHT TO LOWER CENTRE + +1FBBF +NEGATIVE DIAGONAL DIAMOND + +1FBC0 +WHITE HEAVY SALTIRE WITH ROUNDED CORNERS + +1FBC1 +LEFT THIRD WHITE RIGHT POINTING INDEX + +1FBC2 +MIDDLE THIRD WHITE RIGHT POINTING INDEX + +1FBC3 +RIGHT THIRD WHITE RIGHT POINTING INDEX + +1FBC4 +NEGATIVE SQUARED QUESTION MARK + +1FBC5 +STICK FIGURE + +1FBC6 +STICK FIGURE WITH ARMS RAISED + +1FBC7 +STICK FIGURE LEANING LEFT + +1FBC8 +STICK FIGURE LEANING RIGHT + +1FBC9 +STICK FIGURE WITH DRESS + +1FBCA +WHITE UP-POINTING CHEVRON + +1FBCB +WHITE CROSS MARK + +1FBCC +RAISED SMALL LEFT SQUARE BRACKET + +1FBCD +BLACK SMALL UP-POINTING CHEVRON + +1FBCE +LEFT TWO THIRDS BLOCK + +1FBCF +LEFT ONE THIRD BLOCK + +1FBD0 +BOX DRAWINGS LIGHT DIAGONAL MIDDLE RIGHT TO LOWER LEFT + +1FBD1 +BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO MIDDLE LEFT + +1FBD2 +BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO MIDDLE RIGHT + +1FBD3 +BOX DRAWINGS LIGHT DIAGONAL MIDDLE LEFT TO LOWER RIGHT + +1FBD4 +BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER CENTRE + +1FBD5 +BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO LOWER RIGHT + +1FBD6 +BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER CENTRE + +1FBD7 +BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO LOWER LEFT + +1FBD8 +BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO MIDDLE CENTRE TO UPPER RIGHT + +1FBD9 +BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO MIDDLE CENTRE TO LOWER RIGHT + +1FBDA +BOX DRAWINGS LIGHT DIAGONAL LOWER LEFT TO MIDDLE CENTRE TO LOWER RIGHT + +1FBDB +BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO MIDDLE CENTRE TO LOWER LEFT + +1FBDC +BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER CENTRE TO UPPER RIGHT + +1FBDD +BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO MIDDLE LEFT TO LOWER RIGHT + +1FBDE +BOX DRAWINGS LIGHT DIAGONAL LOWER LEFT TO UPPER CENTRE TO LOWER RIGHT + +1FBDF +BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO MIDDLE RIGHT TO LOWER LEFT + +1FBE0 +TOP JUSTIFIED LOWER HALF WHITE CIRCLE + +1FBE1 +RIGHT JUSTIFIED LEFT HALF WHITE CIRCLE + +1FBE2 +BOTTOM JUSTIFIED UPPER HALF WHITE CIRCLE + +1FBE3 +LEFT JUSTIFIED RIGHT HALF WHITE CIRCLE + +1FBE4 +UPPER CENTRE ONE QUARTER BLOCK + +1FBE5 +LOWER CENTRE ONE QUARTER BLOCK + +1FBE6 +MIDDLE LEFT ONE QUARTER BLOCK + +1FBE7 +MIDDLE RIGHT ONE QUARTER BLOCK + +1FBE8 +TOP JUSTIFIED LOWER HALF BLACK CIRCLE + +1FBE9 +RIGHT JUSTIFIED LEFT HALF BLACK CIRCLE + +1FBEA +BOTTOM JUSTIFIED UPPER HALF BLACK CIRCLE + +1FBEB +LEFT JUSTIFIED RIGHT HALF BLACK CIRCLE + +1FBEC +TOP RIGHT JUSTIFIED LOWER LEFT QUARTER BLACK CIRCLE + +1FBED +BOTTOM LEFT JUSTIFIED UPPER RIGHT QUARTER BLACK CIRCLE + +1FBEE +BOTTOM RIGHT JUSTIFIED UPPER LEFT QUARTER BLACK CIRCLE + +1FBEF +TOP LEFT JUSTIFIED LOWER RIGHT QUARTER BLACK CIRCLE + +1FBF0 +SEGMENTED DIGIT ZERO + +1FBF1 +SEGMENTED DIGIT ONE + +1FBF2 +SEGMENTED DIGIT TWO + +1FBF3 +SEGMENTED DIGIT THREE + +1FBF4 +SEGMENTED DIGIT FOUR + +1FBF5 +SEGMENTED DIGIT FIVE + +1FBF6 +SEGMENTED DIGIT SIX + +1FBF7 +SEGMENTED DIGIT SEVEN + +1FBF8 +SEGMENTED DIGIT EIGHT + +1FBF9 +SEGMENTED DIGIT NINE + +1FBFA +ALARM BELL SYMBOL + +E0001 +LANGUAGE TAG + +E0020 +TAG SPACE + +E0021 +TAG EXCLAMATION MARK + +E0022 +TAG QUOTATION MARK + +E0023 +TAG NUMBER SIGN + +E0024 +TAG DOLLAR SIGN + +E0025 +TAG PERCENT SIGN + +E0026 +TAG AMPERSAND + +E0027 +TAG APOSTROPHE + +E0028 +TAG LEFT PARENTHESIS + +E0029 +TAG RIGHT PARENTHESIS + +E002A +TAG ASTERISK + +E002B +TAG PLUS SIGN + +E002C +TAG COMMA + +E002D +TAG HYPHEN-MINUS + +E002E +TAG FULL STOP + +E002F +TAG SOLIDUS + +E0030 +TAG DIGIT ZERO + +E0031 +TAG DIGIT ONE + +E0032 +TAG DIGIT TWO + +E0033 +TAG DIGIT THREE + +E0034 +TAG DIGIT FOUR + +E0035 +TAG DIGIT FIVE + +E0036 +TAG DIGIT SIX + +E0037 +TAG DIGIT SEVEN + +E0038 +TAG DIGIT EIGHT + +E0039 +TAG DIGIT NINE + +E003A +TAG COLON + +E003B +TAG SEMICOLON + +E003C +TAG LESS-THAN SIGN + +E003D +TAG EQUALS SIGN + +E003E +TAG GREATER-THAN SIGN + +E003F +TAG QUESTION MARK + +E0040 +TAG COMMERCIAL AT + +E0041 +TAG LATIN CAPITAL LETTER A + +E0042 +TAG LATIN CAPITAL LETTER B + +E0043 +TAG LATIN CAPITAL LETTER C + +E0044 +TAG LATIN CAPITAL LETTER D + +E0045 +TAG LATIN CAPITAL LETTER E + +E0046 +TAG LATIN CAPITAL LETTER F + +E0047 +TAG LATIN CAPITAL LETTER G + +E0048 +TAG LATIN CAPITAL LETTER H + +E0049 +TAG LATIN CAPITAL LETTER I + +E004A +TAG LATIN CAPITAL LETTER J + +E004B +TAG LATIN CAPITAL LETTER K + +E004C +TAG LATIN CAPITAL LETTER L + +E004D +TAG LATIN CAPITAL LETTER M + +E004E +TAG LATIN CAPITAL LETTER N + +E004F +TAG LATIN CAPITAL LETTER O + +E0050 +TAG LATIN CAPITAL LETTER P + +E0051 +TAG LATIN CAPITAL LETTER Q + +E0052 +TAG LATIN CAPITAL LETTER R + +E0053 +TAG LATIN CAPITAL LETTER S + +E0054 +TAG LATIN CAPITAL LETTER T + +E0055 +TAG LATIN CAPITAL LETTER U + +E0056 +TAG LATIN CAPITAL LETTER V + +E0057 +TAG LATIN CAPITAL LETTER W + +E0058 +TAG LATIN CAPITAL LETTER X + +E0059 +TAG LATIN CAPITAL LETTER Y + +E005A +TAG LATIN CAPITAL LETTER Z + +E005B +TAG LEFT SQUARE BRACKET + +E005C +TAG REVERSE SOLIDUS + +E005D +TAG RIGHT SQUARE BRACKET + +E005E +TAG CIRCUMFLEX ACCENT + +E005F +TAG LOW LINE + +E0060 +TAG GRAVE ACCENT + +E0061 +TAG LATIN SMALL LETTER A + +E0062 +TAG LATIN SMALL LETTER B + +E0063 +TAG LATIN SMALL LETTER C + +E0064 +TAG LATIN SMALL LETTER D + +E0065 +TAG LATIN SMALL LETTER E + +E0066 +TAG LATIN SMALL LETTER F + +E0067 +TAG LATIN SMALL LETTER G + +E0068 +TAG LATIN SMALL LETTER H + +E0069 +TAG LATIN SMALL LETTER I + +E006A +TAG LATIN SMALL LETTER J + +E006B +TAG LATIN SMALL LETTER K + +E006C +TAG LATIN SMALL LETTER L + +E006D +TAG LATIN SMALL LETTER M + +E006E +TAG LATIN SMALL LETTER N + +E006F +TAG LATIN SMALL LETTER O + +E0070 +TAG LATIN SMALL LETTER P + +E0071 +TAG LATIN SMALL LETTER Q + +E0072 +TAG LATIN SMALL LETTER R + +E0073 +TAG LATIN SMALL LETTER S + +E0074 +TAG LATIN SMALL LETTER T + +E0075 +TAG LATIN SMALL LETTER U + +E0076 +TAG LATIN SMALL LETTER V + +E0077 +TAG LATIN SMALL LETTER W + +E0078 +TAG LATIN SMALL LETTER X + +E0079 +TAG LATIN SMALL LETTER Y + +E007A +TAG LATIN SMALL LETTER Z + +E007B +TAG LEFT CURLY BRACKET + +E007C +TAG VERTICAL LINE + +E007D +TAG RIGHT CURLY BRACKET + +E007E +TAG TILDE + +E007F +CANCEL TAG + +E0100 +VARIATION SELECTOR-17 + +E0100 +VS17 + +E0101 +VARIATION SELECTOR-18 + +E0101 +VS18 + +E0102 +VARIATION SELECTOR-19 + +E0102 +VS19 + +E0103 +VARIATION SELECTOR-20 + +E0103 +VS20 + +E0104 +VARIATION SELECTOR-21 + +E0104 +VS21 + +E0105 +VARIATION SELECTOR-22 + +E0105 +VS22 + +E0106 +VARIATION SELECTOR-23 + +E0106 +VS23 + +E0107 +VARIATION SELECTOR-24 + +E0107 +VS24 + +E0108 +VARIATION SELECTOR-25 + +E0108 +VS25 + +E0109 +VARIATION SELECTOR-26 + +E0109 +VS26 + +E010A +VARIATION SELECTOR-27 + +E010A +VS27 + +E010B +VARIATION SELECTOR-28 + +E010B +VS28 + +E010C +VARIATION SELECTOR-29 + +E010C +VS29 + +E010D +VARIATION SELECTOR-30 + +E010D +VS30 + +E010E +VARIATION SELECTOR-31 + +E010E +VS31 + +E010F +VARIATION SELECTOR-32 + +E010F +VS32 + +E0110 +VARIATION SELECTOR-33 + +E0110 +VS33 + +E0111 +VARIATION SELECTOR-34 + +E0111 +VS34 + +E0112 +VARIATION SELECTOR-35 + +E0112 +VS35 + +E0113 +VARIATION SELECTOR-36 + +E0113 +VS36 + +E0114 +VARIATION SELECTOR-37 + +E0114 +VS37 + +E0115 +VARIATION SELECTOR-38 + +E0115 +VS38 + +E0116 +VARIATION SELECTOR-39 + +E0116 +VS39 + +E0117 +VARIATION SELECTOR-40 + +E0117 +VS40 + +E0118 +VARIATION SELECTOR-41 + +E0118 +VS41 + +E0119 +VARIATION SELECTOR-42 + +E0119 +VS42 + +E011A +VARIATION SELECTOR-43 + +E011A +VS43 + +E011B +VARIATION SELECTOR-44 + +E011B +VS44 + +E011C +VARIATION SELECTOR-45 + +E011C +VS45 + +E011D +VARIATION SELECTOR-46 + +E011D +VS46 + +E011E +VARIATION SELECTOR-47 + +E011E +VS47 + +E011F +VARIATION SELECTOR-48 + +E011F +VS48 + +E0120 +VARIATION SELECTOR-49 + +E0120 +VS49 + +E0121 +VARIATION SELECTOR-50 + +E0121 +VS50 + +E0122 +VARIATION SELECTOR-51 + +E0122 +VS51 + +E0123 +VARIATION SELECTOR-52 + +E0123 +VS52 + +E0124 +VARIATION SELECTOR-53 + +E0124 +VS53 + +E0125 +VARIATION SELECTOR-54 + +E0125 +VS54 + +E0126 +VARIATION SELECTOR-55 + +E0126 +VS55 + +E0127 +VARIATION SELECTOR-56 + +E0127 +VS56 + +E0128 +VARIATION SELECTOR-57 + +E0128 +VS57 + +E0129 +VARIATION SELECTOR-58 + +E0129 +VS58 + +E012A +VARIATION SELECTOR-59 + +E012A +VS59 + +E012B +VARIATION SELECTOR-60 + +E012B +VS60 + +E012C +VARIATION SELECTOR-61 + +E012C +VS61 + +E012D +VARIATION SELECTOR-62 + +E012D +VS62 + +E012E +VARIATION SELECTOR-63 + +E012E +VS63 + +E012F +VARIATION SELECTOR-64 + +E012F +VS64 + +E0130 +VARIATION SELECTOR-65 + +E0130 +VS65 + +E0131 +VARIATION SELECTOR-66 + +E0131 +VS66 + +E0132 +VARIATION SELECTOR-67 + +E0132 +VS67 + +E0133 +VARIATION SELECTOR-68 + +E0133 +VS68 + +E0134 +VARIATION SELECTOR-69 + +E0134 +VS69 + +E0135 +VARIATION SELECTOR-70 + +E0135 +VS70 + +E0136 +VARIATION SELECTOR-71 + +E0136 +VS71 + +E0137 +VARIATION SELECTOR-72 + +E0137 +VS72 + +E0138 +VARIATION SELECTOR-73 + +E0138 +VS73 + +E0139 +VARIATION SELECTOR-74 + +E0139 +VS74 + +E013A +VARIATION SELECTOR-75 + +E013A +VS75 + +E013B +VARIATION SELECTOR-76 + +E013B +VS76 + +E013C +VARIATION SELECTOR-77 + +E013C +VS77 + +E013D +VARIATION SELECTOR-78 + +E013D +VS78 + +E013E +VARIATION SELECTOR-79 + +E013E +VS79 + +E013F +VARIATION SELECTOR-80 + +E013F +VS80 + +E0140 +VARIATION SELECTOR-81 + +E0140 +VS81 + +E0141 +VARIATION SELECTOR-82 + +E0141 +VS82 + +E0142 +VARIATION SELECTOR-83 + +E0142 +VS83 + +E0143 +VARIATION SELECTOR-84 + +E0143 +VS84 + +E0144 +VARIATION SELECTOR-85 + +E0144 +VS85 + +E0145 +VARIATION SELECTOR-86 + +E0145 +VS86 + +E0146 +VARIATION SELECTOR-87 + +E0146 +VS87 + +E0147 +VARIATION SELECTOR-88 + +E0147 +VS88 + +E0148 +VARIATION SELECTOR-89 + +E0148 +VS89 + +E0149 +VARIATION SELECTOR-90 + +E0149 +VS90 + +E014A +VARIATION SELECTOR-91 + +E014A +VS91 + +E014B +VARIATION SELECTOR-92 + +E014B +VS92 + +E014C +VARIATION SELECTOR-93 + +E014C +VS93 + +E014D +VARIATION SELECTOR-94 + +E014D +VS94 + +E014E +VARIATION SELECTOR-95 + +E014E +VS95 + +E014F +VARIATION SELECTOR-96 + +E014F +VS96 + +E0150 +VARIATION SELECTOR-97 + +E0150 +VS97 + +E0151 +VARIATION SELECTOR-98 + +E0151 +VS98 + +E0152 +VARIATION SELECTOR-99 + +E0152 +VS99 + +E0153 +VARIATION SELECTOR-100 + +E0153 +VS100 + +E0154 +VARIATION SELECTOR-101 + +E0154 +VS101 + +E0155 +VARIATION SELECTOR-102 + +E0155 +VS102 + +E0156 +VARIATION SELECTOR-103 + +E0156 +VS103 + +E0157 +VARIATION SELECTOR-104 + +E0157 +VS104 + +E0158 +VARIATION SELECTOR-105 + +E0158 +VS105 + +E0159 +VARIATION SELECTOR-106 + +E0159 +VS106 + +E015A +VARIATION SELECTOR-107 + +E015A +VS107 + +E015B +VARIATION SELECTOR-108 + +E015B +VS108 + +E015C +VARIATION SELECTOR-109 + +E015C +VS109 + +E015D +VARIATION SELECTOR-110 + +E015D +VS110 + +E015E +VARIATION SELECTOR-111 + +E015E +VS111 + +E015F +VARIATION SELECTOR-112 + +E015F +VS112 + +E0160 +VARIATION SELECTOR-113 + +E0160 +VS113 + +E0161 +VARIATION SELECTOR-114 + +E0161 +VS114 + +E0162 +VARIATION SELECTOR-115 + +E0162 +VS115 + +E0163 +VARIATION SELECTOR-116 + +E0163 +VS116 + +E0164 +VARIATION SELECTOR-117 + +E0164 +VS117 + +E0165 +VARIATION SELECTOR-118 + +E0165 +VS118 + +E0166 +VARIATION SELECTOR-119 + +E0166 +VS119 + +E0167 +VARIATION SELECTOR-120 + +E0167 +VS120 + +E0168 +VARIATION SELECTOR-121 + +E0168 +VS121 + +E0169 +VARIATION SELECTOR-122 + +E0169 +VS122 + +E016A +VARIATION SELECTOR-123 + +E016A +VS123 + +E016B +VARIATION SELECTOR-124 + +E016B +VS124 + +E016C +VARIATION SELECTOR-125 + +E016C +VS125 + +E016D +VARIATION SELECTOR-126 + +E016D +VS126 + +E016E +VARIATION SELECTOR-127 + +E016E +VS127 + +E016F +VARIATION SELECTOR-128 + +E016F +VS128 + +E0170 +VARIATION SELECTOR-129 + +E0170 +VS129 + +E0171 +VARIATION SELECTOR-130 + +E0171 +VS130 + +E0172 +VARIATION SELECTOR-131 + +E0172 +VS131 + +E0173 +VARIATION SELECTOR-132 + +E0173 +VS132 + +E0174 +VARIATION SELECTOR-133 + +E0174 +VS133 + +E0175 +VARIATION SELECTOR-134 + +E0175 +VS134 + +E0176 +VARIATION SELECTOR-135 + +E0176 +VS135 + +E0177 +VARIATION SELECTOR-136 + +E0177 +VS136 + +E0178 +VARIATION SELECTOR-137 + +E0178 +VS137 + +E0179 +VARIATION SELECTOR-138 + +E0179 +VS138 + +E017A +VARIATION SELECTOR-139 + +E017A +VS139 + +E017B +VARIATION SELECTOR-140 + +E017B +VS140 + +E017C +VARIATION SELECTOR-141 + +E017C +VS141 + +E017D +VARIATION SELECTOR-142 + +E017D +VS142 + +E017E +VARIATION SELECTOR-143 + +E017E +VS143 + +E017F +VARIATION SELECTOR-144 + +E017F +VS144 + +E0180 +VARIATION SELECTOR-145 + +E0180 +VS145 + +E0181 +VARIATION SELECTOR-146 + +E0181 +VS146 + +E0182 +VARIATION SELECTOR-147 + +E0182 +VS147 + +E0183 +VARIATION SELECTOR-148 + +E0183 +VS148 + +E0184 +VARIATION SELECTOR-149 + +E0184 +VS149 + +E0185 +VARIATION SELECTOR-150 + +E0185 +VS150 + +E0186 +VARIATION SELECTOR-151 + +E0186 +VS151 + +E0187 +VARIATION SELECTOR-152 + +E0187 +VS152 + +E0188 +VARIATION SELECTOR-153 + +E0188 +VS153 + +E0189 +VARIATION SELECTOR-154 + +E0189 +VS154 + +E018A +VARIATION SELECTOR-155 + +E018A +VS155 + +E018B +VARIATION SELECTOR-156 + +E018B +VS156 + +E018C +VARIATION SELECTOR-157 + +E018C +VS157 + +E018D +VARIATION SELECTOR-158 + +E018D +VS158 + +E018E +VARIATION SELECTOR-159 + +E018E +VS159 + +E018F +VARIATION SELECTOR-160 + +E018F +VS160 + +E0190 +VARIATION SELECTOR-161 + +E0190 +VS161 + +E0191 +VARIATION SELECTOR-162 + +E0191 +VS162 + +E0192 +VARIATION SELECTOR-163 + +E0192 +VS163 + +E0193 +VARIATION SELECTOR-164 + +E0193 +VS164 + +E0194 +VARIATION SELECTOR-165 + +E0194 +VS165 + +E0195 +VARIATION SELECTOR-166 + +E0195 +VS166 + +E0196 +VARIATION SELECTOR-167 + +E0196 +VS167 + +E0197 +VARIATION SELECTOR-168 + +E0197 +VS168 + +E0198 +VARIATION SELECTOR-169 + +E0198 +VS169 + +E0199 +VARIATION SELECTOR-170 + +E0199 +VS170 + +E019A +VARIATION SELECTOR-171 + +E019A +VS171 + +E019B +VARIATION SELECTOR-172 + +E019B +VS172 + +E019C +VARIATION SELECTOR-173 + +E019C +VS173 + +E019D +VARIATION SELECTOR-174 + +E019D +VS174 + +E019E +VARIATION SELECTOR-175 + +E019E +VS175 + +E019F +VARIATION SELECTOR-176 + +E019F +VS176 + +E01A0 +VARIATION SELECTOR-177 + +E01A0 +VS177 + +E01A1 +VARIATION SELECTOR-178 + +E01A1 +VS178 + +E01A2 +VARIATION SELECTOR-179 + +E01A2 +VS179 + +E01A3 +VARIATION SELECTOR-180 + +E01A3 +VS180 + +E01A4 +VARIATION SELECTOR-181 + +E01A4 +VS181 + +E01A5 +VARIATION SELECTOR-182 + +E01A5 +VS182 + +E01A6 +VARIATION SELECTOR-183 + +E01A6 +VS183 + +E01A7 +VARIATION SELECTOR-184 + +E01A7 +VS184 + +E01A8 +VARIATION SELECTOR-185 + +E01A8 +VS185 + +E01A9 +VARIATION SELECTOR-186 + +E01A9 +VS186 + +E01AA +VARIATION SELECTOR-187 + +E01AA +VS187 + +E01AB +VARIATION SELECTOR-188 + +E01AB +VS188 + +E01AC +VARIATION SELECTOR-189 + +E01AC +VS189 + +E01AD +VARIATION SELECTOR-190 + +E01AD +VS190 + +E01AE +VARIATION SELECTOR-191 + +E01AE +VS191 + +E01AF +VARIATION SELECTOR-192 + +E01AF +VS192 + +E01B0 +VARIATION SELECTOR-193 + +E01B0 +VS193 + +E01B1 +VARIATION SELECTOR-194 + +E01B1 +VS194 + +E01B2 +VARIATION SELECTOR-195 + +E01B2 +VS195 + +E01B3 +VARIATION SELECTOR-196 + +E01B3 +VS196 + +E01B4 +VARIATION SELECTOR-197 + +E01B4 +VS197 + +E01B5 +VARIATION SELECTOR-198 + +E01B5 +VS198 + +E01B6 +VARIATION SELECTOR-199 + +E01B6 +VS199 + +E01B7 +VARIATION SELECTOR-200 + +E01B7 +VS200 + +E01B8 +VARIATION SELECTOR-201 + +E01B8 +VS201 + +E01B9 +VARIATION SELECTOR-202 + +E01B9 +VS202 + +E01BA +VARIATION SELECTOR-203 + +E01BA +VS203 + +E01BB +VARIATION SELECTOR-204 + +E01BB +VS204 + +E01BC +VARIATION SELECTOR-205 + +E01BC +VS205 + +E01BD +VARIATION SELECTOR-206 + +E01BD +VS206 + +E01BE +VARIATION SELECTOR-207 + +E01BE +VS207 + +E01BF +VARIATION SELECTOR-208 + +E01BF +VS208 + +E01C0 +VARIATION SELECTOR-209 + +E01C0 +VS209 + +E01C1 +VARIATION SELECTOR-210 + +E01C1 +VS210 + +E01C2 +VARIATION SELECTOR-211 + +E01C2 +VS211 + +E01C3 +VARIATION SELECTOR-212 + +E01C3 +VS212 + +E01C4 +VARIATION SELECTOR-213 + +E01C4 +VS213 + +E01C5 +VARIATION SELECTOR-214 + +E01C5 +VS214 + +E01C6 +VARIATION SELECTOR-215 + +E01C6 +VS215 + +E01C7 +VARIATION SELECTOR-216 + +E01C7 +VS216 + +E01C8 +VARIATION SELECTOR-217 + +E01C8 +VS217 + +E01C9 +VARIATION SELECTOR-218 + +E01C9 +VS218 + +E01CA +VARIATION SELECTOR-219 + +E01CA +VS219 + +E01CB +VARIATION SELECTOR-220 + +E01CB +VS220 + +E01CC +VARIATION SELECTOR-221 + +E01CC +VS221 + +E01CD +VARIATION SELECTOR-222 + +E01CD +VS222 + +E01CE +VARIATION SELECTOR-223 + +E01CE +VS223 + +E01CF +VARIATION SELECTOR-224 + +E01CF +VS224 + +E01D0 +VARIATION SELECTOR-225 + +E01D0 +VS225 + +E01D1 +VARIATION SELECTOR-226 + +E01D1 +VS226 + +E01D2 +VARIATION SELECTOR-227 + +E01D2 +VS227 + +E01D3 +VARIATION SELECTOR-228 + +E01D3 +VS228 + +E01D4 +VARIATION SELECTOR-229 + +E01D4 +VS229 + +E01D5 +VARIATION SELECTOR-230 + +E01D5 +VS230 + +E01D6 +VARIATION SELECTOR-231 + +E01D6 +VS231 + +E01D7 +VARIATION SELECTOR-232 + +E01D7 +VS232 + +E01D8 +VARIATION SELECTOR-233 + +E01D8 +VS233 + +E01D9 +VARIATION SELECTOR-234 + +E01D9 +VS234 + +E01DA +VARIATION SELECTOR-235 + +E01DA +VS235 + +E01DB +VARIATION SELECTOR-236 + +E01DB +VS236 + +E01DC +VARIATION SELECTOR-237 + +E01DC +VS237 + +E01DD +VARIATION SELECTOR-238 + +E01DD +VS238 + +E01DE +VARIATION SELECTOR-239 + +E01DE +VS239 + +E01DF +VARIATION SELECTOR-240 + +E01DF +VS240 + +E01E0 +VARIATION SELECTOR-241 + +E01E0 +VS241 + +E01E1 +VARIATION SELECTOR-242 + +E01E1 +VS242 + +E01E2 +VARIATION SELECTOR-243 + +E01E2 +VS243 + +E01E3 +VARIATION SELECTOR-244 + +E01E3 +VS244 + +E01E4 +VARIATION SELECTOR-245 + +E01E4 +VS245 + +E01E5 +VARIATION SELECTOR-246 + +E01E5 +VS246 + +E01E6 +VARIATION SELECTOR-247 + +E01E6 +VS247 + +E01E7 +VARIATION SELECTOR-248 + +E01E7 +VS248 + +E01E8 +VARIATION SELECTOR-249 + +E01E8 +VS249 + +E01E9 +VARIATION SELECTOR-250 + +E01E9 +VS250 + +E01EA +VARIATION SELECTOR-251 + +E01EA +VS251 + +E01EB +VARIATION SELECTOR-252 + +E01EB +VS252 + +E01EC +VARIATION SELECTOR-253 + +E01EC +VS253 + +E01ED +VARIATION SELECTOR-254 + +E01ED +VS254 + +E01EE +VARIATION SELECTOR-255 + +E01EE +VS255 + +E01EF +VARIATION SELECTOR-256 + +E01EF +VS256 + +00023 0FE0F 020E3 +KEYCAP NUMBER SIGN + +0002A 0FE0F 020E3 +KEYCAP ASTERISK + +00030 0FE0F 020E3 +KEYCAP DIGIT ZERO + +00031 0FE0F 020E3 +KEYCAP DIGIT ONE + +00032 0FE0F 020E3 +KEYCAP DIGIT TWO + +00033 0FE0F 020E3 +KEYCAP DIGIT THREE + +00034 0FE0F 020E3 +KEYCAP DIGIT FOUR + +00035 0FE0F 020E3 +KEYCAP DIGIT FIVE + +00036 0FE0F 020E3 +KEYCAP DIGIT SIX + +00037 0FE0F 020E3 +KEYCAP DIGIT SEVEN + +00038 0FE0F 020E3 +KEYCAP DIGIT EIGHT + +00039 0FE0F 020E3 +KEYCAP DIGIT NINE + +00100 00300 +LATIN CAPITAL LETTER A WITH MACRON AND GRAVE + +00101 00300 +LATIN SMALL LETTER A WITH MACRON AND GRAVE + +0012A 00300 +LATIN CAPITAL LETTER I WITH MACRON AND GRAVE + +0012B 00300 +LATIN SMALL LETTER I WITH MACRON AND GRAVE + +0016A 00300 +LATIN CAPITAL LETTER U WITH MACRON AND GRAVE + +0016B 00300 +LATIN SMALL LETTER U WITH MACRON AND GRAVE + +00045 00329 +LATIN CAPITAL LETTER E WITH VERTICAL LINE BELOW + +00065 00329 +LATIN SMALL LETTER E WITH VERTICAL LINE BELOW + +000C8 00329 +LATIN CAPITAL LETTER E WITH VERTICAL LINE BELOW AND GRAVE + +000E8 00329 +LATIN SMALL LETTER E WITH VERTICAL LINE BELOW AND GRAVE + +000C9 00329 +LATIN CAPITAL LETTER E WITH VERTICAL LINE BELOW AND ACUTE + +000E9 00329 +LATIN SMALL LETTER E WITH VERTICAL LINE BELOW AND ACUTE + +0004F 00329 +LATIN CAPITAL LETTER O WITH VERTICAL LINE BELOW + +0006F 00329 +LATIN SMALL LETTER O WITH VERTICAL LINE BELOW + +000D2 00329 +LATIN CAPITAL LETTER O WITH VERTICAL LINE BELOW AND GRAVE + +000F2 00329 +LATIN SMALL LETTER O WITH VERTICAL LINE BELOW AND GRAVE + +000D3 00329 +LATIN CAPITAL LETTER O WITH VERTICAL LINE BELOW AND ACUTE + +000F3 00329 +LATIN SMALL LETTER O WITH VERTICAL LINE BELOW AND ACUTE + +00053 00329 +LATIN CAPITAL LETTER S WITH VERTICAL LINE BELOW + +00073 00329 +LATIN SMALL LETTER S WITH VERTICAL LINE BELOW + +000CA 00304 +LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND MACRON + +000EA 00304 +LATIN SMALL LETTER E WITH CIRCUMFLEX AND MACRON + +000CA 0030C +LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND CARON + +000EA 0030C +LATIN SMALL LETTER E WITH CIRCUMFLEX AND CARON + +00069 00307 00301 +LATIN SMALL LETTER I WITH DOT ABOVE AND ACUTE + +0006E 00360 00067 +LATIN SMALL LETTER NG WITH TILDE ABOVE + +00104 00301 +LATIN CAPITAL LETTER A WITH OGONEK AND ACUTE + +00105 00301 +LATIN SMALL LETTER A WITH OGONEK AND ACUTE + +00104 00303 +LATIN CAPITAL LETTER A WITH OGONEK AND TILDE + +00105 00303 +LATIN SMALL LETTER A WITH OGONEK AND TILDE + +00118 00301 +LATIN CAPITAL LETTER E WITH OGONEK AND ACUTE + +00119 00301 +LATIN SMALL LETTER E WITH OGONEK AND ACUTE + +00118 00303 +LATIN CAPITAL LETTER E WITH OGONEK AND TILDE + +00119 00303 +LATIN SMALL LETTER E WITH OGONEK AND TILDE + +00116 00301 +LATIN CAPITAL LETTER E WITH DOT ABOVE AND ACUTE + +00117 00301 +LATIN SMALL LETTER E WITH DOT ABOVE AND ACUTE + +00116 00303 +LATIN CAPITAL LETTER E WITH DOT ABOVE AND TILDE + +00117 00303 +LATIN SMALL LETTER E WITH DOT ABOVE AND TILDE + +00069 00307 00300 +LATIN SMALL LETTER I WITH DOT ABOVE AND GRAVE + +00069 00307 00303 +LATIN SMALL LETTER I WITH DOT ABOVE AND TILDE + +0012E 00301 +LATIN CAPITAL LETTER I WITH OGONEK AND ACUTE + +0012F 00307 00301 +LATIN SMALL LETTER I WITH OGONEK AND DOT ABOVE AND ACUTE + +0012E 00303 +LATIN CAPITAL LETTER I WITH OGONEK AND TILDE + +0012F 00307 00303 +LATIN SMALL LETTER I WITH OGONEK AND DOT ABOVE AND TILDE + +0004A 00303 +LATIN CAPITAL LETTER J WITH TILDE + +0006A 00307 00303 +LATIN SMALL LETTER J WITH DOT ABOVE AND TILDE + +0004C 00303 +LATIN CAPITAL LETTER L WITH TILDE + +0006C 00303 +LATIN SMALL LETTER L WITH TILDE + +0004D 00303 +LATIN CAPITAL LETTER M WITH TILDE + +0006D 00303 +LATIN SMALL LETTER M WITH TILDE + +00052 00303 +LATIN CAPITAL LETTER R WITH TILDE + +00072 00303 +LATIN SMALL LETTER R WITH TILDE + +00172 00301 +LATIN CAPITAL LETTER U WITH OGONEK AND ACUTE + +00173 00301 +LATIN SMALL LETTER U WITH OGONEK AND ACUTE + +00172 00303 +LATIN CAPITAL LETTER U WITH OGONEK AND TILDE + +00173 00303 +LATIN SMALL LETTER U WITH OGONEK AND TILDE + +0016A 00301 +LATIN CAPITAL LETTER U WITH MACRON AND ACUTE + +0016B 00301 +LATIN SMALL LETTER U WITH MACRON AND ACUTE + +0016A 00303 +LATIN CAPITAL LETTER U WITH MACRON AND TILDE + +0016B 00303 +LATIN SMALL LETTER U WITH MACRON AND TILDE + +000E6 00300 +LATIN SMALL LETTER AE WITH GRAVE + +00254 00300 +LATIN SMALL LETTER OPEN O WITH GRAVE + +00254 00301 +LATIN SMALL LETTER OPEN O WITH ACUTE + +0028C 00300 +LATIN SMALL LETTER TURNED V WITH GRAVE + +0028C 00301 +LATIN SMALL LETTER TURNED V WITH ACUTE + +00259 00300 +LATIN SMALL LETTER SCHWA WITH GRAVE + +00259 00301 +LATIN SMALL LETTER SCHWA WITH ACUTE + +0025A 00300 +LATIN SMALL LETTER HOOKED SCHWA WITH GRAVE + +0025A 00301 +LATIN SMALL LETTER HOOKED SCHWA WITH ACUTE + +00626 00627 +ARABIC SEQUENCE YEH WITH HAMZA ABOVE WITH ALEF + +00626 00648 +ARABIC SEQUENCE YEH WITH HAMZA ABOVE WITH WAW + +00626 00649 +ARABIC SEQUENCE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA + +00626 006C6 +ARABIC SEQUENCE YEH WITH HAMZA ABOVE WITH OE + +00626 006C7 +ARABIC SEQUENCE YEH WITH HAMZA ABOVE WITH U + +00626 006C8 +ARABIC SEQUENCE YEH WITH HAMZA ABOVE WITH YU + +00626 006D0 +ARABIC SEQUENCE YEH WITH HAMZA ABOVE WITH E + +00626 006D5 +ARABIC SEQUENCE YEH WITH HAMZA ABOVE WITH AE + +00646 006A9 +ARABIC SEQUENCE NOON WITH KEHEH + +00915 0093C +DEVANAGARI SEQUENCE FOR LETTER QA + +00916 0093C +DEVANAGARI SEQUENCE FOR LETTER KHHA + +00917 0093C +DEVANAGARI SEQUENCE FOR LETTER GHHA + +0091C 0093C +DEVANAGARI SEQUENCE FOR LETTER ZA + +00921 0093C +DEVANAGARI SEQUENCE FOR LETTER DDDHA + +00922 0093C +DEVANAGARI SEQUENCE FOR LETTER RHA + +0092B 0093C +DEVANAGARI SEQUENCE FOR LETTER FA + +0092F 0093C +DEVANAGARI SEQUENCE FOR LETTER YYA + +009A1 009BC +BENGALI SEQUENCE FOR LETTER RRA + +009A2 009BC +BENGALI SEQUENCE FOR LETTER RHA + +009AF 009BC +BENGALI SEQUENCE FOR LETTER YYA + +00A32 00A3C +GURMUKHI SEQUENCE FOR LETTER LLA + +00A38 00A3C +GURMUKHI SEQUENCE FOR LETTER SHA + +00A16 00A3C +GURMUKHI SEQUENCE FOR LETTER KHHA + +00A17 00A3C +GURMUKHI SEQUENCE FOR LETTER GHHA + +00A1C 00A3C +GURMUKHI SEQUENCE FOR LETTER ZA + +00A2B 00A3C +GURMUKHI SEQUENCE FOR LETTER FA + +00B21 00B3C +ORIYA SEQUENCE FOR LETTER RRA + +00B22 00B3C +ORIYA SEQUENCE FOR LETTER RHA + +00995 009CD 009B7 +BENGALI LETTER KHINYA + +00B95 00BCD +TAMIL CONSONANT K + +00B99 00BCD +TAMIL CONSONANT NG + +00B9A 00BCD +TAMIL CONSONANT C + +00B9E 00BCD +TAMIL CONSONANT NY + +00B9F 00BCD +TAMIL CONSONANT TT + +00BA3 00BCD +TAMIL CONSONANT NN + +00BA4 00BCD +TAMIL CONSONANT T + +00BA8 00BCD +TAMIL CONSONANT N + +00BAA 00BCD +TAMIL CONSONANT P + +00BAE 00BCD +TAMIL CONSONANT M + +00BAF 00BCD +TAMIL CONSONANT Y + +00BB0 00BCD +TAMIL CONSONANT R + +00BB2 00BCD +TAMIL CONSONANT L + +00BB5 00BCD +TAMIL CONSONANT V + +00BB4 00BCD +TAMIL CONSONANT LLL + +00BB3 00BCD +TAMIL CONSONANT LL + +00BB1 00BCD +TAMIL CONSONANT RR + +00BA9 00BCD +TAMIL CONSONANT NNN + +00B9C 00BCD +TAMIL CONSONANT J + +00BB6 00BCD +TAMIL CONSONANT SH + +00BB7 00BCD +TAMIL CONSONANT SS + +00BB8 00BCD +TAMIL CONSONANT S + +00BB9 00BCD +TAMIL CONSONANT H + +00B95 00BCD 00BB7 00BCD +TAMIL CONSONANT KSS + +00B95 00BBE +TAMIL SYLLABLE KAA + +00B95 00BBF +TAMIL SYLLABLE KI + +00B95 00BC0 +TAMIL SYLLABLE KII + +00B95 00BC1 +TAMIL SYLLABLE KU + +00B95 00BC2 +TAMIL SYLLABLE KUU + +00B95 00BC6 +TAMIL SYLLABLE KE + +00B95 00BC7 +TAMIL SYLLABLE KEE + +00B95 00BC8 +TAMIL SYLLABLE KAI + +00B95 00BCA +TAMIL SYLLABLE KO + +00B95 00BCB +TAMIL SYLLABLE KOO + +00B95 00BCC +TAMIL SYLLABLE KAU + +00B99 00BBE +TAMIL SYLLABLE NGAA + +00B99 00BBF +TAMIL SYLLABLE NGI + +00B99 00BC0 +TAMIL SYLLABLE NGII + +00B99 00BC1 +TAMIL SYLLABLE NGU + +00B99 00BC2 +TAMIL SYLLABLE NGUU + +00B99 00BC6 +TAMIL SYLLABLE NGE + +00B99 00BC7 +TAMIL SYLLABLE NGEE + +00B99 00BC8 +TAMIL SYLLABLE NGAI + +00B99 00BCA +TAMIL SYLLABLE NGO + +00B99 00BCB +TAMIL SYLLABLE NGOO + +00B99 00BCC +TAMIL SYLLABLE NGAU + +00B9A 00BBE +TAMIL SYLLABLE CAA + +00B9A 00BBF +TAMIL SYLLABLE CI + +00B9A 00BC0 +TAMIL SYLLABLE CII + +00B9A 00BC1 +TAMIL SYLLABLE CU + +00B9A 00BC2 +TAMIL SYLLABLE CUU + +00B9A 00BC6 +TAMIL SYLLABLE CE + +00B9A 00BC7 +TAMIL SYLLABLE CEE + +00B9A 00BC8 +TAMIL SYLLABLE CAI + +00B9A 00BCA +TAMIL SYLLABLE CO + +00B9A 00BCB +TAMIL SYLLABLE COO + +00B9A 00BCC +TAMIL SYLLABLE CAU + +00B9E 00BBE +TAMIL SYLLABLE NYAA + +00B9E 00BBF +TAMIL SYLLABLE NYI + +00B9E 00BC0 +TAMIL SYLLABLE NYII + +00B9E 00BC1 +TAMIL SYLLABLE NYU + +00B9E 00BC2 +TAMIL SYLLABLE NYUU + +00B9E 00BC6 +TAMIL SYLLABLE NYE + +00B9E 00BC7 +TAMIL SYLLABLE NYEE + +00B9E 00BC8 +TAMIL SYLLABLE NYAI + +00B9E 00BCA +TAMIL SYLLABLE NYO + +00B9E 00BCB +TAMIL SYLLABLE NYOO + +00B9E 00BCC +TAMIL SYLLABLE NYAU + +00B9F 00BBE +TAMIL SYLLABLE TTAA + +00B9F 00BBF +TAMIL SYLLABLE TTI + +00B9F 00BC0 +TAMIL SYLLABLE TTII + +00B9F 00BC1 +TAMIL SYLLABLE TTU + +00B9F 00BC2 +TAMIL SYLLABLE TTUU + +00B9F 00BC6 +TAMIL SYLLABLE TTE + +00B9F 00BC7 +TAMIL SYLLABLE TTEE + +00B9F 00BC8 +TAMIL SYLLABLE TTAI + +00B9F 00BCA +TAMIL SYLLABLE TTO + +00B9F 00BCB +TAMIL SYLLABLE TTOO + +00B9F 00BCC +TAMIL SYLLABLE TTAU + +00BA3 00BBE +TAMIL SYLLABLE NNAA + +00BA3 00BBF +TAMIL SYLLABLE NNI + +00BA3 00BC0 +TAMIL SYLLABLE NNII + +00BA3 00BC1 +TAMIL SYLLABLE NNU + +00BA3 00BC2 +TAMIL SYLLABLE NNUU + +00BA3 00BC6 +TAMIL SYLLABLE NNE + +00BA3 00BC7 +TAMIL SYLLABLE NNEE + +00BA3 00BC8 +TAMIL SYLLABLE NNAI + +00BA3 00BCA +TAMIL SYLLABLE NNO + +00BA3 00BCB +TAMIL SYLLABLE NNOO + +00BA3 00BCC +TAMIL SYLLABLE NNAU + +00BA4 00BBE +TAMIL SYLLABLE TAA + +00BA4 00BBF +TAMIL SYLLABLE TI + +00BA4 00BC0 +TAMIL SYLLABLE TII + +00BA4 00BC1 +TAMIL SYLLABLE TU + +00BA4 00BC2 +TAMIL SYLLABLE TUU + +00BA4 00BC6 +TAMIL SYLLABLE TE + +00BA4 00BC7 +TAMIL SYLLABLE TEE + +00BA4 00BC8 +TAMIL SYLLABLE TAI + +00BA4 00BCA +TAMIL SYLLABLE TO + +00BA4 00BCB +TAMIL SYLLABLE TOO + +00BA4 00BCC +TAMIL SYLLABLE TAU + +00BA8 00BBE +TAMIL SYLLABLE NAA + +00BA8 00BBF +TAMIL SYLLABLE NI + +00BA8 00BC0 +TAMIL SYLLABLE NII + +00BA8 00BC1 +TAMIL SYLLABLE NU + +00BA8 00BC2 +TAMIL SYLLABLE NUU + +00BA8 00BC6 +TAMIL SYLLABLE NE + +00BA8 00BC7 +TAMIL SYLLABLE NEE + +00BA8 00BC8 +TAMIL SYLLABLE NAI + +00BA8 00BCA +TAMIL SYLLABLE NO + +00BA8 00BCB +TAMIL SYLLABLE NOO + +00BA8 00BCC +TAMIL SYLLABLE NAU + +00BAA 00BBE +TAMIL SYLLABLE PAA + +00BAA 00BBF +TAMIL SYLLABLE PI + +00BAA 00BC0 +TAMIL SYLLABLE PII + +00BAA 00BC1 +TAMIL SYLLABLE PU + +00BAA 00BC2 +TAMIL SYLLABLE PUU + +00BAA 00BC6 +TAMIL SYLLABLE PE + +00BAA 00BC7 +TAMIL SYLLABLE PEE + +00BAA 00BC8 +TAMIL SYLLABLE PAI + +00BAA 00BCA +TAMIL SYLLABLE PO + +00BAA 00BCB +TAMIL SYLLABLE POO + +00BAA 00BCC +TAMIL SYLLABLE PAU + +00BAE 00BBE +TAMIL SYLLABLE MAA + +00BAE 00BBF +TAMIL SYLLABLE MI + +00BAE 00BC0 +TAMIL SYLLABLE MII + +00BAE 00BC1 +TAMIL SYLLABLE MU + +00BAE 00BC2 +TAMIL SYLLABLE MUU + +00BAE 00BC6 +TAMIL SYLLABLE ME + +00BAE 00BC7 +TAMIL SYLLABLE MEE + +00BAE 00BC8 +TAMIL SYLLABLE MAI + +00BAE 00BCA +TAMIL SYLLABLE MO + +00BAE 00BCB +TAMIL SYLLABLE MOO + +00BAE 00BCC +TAMIL SYLLABLE MAU + +00BAF 00BBE +TAMIL SYLLABLE YAA + +00BAF 00BBF +TAMIL SYLLABLE YI + +00BAF 00BC0 +TAMIL SYLLABLE YII + +00BAF 00BC1 +TAMIL SYLLABLE YU + +00BAF 00BC2 +TAMIL SYLLABLE YUU + +00BAF 00BC6 +TAMIL SYLLABLE YE + +00BAF 00BC7 +TAMIL SYLLABLE YEE + +00BAF 00BC8 +TAMIL SYLLABLE YAI + +00BAF 00BCA +TAMIL SYLLABLE YO + +00BAF 00BCB +TAMIL SYLLABLE YOO + +00BAF 00BCC +TAMIL SYLLABLE YAU + +00BB0 00BBE +TAMIL SYLLABLE RAA + +00BB0 00BBF +TAMIL SYLLABLE RI + +00BB0 00BC0 +TAMIL SYLLABLE RII + +00BB0 00BC1 +TAMIL SYLLABLE RU + +00BB0 00BC2 +TAMIL SYLLABLE RUU + +00BB0 00BC6 +TAMIL SYLLABLE RE + +00BB0 00BC7 +TAMIL SYLLABLE REE + +00BB0 00BC8 +TAMIL SYLLABLE RAI + +00BB0 00BCA +TAMIL SYLLABLE RO + +00BB0 00BCB +TAMIL SYLLABLE ROO + +00BB0 00BCC +TAMIL SYLLABLE RAU + +00BB2 00BBE +TAMIL SYLLABLE LAA + +00BB2 00BBF +TAMIL SYLLABLE LI + +00BB2 00BC0 +TAMIL SYLLABLE LII + +00BB2 00BC1 +TAMIL SYLLABLE LU + +00BB2 00BC2 +TAMIL SYLLABLE LUU + +00BB2 00BC6 +TAMIL SYLLABLE LE + +00BB2 00BC7 +TAMIL SYLLABLE LEE + +00BB2 00BC8 +TAMIL SYLLABLE LAI + +00BB2 00BCA +TAMIL SYLLABLE LO + +00BB2 00BCB +TAMIL SYLLABLE LOO + +00BB2 00BCC +TAMIL SYLLABLE LAU + +00BB5 00BBE +TAMIL SYLLABLE VAA + +00BB5 00BBF +TAMIL SYLLABLE VI + +00BB5 00BC0 +TAMIL SYLLABLE VII + +00BB5 00BC1 +TAMIL SYLLABLE VU + +00BB5 00BC2 +TAMIL SYLLABLE VUU + +00BB5 00BC6 +TAMIL SYLLABLE VE + +00BB5 00BC7 +TAMIL SYLLABLE VEE + +00BB5 00BC8 +TAMIL SYLLABLE VAI + +00BB5 00BCA +TAMIL SYLLABLE VO + +00BB5 00BCB +TAMIL SYLLABLE VOO + +00BB5 00BCC +TAMIL SYLLABLE VAU + +00BB4 00BBE +TAMIL SYLLABLE LLLAA + +00BB4 00BBF +TAMIL SYLLABLE LLLI + +00BB4 00BC0 +TAMIL SYLLABLE LLLII + +00BB4 00BC1 +TAMIL SYLLABLE LLLU + +00BB4 00BC2 +TAMIL SYLLABLE LLLUU + +00BB4 00BC6 +TAMIL SYLLABLE LLLE + +00BB4 00BC7 +TAMIL SYLLABLE LLLEE + +00BB4 00BC8 +TAMIL SYLLABLE LLLAI + +00BB4 00BCA +TAMIL SYLLABLE LLLO + +00BB4 00BCB +TAMIL SYLLABLE LLLOO + +00BB4 00BCC +TAMIL SYLLABLE LLLAU + +00BB3 00BBE +TAMIL SYLLABLE LLAA + +00BB3 00BBF +TAMIL SYLLABLE LLI + +00BB3 00BC0 +TAMIL SYLLABLE LLII + +00BB3 00BC1 +TAMIL SYLLABLE LLU + +00BB3 00BC2 +TAMIL SYLLABLE LLUU + +00BB3 00BC6 +TAMIL SYLLABLE LLE + +00BB3 00BC7 +TAMIL SYLLABLE LLEE + +00BB3 00BC8 +TAMIL SYLLABLE LLAI + +00BB3 00BCA +TAMIL SYLLABLE LLO + +00BB3 00BCB +TAMIL SYLLABLE LLOO + +00BB3 00BCC +TAMIL SYLLABLE LLAU + +00BB1 00BBE +TAMIL SYLLABLE RRAA + +00BB1 00BBF +TAMIL SYLLABLE RRI + +00BB1 00BC0 +TAMIL SYLLABLE RRII + +00BB1 00BC1 +TAMIL SYLLABLE RRU + +00BB1 00BC2 +TAMIL SYLLABLE RRUU + +00BB1 00BC6 +TAMIL SYLLABLE RRE + +00BB1 00BC7 +TAMIL SYLLABLE RREE + +00BB1 00BC8 +TAMIL SYLLABLE RRAI + +00BB1 00BCA +TAMIL SYLLABLE RRO + +00BB1 00BCB +TAMIL SYLLABLE RROO + +00BB1 00BCC +TAMIL SYLLABLE RRAU + +00BA9 00BBE +TAMIL SYLLABLE NNNAA + +00BA9 00BBF +TAMIL SYLLABLE NNNI + +00BA9 00BC0 +TAMIL SYLLABLE NNNII + +00BA9 00BC1 +TAMIL SYLLABLE NNNU + +00BA9 00BC2 +TAMIL SYLLABLE NNNUU + +00BA9 00BC6 +TAMIL SYLLABLE NNNE + +00BA9 00BC7 +TAMIL SYLLABLE NNNEE + +00BA9 00BC8 +TAMIL SYLLABLE NNNAI + +00BA9 00BCA +TAMIL SYLLABLE NNNO + +00BA9 00BCB +TAMIL SYLLABLE NNNOO + +00BA9 00BCC +TAMIL SYLLABLE NNNAU + +00B9C 00BBE +TAMIL SYLLABLE JAA + +00B9C 00BBF +TAMIL SYLLABLE JI + +00B9C 00BC0 +TAMIL SYLLABLE JII + +00B9C 00BC1 +TAMIL SYLLABLE JU + +00B9C 00BC2 +TAMIL SYLLABLE JUU + +00B9C 00BC6 +TAMIL SYLLABLE JE + +00B9C 00BC7 +TAMIL SYLLABLE JEE + +00B9C 00BC8 +TAMIL SYLLABLE JAI + +00B9C 00BCA +TAMIL SYLLABLE JO + +00B9C 00BCB +TAMIL SYLLABLE JOO + +00B9C 00BCC +TAMIL SYLLABLE JAU + +00BB6 00BBE +TAMIL SYLLABLE SHAA + +00BB6 00BBF +TAMIL SYLLABLE SHI + +00BB6 00BC0 +TAMIL SYLLABLE SHII + +00BB6 00BC1 +TAMIL SYLLABLE SHU + +00BB6 00BC2 +TAMIL SYLLABLE SHUU + +00BB6 00BC6 +TAMIL SYLLABLE SHE + +00BB6 00BC7 +TAMIL SYLLABLE SHEE + +00BB6 00BC8 +TAMIL SYLLABLE SHAI + +00BB6 00BCA +TAMIL SYLLABLE SHO + +00BB6 00BCB +TAMIL SYLLABLE SHOO + +00BB6 00BCC +TAMIL SYLLABLE SHAU + +00BB7 00BBE +TAMIL SYLLABLE SSAA + +00BB7 00BBF +TAMIL SYLLABLE SSI + +00BB7 00BC0 +TAMIL SYLLABLE SSII + +00BB7 00BC1 +TAMIL SYLLABLE SSU + +00BB7 00BC2 +TAMIL SYLLABLE SSUU + +00BB7 00BC6 +TAMIL SYLLABLE SSE + +00BB7 00BC7 +TAMIL SYLLABLE SSEE + +00BB7 00BC8 +TAMIL SYLLABLE SSAI + +00BB7 00BCA +TAMIL SYLLABLE SSO + +00BB7 00BCB +TAMIL SYLLABLE SSOO + +00BB7 00BCC +TAMIL SYLLABLE SSAU + +00BB8 00BBE +TAMIL SYLLABLE SAA + +00BB8 00BBF +TAMIL SYLLABLE SI + +00BB8 00BC0 +TAMIL SYLLABLE SII + +00BB8 00BC1 +TAMIL SYLLABLE SU + +00BB8 00BC2 +TAMIL SYLLABLE SUU + +00BB8 00BC6 +TAMIL SYLLABLE SE + +00BB8 00BC7 +TAMIL SYLLABLE SEE + +00BB8 00BC8 +TAMIL SYLLABLE SAI + +00BB8 00BCA +TAMIL SYLLABLE SO + +00BB8 00BCB +TAMIL SYLLABLE SOO + +00BB8 00BCC +TAMIL SYLLABLE SAU + +00BB9 00BBE +TAMIL SYLLABLE HAA + +00BB9 00BBF +TAMIL SYLLABLE HI + +00BB9 00BC0 +TAMIL SYLLABLE HII + +00BB9 00BC1 +TAMIL SYLLABLE HU + +00BB9 00BC2 +TAMIL SYLLABLE HUU + +00BB9 00BC6 +TAMIL SYLLABLE HE + +00BB9 00BC7 +TAMIL SYLLABLE HEE + +00BB9 00BC8 +TAMIL SYLLABLE HAI + +00BB9 00BCA +TAMIL SYLLABLE HO + +00BB9 00BCB +TAMIL SYLLABLE HOO + +00BB9 00BCC +TAMIL SYLLABLE HAU + +00B95 00BCD 00BB7 +TAMIL SYLLABLE KSSA + +00B95 00BCD 00BB7 00BBE +TAMIL SYLLABLE KSSAA + +00B95 00BCD 00BB7 00BBF +TAMIL SYLLABLE KSSI + +00B95 00BCD 00BB7 00BC0 +TAMIL SYLLABLE KSSII + +00B95 00BCD 00BB7 00BC1 +TAMIL SYLLABLE KSSU + +00B95 00BCD 00BB7 00BC2 +TAMIL SYLLABLE KSSUU + +00B95 00BCD 00BB7 00BC6 +TAMIL SYLLABLE KSSE + +00B95 00BCD 00BB7 00BC7 +TAMIL SYLLABLE KSSEE + +00B95 00BCD 00BB7 00BC8 +TAMIL SYLLABLE KSSAI + +00B95 00BCD 00BB7 00BCA +TAMIL SYLLABLE KSSO + +00B95 00BCD 00BB7 00BCB +TAMIL SYLLABLE KSSOO + +00B95 00BCD 00BB7 00BCC +TAMIL SYLLABLE KSSAU + +00BB6 00BCD 00BB0 00BC0 +TAMIL SYLLABLE SHRII + +00DCA 0200D 00DBA +SINHALA CONSONANT SIGN YANSAYA + +00DCA 0200D 00DBB +SINHALA CONSONANT SIGN RAKAARAANSAYA + +00DBB 00DCA 0200D +SINHALA CONSONANT SIGN REPAYA + +010E3 00302 +GEORGIAN LETTER U-BRJGU + +017D2 01780 +KHMER CONSONANT SIGN COENG KA + +017D2 01781 +KHMER CONSONANT SIGN COENG KHA + +017D2 01782 +KHMER CONSONANT SIGN COENG KO + +017D2 01783 +KHMER CONSONANT SIGN COENG KHO + +017D2 01784 +KHMER CONSONANT SIGN COENG NGO + +017D2 01785 +KHMER CONSONANT SIGN COENG CA + +017D2 01786 +KHMER CONSONANT SIGN COENG CHA + +017D2 01787 +KHMER CONSONANT SIGN COENG CO + +017D2 01788 +KHMER CONSONANT SIGN COENG CHO + +017D2 01789 +KHMER CONSONANT SIGN COENG NYO + +017D2 0178A +KHMER CONSONANT SIGN COENG DA + +017D2 0178B +KHMER CONSONANT SIGN COENG TTHA + +017D2 0178C +KHMER CONSONANT SIGN COENG DO + +017D2 0178D +KHMER CONSONANT SIGN COENG TTHO + +017D2 0178E +KHMER CONSONANT SIGN COENG NA + +017D2 0178F +KHMER CONSONANT SIGN COENG TA + +017D2 01790 +KHMER CONSONANT SIGN COENG THA + +017D2 01791 +KHMER CONSONANT SIGN COENG TO + +017D2 01792 +KHMER CONSONANT SIGN COENG THO + +017D2 01793 +KHMER CONSONANT SIGN COENG NO + +017D2 01794 +KHMER CONSONANT SIGN COENG BA + +017D2 01795 +KHMER CONSONANT SIGN COENG PHA + +017D2 01796 +KHMER CONSONANT SIGN COENG PO + +017D2 01797 +KHMER CONSONANT SIGN COENG PHO + +017D2 01798 +KHMER CONSONANT SIGN COENG MO + +017D2 01799 +KHMER CONSONANT SIGN COENG YO + +017D2 0179A +KHMER CONSONANT SIGN COENG RO + +017D2 0179B +KHMER CONSONANT SIGN COENG LO + +017D2 0179C +KHMER CONSONANT SIGN COENG VO + +017D2 0179D +KHMER CONSONANT SIGN COENG SHA + +017D2 0179E +KHMER CONSONANT SIGN COENG SSA + +017D2 0179F +KHMER CONSONANT SIGN COENG SA + +017D2 017A0 +KHMER CONSONANT SIGN COENG HA + +017D2 017A1 +KHMER CONSONANT SIGN COENG LA + +017D2 017A2 +KHMER VOWEL SIGN COENG QA + +017D2 017A7 +KHMER INDEPENDENT VOWEL SIGN COENG QU + +017D2 017AB +KHMER INDEPENDENT VOWEL SIGN COENG RY + +017D2 017AC +KHMER INDEPENDENT VOWEL SIGN COENG RYY + +017D2 017AF +KHMER INDEPENDENT VOWEL SIGN COENG QE + +017BB 017C6 +KHMER VOWEL SIGN OM + +017B6 017C6 +KHMER VOWEL SIGN AAM + +0304B 0309A +HIRAGANA LETTER BIDAKUON NGA + +0304D 0309A +HIRAGANA LETTER BIDAKUON NGI + +0304F 0309A +HIRAGANA LETTER BIDAKUON NGU + +03051 0309A +HIRAGANA LETTER BIDAKUON NGE + +03053 0309A +HIRAGANA LETTER BIDAKUON NGO + +030AB 0309A +KATAKANA LETTER BIDAKUON NGA + +030AD 0309A +KATAKANA LETTER BIDAKUON NGI + +030AF 0309A +KATAKANA LETTER BIDAKUON NGU + +030B1 0309A +KATAKANA LETTER BIDAKUON NGE + +030B3 0309A +KATAKANA LETTER BIDAKUON NGO + +030BB 0309A +KATAKANA LETTER AINU CE + +030C4 0309A +KATAKANA LETTER AINU TU + +030C8 0309A +KATAKANA LETTER AINU TO + +031F7 0309A +KATAKANA LETTER AINU P + +002E5 002E9 +MODIFIER LETTER EXTRA-HIGH EXTRA-LOW CONTOUR TONE BAR + +002E9 002E5 +MODIFIER LETTER EXTRA-LOW EXTRA-HIGH CONTOUR TONE BAR + +END diff --git a/src/test/java/org/perlonjava/ErrorMessageUtilSourceLocationIndexTest.java b/src/test/java/org/perlonjava/ErrorMessageUtilSourceLocationIndexTest.java new file mode 100644 index 0000000000..48924e69ed --- /dev/null +++ b/src/test/java/org/perlonjava/ErrorMessageUtilSourceLocationIndexTest.java @@ -0,0 +1,93 @@ +package org.perlonjava; + +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.perlonjava.frontend.lexer.Lexer; +import org.perlonjava.frontend.lexer.LexerToken; +import org.perlonjava.runtime.runtimetypes.ErrorMessageUtil; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotSame; +import static org.junit.jupiter.api.Assertions.assertSame; + +@Tag("unit") +public class ErrorMessageUtilSourceLocationIndexTest { + @Test + void indexesBlankHeavyMultibyteSourceAndRepeatedLookups() throws Exception { + String source = "\n".repeat(4_000) + + "my $caf\u00e9 = 1;\n" + + "#line 700 \"same-\u03b1.pl\"\n" + + "warn 'first';\n" + + "#line 0 lib/Other.pm\n" + + "warn 'second';\n"; + List tokens = new Lexer(source).tokenize(); + ErrorMessageUtil util = new ErrorMessageUtil("physical.pl", tokens); + + int declaration = tokenIndex(tokens, "my", 0); + int firstWarn = tokenIndex(tokens, "warn", 0); + int secondWarn = tokenIndex(tokens, "warn", 1); + + assertEquals(new ErrorMessageUtil.SourceLocation("physical.pl", 4_001), + util.getSourceLocationAccurate(declaration)); + ErrorMessageUtil.SourceLocation first = + util.getSourceLocationAccurate(firstWarn); + assertEquals(new ErrorMessageUtil.SourceLocation("same-\u03b1.pl", 700), first); + assertEquals(first, util.getSourceLocationAccurate(firstWarn)); + assertEquals(new ErrorMessageUtil.SourceLocation("lib/Other.pm", 0), + util.getSourceLocationAccurate(secondWarn)); + + Object index = sourceIndex(util); + assertSame(index, sourceIndex(util)); + assertEquals(2, directiveCount(index)); + } + + @Test + void equalAndDistinctTokenIdentitiesKeepIndependentIndexes() throws Exception { + String source = "#line 9 \"logical.pl\"\nwarn 'same';\n"; + List firstTokens = new Lexer(source).tokenize(); + List equalButDistinctTokens = new ArrayList<>(firstTokens); + ErrorMessageUtil first = new ErrorMessageUtil("first.pl", firstTokens); + ErrorMessageUtil second = new ErrorMessageUtil( + "second.pl", equalButDistinctTokens); + int warn = tokenIndex(firstTokens, "warn", 0); + + ErrorMessageUtil.SourceLocation expected = + new ErrorMessageUtil.SourceLocation("logical.pl", 9); + assertEquals(expected, first.getSourceLocationAccurate(warn)); + assertEquals(expected, second.getSourceLocationAccurate(warn)); + assertNotSame(sourceIndex(first), sourceIndex(second)); + + List replacement = new Lexer( + "#line 11 \"changed.pl\"\nwarn 'changed';\n").tokenize(); + first.updateTokens(replacement); + assertEquals(new ErrorMessageUtil.SourceLocation("changed.pl", 11), + first.getSourceLocationAccurate(tokenIndex(replacement, "warn", 0))); + assertEquals(expected, second.getSourceLocationAccurate(warn)); + } + + private static int tokenIndex( + List tokens, String text, int occurrence) { + for (int index = 0; index < tokens.size(); index++) { + if (tokens.get(index).text.equals(text) && occurrence-- == 0) { + return index; + } + } + throw new AssertionError("Missing token: " + text); + } + + private static Object sourceIndex(ErrorMessageUtil util) throws Exception { + Field field = ErrorMessageUtil.class.getDeclaredField("sourceDirectiveIndex"); + field.setAccessible(true); + return field.get(util); + } + + private static int directiveCount(Object sourceIndex) throws Exception { + Field field = sourceIndex.getClass().getDeclaredField("tokenIndexes"); + field.setAccessible(true); + return ((int[]) field.get(sourceIndex)).length; + } +} diff --git a/src/test/java/org/perlonjava/PerlScriptExecutionTest.java b/src/test/java/org/perlonjava/PerlScriptExecutionTest.java index 1c0d7835a3..613220a92a 100644 --- a/src/test/java/org/perlonjava/PerlScriptExecutionTest.java +++ b/src/test/java/org/perlonjava/PerlScriptExecutionTest.java @@ -219,8 +219,8 @@ void setUp() { originalRegexBackend = System.getProperty(REGEX_BACKEND_PROPERTY); // Keep the Perl unit corpus as an explicit forced-Joni compatibility - // gate while automatic production routing temporarily remains - // Java-first. RegexBackendPolicyTest covers the automatic policy. + // gate. Production matching is already Joni-only; the property remains + // solely to exercise the disconnected historical policy parser. System.setProperty(REGEX_BACKEND_PROPERTY, "joni"); // Create a new StandardIO with the capture stream diff --git a/src/test/java/org/perlonjava/RegexDebugOutputTest.java b/src/test/java/org/perlonjava/RegexDebugOutputTest.java new file mode 100644 index 0000000000..1b9080d8ff --- /dev/null +++ b/src/test/java/org/perlonjava/RegexDebugOutputTest.java @@ -0,0 +1,64 @@ +package org.perlonjava; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.ByteArrayOutputStream; +import java.nio.charset.StandardCharsets; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.perlonjava.app.cli.ArgumentParser; +import org.perlonjava.app.cli.CompilerOptions; +import org.perlonjava.app.scriptengine.PerlLanguageProvider; +import org.perlonjava.runtime.io.StandardIO; +import org.perlonjava.runtime.runtimetypes.GlobalVariable; +import org.perlonjava.runtime.runtimetypes.RuntimeIO; + +@Tag("unit") +public class RegexDebugOutputTest extends PerlRuntimeTestBase { + private RuntimeIO originalStdout; + private RuntimeIO originalStderr; + private ByteArrayOutputStream stdout; + private ByteArrayOutputStream stderr; + + @BeforeEach + void setUp() { + PerlLanguageProvider.resetAll(); + originalStdout = RuntimeIO.getStdout(); + originalStderr = RuntimeIO.getStderr(); + stdout = new ByteArrayOutputStream(); + stderr = new ByteArrayOutputStream(); + RuntimeIO.setStdout(new RuntimeIO(new StandardIO(stdout, true))); + RuntimeIO.setStderr(new RuntimeIO(new StandardIO(stderr, false))); + GlobalVariable.getGlobalIO("main::STDOUT").setIO(RuntimeIO.getStdout()); + GlobalVariable.getGlobalIO("main::STDERR").setIO(RuntimeIO.getStderr()); + } + + @AfterEach + void tearDown() { + RuntimeIO.setStdout(originalStdout); + RuntimeIO.setStderr(originalStderr); + GlobalVariable.getGlobalIO("main::STDOUT").setIO(RuntimeIO.getStdout()); + GlobalVariable.getGlobalIO("main::STDERR").setIO(RuntimeIO.getStderr()); + PerlLanguageProvider.resetAll(); + } + + @Test + void reportsNativeProgramAndCompiledOptimizerAnchor() throws Exception { + CompilerOptions options = ArgumentParser.parseArguments(new String[] { + "-e", "use re 'debug'; qr/.*?phase36_debug_label/" + }); + + PerlLanguageProvider.executePerlCode(options, true); + RuntimeIO.getStdout().flush(); + RuntimeIO.getStderr().flush(); + String trace = stderr.toString(StandardCharsets.ISO_8859_1); + + assertTrue(trace.contains("JONI_PATTERN"), trace); + assertTrue(trace.contains("anchored(MBOL) implicit"), trace); + assertFalse(trace.contains("JAVA_PATTERN"), trace); + } +} diff --git a/src/test/java/org/perlonjava/RegexNamedDebugOptionTest.java b/src/test/java/org/perlonjava/RegexNamedDebugOptionTest.java new file mode 100644 index 0000000000..82153b215c --- /dev/null +++ b/src/test/java/org/perlonjava/RegexNamedDebugOptionTest.java @@ -0,0 +1,59 @@ +package org.perlonjava; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.ByteArrayOutputStream; +import java.nio.charset.StandardCharsets; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.perlonjava.app.cli.ArgumentParser; +import org.perlonjava.app.cli.CompilerOptions; +import org.perlonjava.app.scriptengine.PerlLanguageProvider; +import org.perlonjava.runtime.io.StandardIO; +import org.perlonjava.runtime.runtimetypes.GlobalVariable; +import org.perlonjava.runtime.runtimetypes.RuntimeIO; + +@Tag("unit") +public class RegexNamedDebugOptionTest extends PerlRuntimeTestBase { + private RuntimeIO originalStdout; + private RuntimeIO originalStderr; + private ByteArrayOutputStream stderr; + + @BeforeEach + void setUp() { + PerlLanguageProvider.resetAll(); + originalStdout = RuntimeIO.getStdout(); + originalStderr = RuntimeIO.getStderr(); + RuntimeIO.setStdout(new RuntimeIO(new StandardIO(new ByteArrayOutputStream(), true))); + stderr = new ByteArrayOutputStream(); + RuntimeIO.setStderr(new RuntimeIO(new StandardIO(stderr, false))); + GlobalVariable.getGlobalIO("main::STDOUT").setIO(RuntimeIO.getStdout()); + GlobalVariable.getGlobalIO("main::STDERR").setIO(RuntimeIO.getStderr()); + } + + @AfterEach + void tearDown() { + RuntimeIO.setStdout(originalStdout); + RuntimeIO.setStderr(originalStderr); + GlobalVariable.getGlobalIO("main::STDOUT").setIO(RuntimeIO.getStdout()); + GlobalVariable.getGlobalIO("main::STDERR").setIO(RuntimeIO.getStderr()); + PerlLanguageProvider.resetAll(); + } + + @Test + void namedAllOptionEnablesLexicalTrace() throws Exception { + CompilerOptions options = ArgumentParser.parseArguments(new String[] { + "-e", "use re Debug => 'ALL'; qr/phase36_named_debug_trace/" + }); + + PerlLanguageProvider.executePerlCode(options, true); + RuntimeIO.getStderr().flush(); + String trace = stderr.toString(StandardCharsets.ISO_8859_1); + + assertTrue(trace.contains("Compiling REx \"phase36_named_debug_trace\""), trace); + assertTrue(trace.contains("JONI_PATTERN"), trace); + } +} diff --git a/src/test/java/org/perlonjava/runtime/regex/JoniSearchOptimizerTest.java b/src/test/java/org/perlonjava/runtime/regex/JoniSearchOptimizerTest.java new file mode 100644 index 0000000000..9b7b3a02ee --- /dev/null +++ b/src/test/java/org/perlonjava/runtime/regex/JoniSearchOptimizerTest.java @@ -0,0 +1,50 @@ +package org.perlonjava.runtime.regex; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.List; + +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +@Tag("unit") +class JoniSearchOptimizerTest { + private static final RegexFlags FLAGS = RegexFlags.fromModifiers("", ""); + + @Test + void greedyAnyCharacterStarStillFindsAndRejectsRequiredLiterals() { + String prefix = "0".repeat(40_000); + + assertFalse(matches(".*:::\\s*ab", prefix + "::: 0c")); + assertTrue(matches(".*:::\\s*ab", prefix + "::: ab")); + } + + @Test + void exactUtf8FollowersKeepLateCandidatesAndNewlineSemantics() { + assertLateCandidate("¢", "¢x", "¢ok"); + assertLateCandidate("€", "€x", "€ok"); + assertLateCandidate("😀", "😀x", "😀ok"); + assertFalse(matches("\\A.*:::ab", "prefix\n:::ab")); + } + + @Test + void lazyAndGreedyRequiredLiteralsAgreeOnARejectingSubject() { + String subject = "0".repeat(20_000) + "::: ac"; + + assertFalse(matches(".*:::\\s*ab", subject)); + assertFalse(matches(".*?:::\\s*ab", subject)); + } + + private static void assertLateCandidate(String character, String falseSuffix, String trueSuffix) { + String subject = "0".repeat(1_000) + character + falseSuffix + character + trueSuffix; + + assertTrue(matches(".*" + character + "ok", subject)); + assertFalse(matches(".*" + character + "missing", subject)); + } + + private static boolean matches(String source, String input) { + RegexMatcher matcher = new JoniRegexPattern(source, FLAGS).matcher(input, List.of()); + return matcher.find(); + } +} diff --git a/src/test/java/org/perlonjava/runtime/regex/JoniSubjectEncodingCacheTest.java b/src/test/java/org/perlonjava/runtime/regex/JoniSubjectEncodingCacheTest.java new file mode 100644 index 0000000000..8cdcc125c1 --- /dev/null +++ b/src/test/java/org/perlonjava/runtime/regex/JoniSubjectEncodingCacheTest.java @@ -0,0 +1,61 @@ +package org.perlonjava.runtime.regex; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertNotSame; +import static org.junit.jupiter.api.Assertions.assertSame; + +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.perlonjava.runtime.runtimetypes.RuntimeScalar; + +@Tag("unit") +class JoniSubjectEncodingCacheTest { + @Test + void unchangedScalarReusesEncodingButMutationInvalidatesIt() { + RuntimeScalar subject = new RuntimeScalar("a😀b"); + + JoniRegexPattern.InputEncoding first = JoniRegexPattern.inputEncoding( + subject.toString(), subject, false); + JoniRegexPattern.InputEncoding second = JoniRegexPattern.inputEncoding( + subject.toString(), subject, false); + assertSame(first, second); + assertArrayEquals(new int[] {0, 1, 1, 5, 6}, first.charToByte()); + + subject.set("changed"); + JoniRegexPattern.InputEncoding changed = JoniRegexPattern.inputEncoding( + subject.toString(), subject, false); + assertNotSame(first, changed); + } + + @Test + void renderedNonStringScalarDoesNotReuseStaleEncoding() { + RuntimeScalar subject = new RuntimeScalar(42); + + JoniRegexPattern.InputEncoding first = JoniRegexPattern.inputEncoding( + "first", subject, false); + JoniRegexPattern.InputEncoding second = JoniRegexPattern.inputEncoding( + "second", subject, false); + + assertNotSame(first, second); + assertArrayEquals("first".getBytes(java.nio.charset.StandardCharsets.UTF_8), + first.bytes()); + assertArrayEquals("second".getBytes(java.nio.charset.StandardCharsets.UTF_8), + second.bytes()); + } + + @Test + void equalValuedScalarsAndByteModeDoNotShareEncoding() { + RuntimeScalar firstSubject = new RuntimeScalar(new String("é")); + RuntimeScalar secondSubject = new RuntimeScalar(new String("é")); + + JoniRegexPattern.InputEncoding first = JoniRegexPattern.inputEncoding( + firstSubject.toString(), firstSubject, false); + JoniRegexPattern.InputEncoding second = JoniRegexPattern.inputEncoding( + secondSubject.toString(), secondSubject, false); + JoniRegexPattern.InputEncoding bytes = JoniRegexPattern.inputEncoding( + firstSubject.toString(), firstSubject, true); + + assertNotSame(first, second); + assertNotSame(first, bytes); + } +} diff --git a/src/test/java/org/perlonjava/runtime/regex/NativeAsciiStrictRoutingTest.java b/src/test/java/org/perlonjava/runtime/regex/NativeAsciiStrictRoutingTest.java index 433c329ccb..3a4ca9a3b9 100644 --- a/src/test/java/org/perlonjava/runtime/regex/NativeAsciiStrictRoutingTest.java +++ b/src/test/java/org/perlonjava/runtime/regex/NativeAsciiStrictRoutingTest.java @@ -13,7 +13,7 @@ class NativeAsciiStrictRoutingTest { private String originalBackendProperty; @BeforeEach - void forceTemporaryJavaPolicy() { + void forceHistoricalJavaPolicySpelling() { originalBackendProperty = System.getProperty(RegexBackendPolicy.PROPERTY); System.setProperty(RegexBackendPolicy.PROPERTY, "java"); } diff --git a/src/test/java/org/perlonjava/runtime/regex/NativeExtendedClassRoutingTest.java b/src/test/java/org/perlonjava/runtime/regex/NativeExtendedClassRoutingTest.java new file mode 100644 index 0000000000..c0e75fc57d --- /dev/null +++ b/src/test/java/org/perlonjava/runtime/regex/NativeExtendedClassRoutingTest.java @@ -0,0 +1,37 @@ +package org.perlonjava.runtime.regex; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +@Tag("unit") +class NativeExtendedClassRoutingTest { + private String originalBackendProperty; + + @BeforeEach + void selectJavaDiagnosticMode() { + originalBackendProperty = System.getProperty(RegexBackendPolicy.PROPERTY); + System.setProperty(RegexBackendPolicy.PROPERTY, "java"); + } + + @AfterEach + void restoreBackendProperty() { + if (originalBackendProperty == null) System.clearProperty(RegexBackendPolicy.PROPERTY); + else System.setProperty(RegexBackendPolicy.PROPERTY, originalBackendProperty); + } + + @Test + void routesRealExtendedClassesToNativeJoni() { + assertTrue(RegexBackendPolicy.useJoni("(?[ [:ascii:] & [:graph:] ])")); + } + + @Test + void ignoresEscapedAndQuotedExtendedClassLookalikes() { + assertFalse(RegexBackendPolicy.useJoni("\\(\\?\\[")); + assertFalse(RegexBackendPolicy.useJoni("\\Q(?[ [:ascii:] ])\\E")); + } +} diff --git a/src/test/java/org/perlonjava/runtime/regex/NativeScriptRunRoutingTest.java b/src/test/java/org/perlonjava/runtime/regex/NativeScriptRunRoutingTest.java new file mode 100644 index 0000000000..ed09a8adc1 --- /dev/null +++ b/src/test/java/org/perlonjava/runtime/regex/NativeScriptRunRoutingTest.java @@ -0,0 +1,25 @@ +package org.perlonjava.runtime.regex; + +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@Tag("unit") +class NativeScriptRunRoutingTest { + @Test + void routesScriptRunFormsToJoni() { + assertTrue(JoniRegexPattern.requiresJoniBackend("(*script_run:a|ab)c")); + assertTrue(JoniRegexPattern.requiresJoniBackend("(*sr:a|ab)c")); + assertTrue(JoniRegexPattern.requiresJoniBackend("(*atomic_script_run:a|ab)c")); + assertTrue(JoniRegexPattern.requiresJoniBackend("(*asr:a|ab)c")); + } + + @Test + void ignoresScriptRunLookalikes() { + assertFalse(JoniRegexPattern.requiresJoniBackend("\\Q(*script_run:a)\\E")); + assertFalse(JoniRegexPattern.requiresJoniBackend("[(?*script_run:)]")); + assertFalse(JoniRegexPattern.requiresJoniBackend("(?# (*script_run:a))ordinary")); + } +} diff --git a/src/test/java/org/perlonjava/runtime/regex/PerlCasingAliasFoldPolicyTest.java b/src/test/java/org/perlonjava/runtime/regex/PerlCasingAliasFoldPolicyTest.java new file mode 100644 index 0000000000..538fc3e4c8 --- /dev/null +++ b/src/test/java/org/perlonjava/runtime/regex/PerlCasingAliasFoldPolicyTest.java @@ -0,0 +1,43 @@ +package org.perlonjava.runtime.regex; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.joni.CharacterPropertyResolver; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +@Tag("unit") +class PerlCasingAliasFoldPolicyTest { + + @Test + void unicodePropertyAliasesShareTheirCanonicalCasingFoldPolicy() { + for (String property : new String[] {"Upper", "Uppercase", "Lower", "Lowercase"}) { + CharacterPropertyResolver.Result result = + UnicodeResolver.resolveJoniProperty(property, false, true); + assertNotNull(result, property); + assertTrue(result.caseFold, property); + } + } + + @Test + void aliasRangesRemainDirectionalBeforeJoniAppliesIgnoreCase() { + CharacterPropertyResolver.Result upper = + UnicodeResolver.resolveJoniProperty("Upper", false, false); + CharacterPropertyResolver.Result lower = + UnicodeResolver.resolveJoniProperty("Lower", false, false); + assertTrue(contains(upper.ranges, 'A')); + assertFalse(contains(upper.ranges, 'a')); + assertTrue(contains(lower.ranges, 'a')); + assertFalse(contains(lower.ranges, 'A')); + } + + private static boolean contains(int[] ranges, int codePoint) { + for (int index = 0; index < ranges[0]; index++) { + if (codePoint >= ranges[index * 2 + 1] + && codePoint <= ranges[index * 2 + 2]) return true; + } + return false; + } +} diff --git a/src/test/java/org/perlonjava/runtime/regex/PerlLineBreakPropertyResolverTest.java b/src/test/java/org/perlonjava/runtime/regex/PerlLineBreakPropertyResolverTest.java new file mode 100644 index 0000000000..4c513c3cd3 --- /dev/null +++ b/src/test/java/org/perlonjava/runtime/regex/PerlLineBreakPropertyResolverTest.java @@ -0,0 +1,21 @@ +package org.perlonjava.runtime.regex; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import org.joni.CharacterPropertyResolver; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +@Tag("unit") +class PerlLineBreakPropertyResolverTest { + @Test + void resolvesLineBreakAliasesWithoutCaseFolding() { + for (String property : new String[] {"lb=CR", "Line_Break=Carriage_Return"}) { + CharacterPropertyResolver.Result result = + UnicodeResolver.resolveJoniProperty(property, false, true); + assertNotNull(result, property); + assertFalse(result.caseFold, property); + } + } +} diff --git a/src/test/java/org/perlonjava/runtime/regex/PerlUnicodeScalarNameDataTest.java b/src/test/java/org/perlonjava/runtime/regex/PerlUnicodeScalarNameDataTest.java new file mode 100644 index 0000000000..d7e8978251 --- /dev/null +++ b/src/test/java/org/perlonjava/runtime/regex/PerlUnicodeScalarNameDataTest.java @@ -0,0 +1,64 @@ +package org.perlonjava.runtime.regex; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.ByteArrayOutputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +@Tag("unit") +class PerlUnicodeScalarNameDataTest { + + @Test + void retainsCanonicalNamesAndEveryAliasFamilyFromNamePl() { + assertEquals(35_079, PerlUnicodeScalarNameData.entryCount()); + assertEquals(0, PerlUnicodeScalarNameData.DUPLICATE_NAME_COUNT); + assertEquals(0x00ad, PerlUnicodeScalarNameData.codePoint("SOFT HYPHEN")); + assertEquals(0x00ad, PerlUnicodeScalarNameData.codePoint("SHY")); + assertEquals(0x000a, PerlUnicodeScalarNameData.codePoint("LINE FEED (LF)")); + assertEquals(0x000a, PerlUnicodeScalarNameData.codePoint("NEW LINE")); + assertEquals(0x01a2, PerlUnicodeScalarNameData.codePoint( + "LATIN CAPITAL LETTER GHA")); + assertEquals(0x01a2, PerlUnicodeScalarNameData.codePoint( + "LATIN CAPITAL LETTER OI")); + assertEquals(0xfeff, PerlUnicodeScalarNameData.codePoint("BOM")); + assertEquals(-1, PerlUnicodeScalarNameData.codePoint("NOT A CHARACTER NAME")); + assertEquals(-1, PerlUnicodeScalarNameData.codePoint(null)); + } + + @Test + void generatorIsDeterministicAndFresh() throws Exception { + Path root = Path.of(System.getProperty("user.dir")); + Path generator = root.resolve( + "dev/tools/generate_perl_unicode_scalar_name_data.pl"); + Path generated = root.resolve( + "src/main/java/org/perlonjava/runtime/regex/PerlUnicodeScalarNameData.java"); + + byte[] first = generate(root, generator); + byte[] second = generate(root, generator); + assertArrayEquals(first, second, "generator output must be deterministic"); + assertArrayEquals(canonicalLf(Files.readAllBytes(generated)), canonicalLf(first), + "checked-in scalar-name data must match current imported Name.pl"); + } + + private static byte[] generate(Path root, Path generator) throws Exception { + Process process = new ProcessBuilder("perl", generator.toString()) + .directory(root.toFile()) + .redirectErrorStream(true) + .start(); + ByteArrayOutputStream output = new ByteArrayOutputStream(); + process.getInputStream().transferTo(output); + assertEquals(0, process.waitFor(), new String(output.toByteArray())); + return output.toByteArray(); + } + + private static byte[] canonicalLf(byte[] bytes) { + return new String(bytes, StandardCharsets.UTF_8) + .replace("\r\n", "\n") + .getBytes(StandardCharsets.UTF_8); + } +} diff --git a/src/main/java/org/perlonjava/runtime/regex/RegexBackendPolicy.java b/src/test/java/org/perlonjava/runtime/regex/RegexBackendPolicy.java similarity index 78% rename from src/main/java/org/perlonjava/runtime/regex/RegexBackendPolicy.java rename to src/test/java/org/perlonjava/runtime/regex/RegexBackendPolicy.java index d341c3c42d..eb816fb351 100644 --- a/src/main/java/org/perlonjava/runtime/regex/RegexBackendPolicy.java +++ b/src/test/java/org/perlonjava/runtime/regex/RegexBackendPolicy.java @@ -1,11 +1,11 @@ package org.perlonjava.runtime.regex; /** - * Temporary migration policy for comparing the canonical Joni matcher with - * the legacy Java matcher. Default and auto modes use Joni; explicit Java mode - * remains only for differential diagnosis. Constructs unavailable in Java may - * still force Joni even in explicit Java mode. This class and its controls are - * removed when the Java matching backend is retired. + * Test-only model of the retired regex-backend selector. + * + *

    The historical routing tests remain useful migration documentation, but + * this class is deliberately absent from production artifacts. Production + * matching is unconditionally implemented by Joni.

    */ final class RegexBackendPolicy { static final String PROPERTY = "jperl.regex.backend"; diff --git a/src/test/java/org/perlonjava/runtime/regex/RuntimeRegexBackendInvarianceTest.java b/src/test/java/org/perlonjava/runtime/regex/RuntimeRegexBackendInvarianceTest.java new file mode 100644 index 0000000000..9373d3893a --- /dev/null +++ b/src/test/java/org/perlonjava/runtime/regex/RuntimeRegexBackendInvarianceTest.java @@ -0,0 +1,27 @@ +package org.perlonjava.runtime.regex; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.perlonjava.runtime.runtimetypes.PerlRuntime; + +@Tag("unit") +class RuntimeRegexBackendInvarianceTest { + @Test + void retiredJavaPropertyCannotChangeTheProductionEngine() { + String original = System.getProperty("jperl.regex.backend"); + System.setProperty("jperl.regex.backend", "java"); + try (PerlRuntime.Binding ignored = new PerlRuntime().bind()) { + RuntimeRegex regex = RuntimeRegex.compile("ordinary", ""); + assertNotNull(regex.recursivePattern, + "ordinary production patterns must compile through Joni"); + } finally { + if (original == null) { + System.clearProperty("jperl.regex.backend"); + } else { + System.setProperty("jperl.regex.backend", original); + } + } + } +} diff --git a/src/test/java/org/perlonjava/runtime/regex/RuntimeRegexTemplateTest.java b/src/test/java/org/perlonjava/runtime/regex/RuntimeRegexTemplateTest.java new file mode 100644 index 0000000000..fc9bbd7661 --- /dev/null +++ b/src/test/java/org/perlonjava/runtime/regex/RuntimeRegexTemplateTest.java @@ -0,0 +1,35 @@ +package org.perlonjava.runtime.regex; + +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +@Tag("unit") +class RuntimeRegexTemplateTest { + @Test + void rejectsMalformedInternalCalloutSlots() { + String[] malformed = { + "\u001e", + "\u001eX0\u001f", + "\u001eB\u001f", + "\u001eB0", + "\u001eB2147483648\u001f", + }; + + for (String pattern : malformed) { + IllegalArgumentException error = assertThrows(IllegalArgumentException.class, + () -> RuntimeRegexTemplate.materializeTrustedCallouts(pattern, 1)); + assertEquals("Malformed internal regex callout slot", error.getMessage()); + } + } + + @Test + void preservesRawSlotBytesOutsideTheStructuralTemplateBoundary() { + String raw = "\u001eB0\u001f"; + assertEquals(raw, RuntimeRegexTemplate.materializeTrustedCallouts(raw, 0)); + assertEquals(raw, RuntimeRegexTemplate.materializeTrustedCallouts( + "\u001e\u001eB0\u001f", 1)); + } +} diff --git a/src/test/java/org/perlonjava/runtime/regex/UnicodeNamedCharacterWhitespaceTest.java b/src/test/java/org/perlonjava/runtime/regex/UnicodeNamedCharacterWhitespaceTest.java new file mode 100644 index 0000000000..8ce0626ec9 --- /dev/null +++ b/src/test/java/org/perlonjava/runtime/regex/UnicodeNamedCharacterWhitespaceTest.java @@ -0,0 +1,15 @@ +package org.perlonjava.runtime.regex; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +@Tag("unit") +class UnicodeNamedCharacterWhitespaceTest { + @Test + void trimsWhitespaceAroundUPlusNames() { + assertEquals(0x100, UnicodeResolver.getCodePointFromName(" U+0100 ")); + assertEquals(0x1f642, UnicodeResolver.getCodePointFromName("\tU+1F642\n")); + } +} diff --git a/src/test/resources/unit/caller_negative_frame.t b/src/test/resources/unit/caller_negative_frame.t new file mode 100644 index 0000000000..a6f7c7df68 --- /dev/null +++ b/src/test/resources/unit/caller_negative_frame.t @@ -0,0 +1,24 @@ +#!/usr/bin/perl +use strict; +use warnings; +use Test::More tests => 6; + +sub inspect_negative_frames { + my @minus_one = caller(-1); + my @minus_two = caller(-2); + my $scalar_minus_one = caller(-1); + my $scalar_minus_two = caller(-2); + return (\@minus_one, \@minus_two, $scalar_minus_one, $scalar_minus_two); +} + +sub outer { inspect_negative_frames() } + +my ($minus_one, $minus_two, $scalar_minus_one, $scalar_minus_two) = outer(); +is(scalar(@$minus_one), 0, 'caller(-1) returns an empty list'); +is(scalar(@$minus_two), 0, 'caller(-2) returns an empty list'); +ok(!defined($scalar_minus_one), 'scalar caller(-1) is undef'); +ok(!defined($scalar_minus_two), 'scalar caller(-2) is undef'); + +my @top_level = caller(-1); +is(scalar(@top_level), 0, 'top-level caller(-1) returns an empty list'); +ok(!defined(scalar caller(-1)), 'top-level scalar caller(-1) is undef'); diff --git a/src/test/resources/unit/charnames_generated_scalar_aliases.t b/src/test/resources/unit/charnames_generated_scalar_aliases.t new file mode 100644 index 0000000000..8b9c0be945 --- /dev/null +++ b/src/test/resources/unit/charnames_generated_scalar_aliases.t @@ -0,0 +1,43 @@ +use strict; +use warnings; +use Test::More; + +{ + use charnames ':full'; + is(ord("\N{SOFT HYPHEN}"), 0x00AD, 'canonical scalar name resolves'); + is(ord("\N{SHY}"), 0x00AD, 'abbreviation alias resolves'); + is(ord("\N{LINE FEED (LF)}"), 0x000A, 'control alias resolves'); + is(ord("\N{LATIN CAPITAL LETTER GHA}"), 0x01A2, + 'correction alias resolves'); + is(ord("\N{BOM}"), 0xFEFF, 'alternate alias resolves'); + is(ord("\N{CJK UNIFIED IDEOGRAPH-4E00}"), 0x4E00, + 'algorithmic CJK name remains available'); + is(ord("\N{HANGUL SYLLABLE GA}"), 0xAC00, + 'algorithmic Hangul name remains available'); + is_deeply([map ord, split //, "\N{KEYCAP DIGIT NINE}"], + [0x0039, 0xFE0F, 0x20E3], 'named sequence remains multi-scalar'); +} + +{ + use charnames ':loose'; + is(ord("\N{latin-capital_letter a}"), 0x0041, + 'loose full-name matching remains active'); +} + +my $strict_loose = eval q{use charnames ':full'; "\N{latin-capital_letter a}"}; +ok(!defined $strict_loose, ':full rejects a loose spelling'); +like($@, qr/Unknown charname/, ':full rejection keeps Perl diagnostic'); + +my $unknown = eval q{use charnames ':full'; "\N{NOT A CHARACTER NAME}"}; +ok(!defined $unknown, 'unknown standard name stays unresolved'); +like($@, qr/Unknown charname/, 'unknown standard name keeps Perl diagnostic'); + +my $custom; +{ + use lib 'src/test/resources/unit/lib'; + use Phase36Cname; + $custom = "\N{CUSTOM VALUE}"; +} +is($custom, 'CUSTOM VALUE', 'custom lexical translator stays authoritative'); + +done_testing(); diff --git a/src/test/resources/unit/chop_wide_scalars.t b/src/test/resources/unit/chop_wide_scalars.t new file mode 100644 index 0000000000..1a12d24915 --- /dev/null +++ b/src/test/resources/unit/chop_wide_scalars.t @@ -0,0 +1,16 @@ +use strict; +use warnings; +no warnings 'portable'; +use Test::More tests => 6; + +my $high = chr(0x80000001) . chr(0x80000000); +is(chop($high), chr(0x80000000), 'chop returns a beyond-Unicode scalar'); +is($high, chr(0x80000001), 'chop removes one beyond-Unicode scalar'); + +my $highest = chr(0x7fffffffffffffff) . chr(0x7ffffffffffffffe); +is(chop($highest), chr(0x7ffffffffffffffe), 'chop returns the highest signed-IV scalar'); +is($highest, chr(0x7fffffffffffffff), 'chop preserves the preceding highest scalar'); + +my $supplementary = "A" . chr(0x1f642); +is(chop($supplementary), chr(0x1f642), 'chop returns one supplementary scalar'); +is($supplementary, 'A', 'chop removes one supplementary scalar'); diff --git a/src/test/resources/unit/eval_concat_warning_scope.t b/src/test/resources/unit/eval_concat_warning_scope.t new file mode 100644 index 0000000000..a3f1678e39 --- /dev/null +++ b/src/test/resources/unit/eval_concat_warning_scope.t @@ -0,0 +1,36 @@ +use strict; +use warnings FATAL => 'uninitialized'; + +print "1..3\n"; + +{ + no warnings 'uninitialized'; + my $ok = eval q{my $value; my $text = '<' . $value . '>'; 1}; + print defined($ok) + ? "ok 1 - eval inherits lexical no warnings\n" + : "not ok 1 - eval inherits lexical no warnings: $@\n"; +} + +my @warnings; +my $code = eval q{ + use warnings NONFATAL => 'uninitialized'; + no strict 'vars'; + sub { $eval_warning_value = $eval_warning_value . 'suffix' } +}; +{ + local $SIG{__WARN__} = sub { push @warnings, shift }; + $code->(); +} +print grep(/uninitialized value/i, @warnings) + ? "ok 2 - eval can enable concatenation warnings\n" + : "not ok 2 - eval can enable concatenation warnings\n"; + +my $quiet = eval q{ + no warnings 'uninitialized'; + my $value; + my $text = '<' . $value . '>'; + 1 +}; +print defined($quiet) + ? "ok 3 - eval can disable inherited fatal warning\n" + : "not ok 3 - eval can disable inherited fatal warning: $@\n"; diff --git a/src/test/resources/unit/fixtures/raw_utf8_nel_source.pl b/src/test/resources/unit/fixtures/raw_utf8_nel_source.pl new file mode 100644 index 0000000000..5fa6b70ea3 --- /dev/null +++ b/src/test/resources/unit/fixtures/raw_utf8_nel_source.pl @@ -0,0 +1,7 @@ +use strict; +use warnings; +use utf8; + +our $RAW_UTF8_NEL = "…"; +our $RAW_UTF8_NEL_REGEX = qr/(?[ \t… ])/; +1; diff --git a/src/test/resources/unit/foreach_implicit_live_array.t b/src/test/resources/unit/foreach_implicit_live_array.t new file mode 100644 index 0000000000..94493455e5 --- /dev/null +++ b/src/test/resources/unit/foreach_implicit_live_array.t @@ -0,0 +1,75 @@ +use strict; +use warnings; +use Test::More tests => 11; + +my @implicit_append = (1, 2); +my @seen; +for (@implicit_append) { + push @seen, $_; + push @implicit_append, 3 if $_ == 1; +} +is_deeply(\@seen, [1, 2, 3], 'implicit foreach visits appended elements'); +is_deeply(\@implicit_append, [1, 2, 3], 'implicit append preserves array'); + +my @implicit_delete = (1, 2, 3); +@seen = (); +for (@implicit_delete) { + push @seen, $_; + pop @implicit_delete if $_ == 1; +} +is_deeply(\@seen, [1, 2], 'implicit foreach follows a shortened array'); +is_deeply(\@implicit_delete, [1, 2], 'implicit deletion preserves survivors'); + +my @lexical_append = (1, 2); +@seen = (); +for my $item (@lexical_append) { + push @seen, $item; + push @lexical_append, 3 if $item == 1; +} +is_deeply(\@seen, [1, 2, 3], 'lexical foreach retains live-array behavior'); + +my @aliases = (1, 2); +for (@aliases) { + $_ *= 10; +} +is_deeply(\@aliases, [10, 20], 'implicit iterator aliases array elements'); + +$_ = 'outside'; +{ + local $_ = 'localized'; + my @outer = (1); + my @inner = (2); + @seen = (); + for (@outer) { + push @seen, "o$_"; + for (@inner) { + push @seen, "i$_"; + } + push @seen, "r$_"; + } + is_deeply(\@seen, ['o1', 'i2', 'r1'], + 'nested implicit loops restore the outer alias'); + is($_, 'localized', 'implicit foreach restores localized underscore'); +} +is($_, 'outside', 'local underscore restores its package value'); + +{ + package Local::TieArray; + sub TIEARRAY { bless { values => [10, 20] }, shift } + sub FETCHSIZE { scalar @{$_[0]{values}} } + sub FETCH { $_[0]{values}[$_[1]] } + sub STORE { $_[0]{values}[$_[1]] = $_[2] } +} + +tie my @tied, 'Local::TieArray'; +@seen = (); +for (@tied) { + push @seen, $_; +} +is_deeply(\@seen, [10, 20], 'tied arrays retain fetched iteration values'); + +@seen = (); +for (1, 2) { + push @seen, $_; +} +is_deeply(\@seen, [1, 2], 'non-array list expressions retain snapshot iteration'); diff --git a/src/test/resources/unit/interpreter_eval_named_sub_lexical_mutation.t b/src/test/resources/unit/interpreter_eval_named_sub_lexical_mutation.t new file mode 100644 index 0000000000..e3ef5fb51b --- /dev/null +++ b/src/test/resources/unit/interpreter_eval_named_sub_lexical_mutation.t @@ -0,0 +1,24 @@ +use strict; +use warnings; +use Test::More tests => 7; + +my $calls = 0; +my $defined = eval q{ + sub interpreter_eval_named_sub_lexical_mutation { + return ++$calls; + } + 1; +}; + +ok($defined, 'eval STRING defines a named closure') or diag($@); +is($calls, 0, 'captured lexical starts unchanged'); +is(interpreter_eval_named_sub_lexical_mutation(), 1, + 'named closure returns its first increment'); +is($calls, 1, 'named closure publishes its first lexical mutation'); + +$calls = 40; +is(interpreter_eval_named_sub_lexical_mutation(), 41, + 'named closure observes a later outer lexical mutation'); +is($calls, 41, 'named closure publishes a later lexical mutation'); +is(interpreter_eval_named_sub_lexical_mutation(), 42, + 'named closure retains the shared lexical cell across calls'); diff --git a/src/test/resources/unit/interpreter_raw_utf8_source.t b/src/test/resources/unit/interpreter_raw_utf8_source.t new file mode 100644 index 0000000000..fec38b9857 --- /dev/null +++ b/src/test/resources/unit/interpreter_raw_utf8_source.t @@ -0,0 +1,28 @@ +use strict; +use warnings; +use Test::More tests => 8; + +our $RAW_UTF8_NEL; +our $RAW_UTF8_NEL_REGEX; +my $fixture = './src/test/resources/unit/fixtures/raw_utf8_nel_source.pl'; +open my $source, '<:raw', $fixture or die "Cannot open $fixture: $!"; +local $/; +my $source_bytes = <$source>; +close $source; +is(() = $source_bytes =~ /\xC2\x85/g, 2, + 'separate fixture contains two raw UTF-8 NEL byte sequences'); + +my $loaded = do $fixture; + +ok($loaded, 'ASCII harness loads the separate raw UTF-8 source fixture') + or diag($@ || $!); +is(length($RAW_UTF8_NEL), 1, 'raw UTF-8 NEL decodes to one source character'); +is(ord($RAW_UTF8_NEL), 0x85, 'raw UTF-8 NEL preserves its code point'); +is(unpack('H*', $RAW_UTF8_NEL), '85', 'decoded NEL retains Perl character bytes'); +ok(utf8::is_utf8($RAW_UTF8_NEL), 'raw UTF-8 source retains its Unicode flag'); + +my $runtime_regex = qr/(?[ [$RAW_UTF8_NEL] ])/; +like($RAW_UTF8_NEL, $runtime_regex, + 'ASCII source can interpolate the decoded character into a regex'); +unlike($RAW_UTF8_NEL, $RAW_UTF8_NEL_REGEX, + 'regex parsed from the fixture treats raw NEL as pattern whitespace'); diff --git a/src/test/resources/unit/lib/Phase36CnameMode.pm b/src/test/resources/unit/lib/Phase36CnameMode.pm new file mode 100644 index 0000000000..d4f7fae603 --- /dev/null +++ b/src/test/resources/unit/lib/Phase36CnameMode.pm @@ -0,0 +1,18 @@ +package Phase36CnameMode; + +use strict; +use warnings; + +our @Modes; + +sub translator { + my ($name) = @_; + push @Modes, utf8::is_utf8($name) ? 'U' : 'B'; + return $name eq 'FOO' || $name eq 'BAZ' ? 'A' : 'B'; +} + +sub import { + $^H{charnames} = \&translator; +} + +1; diff --git a/src/test/resources/unit/regex/LocalDynamicCharnames.pm b/src/test/resources/unit/regex/LocalDynamicCharnames.pm new file mode 100644 index 0000000000..a78ad04783 --- /dev/null +++ b/src/test/resources/unit/regex/LocalDynamicCharnames.pm @@ -0,0 +1,21 @@ +package LocalDynamicCharnames; + +use strict; +use warnings; + +our %seen; + +sub translator { + my ($name) = @_; + return 'foo' if $name eq 'FOO'; + return 'bar' if $name eq 'BAR'; + return '' if $name eq 'EMPTY'; + return chr(65 + $seen{$name}++) if $name eq 'EVIL'; + return; +} + +sub import { + $^H{charnames} = \&translator; +} + +1; diff --git a/src/test/resources/unit/regex/LocalPermissiveCharnames.pm b/src/test/resources/unit/regex/LocalPermissiveCharnames.pm new file mode 100644 index 0000000000..ab05a38587 --- /dev/null +++ b/src/test/resources/unit/regex/LocalPermissiveCharnames.pm @@ -0,0 +1,14 @@ +package LocalPermissiveCharnames; + +use strict; +use warnings; + +sub translator { + return $_[0]; +} + +sub import { + $^H{charnames} = \&translator; +} + +1; diff --git a/src/test/resources/unit/regex/analyser_variable_lookbehind_warning_defaults.t b/src/test/resources/unit/regex/analyser_variable_lookbehind_warning_defaults.t new file mode 100644 index 0000000000..b8377fe83f --- /dev/null +++ b/src/test/resources/unit/regex/analyser_variable_lookbehind_warning_defaults.t @@ -0,0 +1,38 @@ +use strict; +use Test::More; + +sub warnings_for { + my ($source) = @_; + my @warnings; + local $SIG{__WARN__} = sub { push @warnings, @_ }; + local $^W; + my $compiled = eval $source; + is $@, '', "compiled: $source"; + return \@warnings; +} + +my $strict = q{no warnings 'experimental::re_strict'; use re 'strict'; }; +my $pattern = q{m/(?<=(p|qq|rrr))/}; + +my $default = warnings_for($pattern); +like join('', @$default), qr/Variable length .*lookbehind.*experimental/, + 'experimental::vlb warning is default-on without use re strict'; + +my $default_suppressed = warnings_for( + q{no warnings 'experimental::vlb'; } . $pattern); +is scalar(@$default_suppressed), 0, + 'non-strict explicit experimental::vlb suppression wins'; + +my $isolated = warnings_for($strict . $pattern); +like join('', @$isolated), qr/Variable length .*lookbehind.*experimental/, + 'use re strict makes experimental::vlb warning default-on'; + +my $suppressed = warnings_for( + $strict . q{no warnings 'experimental::vlb'; } . $pattern); +is scalar(@$suppressed), 0, 'explicit experimental::vlb suppression wins'; + +my $after_suppression = warnings_for($strict . $pattern); +like join('', @$after_suppression), qr/Variable length .*lookbehind.*experimental/, + 'suppression in a prior eval does not leak into the next eval'; + +done_testing; diff --git a/src/test/resources/unit/regex/analyser_variable_lookbehind_warnings.t b/src/test/resources/unit/regex/analyser_variable_lookbehind_warnings.t new file mode 100644 index 0000000000..6ea59d27a5 --- /dev/null +++ b/src/test/resources/unit/regex/analyser_variable_lookbehind_warnings.t @@ -0,0 +1,29 @@ +use strict; +use warnings; +use Test::More tests => 10; + +for my $pattern ( + '(?<=(p|qq|rrr))', + '(? 4; + +for my $pattern ('(?=a){1,3}\x{100}', '(a|b)(?=a){3}\x{100}') { + my $warning = ''; + my $compiled; + { + local $SIG{__WARN__} = sub { $warning .= $_[0] }; + $compiled = eval "qr/$pattern/"; + } + ok(defined $compiled, "$pattern compiles"); + like($warning, qr/Quantifier unexpected on zero-length expression/, + "$pattern emits the zero-length quantifier warning"); +} diff --git a/src/test/resources/unit/regex/boundary_unicode_mode_policy.t b/src/test/resources/unit/regex/boundary_unicode_mode_policy.t new file mode 100644 index 0000000000..580396fbef --- /dev/null +++ b/src/test/resources/unit/regex/boundary_unicode_mode_policy.t @@ -0,0 +1,30 @@ +use strict; +use warnings; +use Test::More tests => 7; + +my @warnings; +{ + local $SIG{__WARN__} = sub { push @warnings, @_ }; + eval q{qr/\b{g}/}; +} +is($@, '', 'short grapheme-boundary alias compiles'); +is_deeply(\@warnings, [], 'short grapheme-boundary alias is silent in Unicode mode'); + +@warnings = (); +{ + local $SIG{__WARN__} = sub { push @warnings, @_ }; + eval q{qr/\b{g}/a}; +} +is($@, '', 'short grapheme-boundary alias compiles under /a'); +is(scalar @warnings, 1, 'short grapheme-boundary alias warns once under /a'); +like($warnings[0], qr/^Using \/u for '\\b\{g\}' instead of \/a in regex;/, + 'short alias warning preserves its source spelling'); + +@warnings = (); +{ + local $SIG{__WARN__} = sub { push @warnings, @_ }; + eval q{qr/\B{gcb}/a}; +} +is($@, '', 'long grapheme-boundary spelling compiles under /a'); +like($warnings[0], qr/^Using \/u for '\\B\{gcb\}' instead of \/a in regex;/, + 'long spelling warning preserves negation and source spelling'); diff --git a/src/test/resources/unit/regex/branch_reset_capture_semantics.t b/src/test/resources/unit/regex/branch_reset_capture_semantics.t new file mode 100644 index 0000000000..beb44e0963 --- /dev/null +++ b/src/test/resources/unit/regex/branch_reset_capture_semantics.t @@ -0,0 +1,41 @@ +use strict; +use warnings; +use Test::More; + +plan skip_all => 'GH 20653 semantics require Perl 5.44+' if $] < 5.044; + +ok('bbab' =~ /(?|(?a)|(?b))\1(?&a)(?&b)/, + 'branch-reset numbered and named subroutine targets share captures'); +ok('byb' =~ /(?|(?a)|(?b))(?()x|y)\1/, + 'named condition sees unset sibling capture'); +ok(!('bxb' =~ /(?|(?a)|(?b))(?()x|y)\1/), + 'named condition rejects wrong unset-capture branch'); +ok('axa' =~ /(?|(?a)|(?b))(?()x|y)\1/, + 'named condition sees set capture'); + +'a' =~ /(?|(?a)|(?b))/; +is("$1-$+{a}-" . (defined $+{b} ? $+{b} : ''), 'a-a-', + 'first branch publishes only its named capture'); +'b' =~ /(?|(?a)|(?b))/; +is("$1-" . (defined $+{a} ? $+{a} : '') . "-$+{b}", 'b--b', + 'second branch publishes only its named capture'); + +for my $case ( + ['preabcpost', 'a-b-c'], + ['predepost', 'd-e-'], + ['prefpost', 'f--'], +) { + my ($subject, $expected) = @$case; + $subject =~ /(?
    pre)(?|(?a)(?b)(?c)|(?d)(?e)|(?f))(?post)/;
    +    is("$2-" . (defined $3 ? $3 : '') . '-' . (defined $4 ? $4 : ''),
    +        $expected, 'branch-reset physical slots preserve post-group numbering');
    +}
    +
    +for my $letter (qw(a b c)) {
    +    my $subject = $letter x 2;
    +    ok($subject =~ /((?|(?a)(?-1)|(?b)(?-1)|(?c)(?-1)))/,
    +        'relative subroutine target resolves inside each branch-reset alternative');
    +    is($1, $subject, 'relative subroutine target consumes the matching pair');
    +}
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/byte_posix_ascii_complement.t b/src/test/resources/unit/regex/byte_posix_ascii_complement.t
    new file mode 100644
    index 0000000000..6cd4ce79b4
    --- /dev/null
    +++ b/src/test/resources/unit/regex/byte_posix_ascii_complement.t
    @@ -0,0 +1,13 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 7;
    +
    +my $suffix = chr(0xff) x 2;
    +my $subject = "ABcd01Xy__--  " . ("\0" x 2) . $suffix;
    +ok($subject =~ /([[:^ascii:]]+)/, 'POSIX non-ASCII class finds the suffix');
    +is($1, $suffix, 'capture contains the non-ASCII suffix');
    +ok($suffix =~ /[[:^ascii:]]/, 'direct non-ASCII scalar matches');
    +ok(chr(0x80) =~ /[[:^ascii:]]/, 'lower high byte matches');
    +ok(chr(0xff) =~ /[[:^ascii:]]/, 'upper high byte matches');
    +ok(chr(0x7f) !~ /[[:^ascii:]]/, 'ASCII boundary does not match complement');
    +ok(chr(0xff) !~ /[[:ascii:]]/, 'positive ASCII class excludes high byte');
    diff --git a/src/test/resources/unit/regex/byte_property_fold_promotion.t b/src/test/resources/unit/regex/byte_property_fold_promotion.t
    new file mode 100644
    index 0000000000..3927179f63
    --- /dev/null
    +++ b/src/test/resources/unit/regex/byte_property_fold_promotion.t
    @@ -0,0 +1,44 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +
    +my $subject = "\xC0a";
    +utf8::downgrade($subject, 1);
    +
    +ok($subject =~ /\xE0\pL/i,
    +    'literal byte followed by a property promotes case folding');
    +is($&, $subject,
    +    'literal property fold captures the complete byte subject');
    +
    +my $literal = "\xE0";
    +utf8::downgrade($literal, 1);
    +my $pattern = qr/$literal\pL/i;
    +ok($subject =~ $pattern,
    +    'interpolated byte followed by a property promotes case folding');
    +is($&, $subject,
    +    'interpolated property fold captures the complete byte subject');
    +
    +my $byte_upper = chr 0xC0;
    +utf8::downgrade($byte_upper, 1);
    +ok($byte_upper !~ /(?d:[]\P{Lowercase}_])/i,
    +    'leading literal close keeps a property inside its byte class');
    +ok($byte_upper !~ /(?d:[[:digit:]\P{Lowercase}_])/i,
    +    'POSIX nesting keeps a property inside its byte class');
    +ok($subject =~ /(?d:[[:digit:]]*)\xE0\pL/i,
    +    'a property after a POSIX class promotes the following byte fold');
    +is($&, $subject,
    +    'the POSIX class scanner returns to top level after its outer close');
    +
    +no warnings 'experimental::regex_sets';
    +my $byte_lower = chr 0xE0;
    +utf8::downgrade($byte_lower, 1);
    +ok($byte_lower =~
    +        /(?d:(?[ ([\x{e0}] + \p{Hex_Digit}) - \p{Hex_Digit} ]))/i,
    +    'nested extended classes retain their surviving byte literal');
    +ok($byte_upper =~
    +        /(?d:(?[ ([\x{e0}] + \p{Hex_Digit}) - \p{Hex_Digit} ]))/i,
    +    'nested extended classes retain byte fold provenance');
    +ok('[A' =~ /^\[\p{Lowercase}$/i,
    +    'an escaped opening bracket does not hide a top-level property');
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/callback_cache_identity.t b/src/test/resources/unit/regex/callback_cache_identity.t
    new file mode 100644
    index 0000000000..c022c504aa
    --- /dev/null
    +++ b/src/test/resources/unit/regex/callback_cache_identity.t
    @@ -0,0 +1,30 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +
    +my @seen;
    +
    +sub callback_for {
    +    my ($label) = @_;
    +    return qr/(?{ push @seen, $label })/;
    +}
    +
    +my $a = callback_for('A');
    +my $b = callback_for('B');
    +
    +ok('' =~ $a, 'first identical-source callback regex matches');
    +ok('' =~ $b, 'second identical-source callback regex matches');
    +ok('' =~ $a, 'first callback regex remains reusable');
    +is_deeply(\@seen, [qw(A B A)],
    +    'compiled regex cache never retains another regex callback table');
    +
    +@seen = ();
    +my $prefix = '(?:)';
    +my $wrapped_a = qr/$prefix$a/;
    +my $wrapped_b = qr/$prefix$b/;
    +ok('' =~ $wrapped_a && '' =~ $wrapped_b && '' =~ $wrapped_a,
    +    'identical runtime templates remain reusable');
    +is_deeply(\@seen, [qw(A B A)],
    +    'runtime template recompilation keeps each callback closure table');
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/callback_localized_hash_path.t b/src/test/resources/unit/regex/callback_localized_hash_path.t
    new file mode 100644
    index 0000000000..acfa3ad6fb
    --- /dev/null
    +++ b/src/test/resources/unit/regex/callback_localized_hash_path.t
    @@ -0,0 +1,58 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 15;
    +
    +our ($hash, @seen);
    +$hash->{existing} = 'outer';
    +
    +ok('JohnSmith' =~ /(John)(?{ local $hash->{name} = $^N })
    +                     (Smith)(?{ push @seen, "$hash->{name}:$^N" })/x,
    +   'match with localized hash element succeeds');
    +is_deeply(\@seen, ['John:Smith'],
    +          'a later callback sees a localized element from the same path');
    +ok(!exists $hash->{name}, 'absent hash element is restored after the match');
    +
    +@seen = ();
    +ok('ab' =~ /a(?{ local $hash->{existing} = 'failed' })c
    +             |ab(?{ push @seen, $hash->{existing} })/x,
    +   'backtracking alternative succeeds');
    +is_deeply(\@seen, ['outer'],
    +          'a failed callback path unwinds its localized element');
    +is($hash->{existing}, 'outer', 'existing element is restored after matching');
    +
    +@seen = ();
    +ok('ab' =~ /a(?{ { local $hash->{existing} = 'nested' } })
    +             b(?{ push @seen, $hash->{existing} })/x,
    +   'nested callback block succeeds');
    +is_deeply(\@seen, ['outer'],
    +          'a nested lexical block restores local before the next callback');
    +
    +my ($failed_scalar, $failed_autoviv) = (0, undef);
    +ok('abc' !~ /^a(?{
    +        $failed_scalar = 1;
    +        $failed_autoviv->{value} = 2;
    +    })b$/,
    +   'whole-match failure abandons a plain callback path');
    +is($failed_scalar, 0, 'failed plain callback restores a scalar mutation');
    +ok(!defined $failed_autoviv,
    +   'failed plain callback restores a newly autovivified aggregate');
    +
    +ok('ab' =~ /^a(?{ $failed_scalar = 3 })b$/ && $failed_scalar == 3,
    +   'successful plain callback commits its scalar mutation');
    +
    +my ($exception_scalar, @exception_values) = (0, ());
    +my $error = '';
    +eval {
    +    'a' =~ /a(?{
    +        $exception_scalar = 4;
    +        push @exception_values, 'kept';
    +        die "callback exception\n";
    +    })/;
    +    1;
    +} or $error = $@;
    +like($error, qr/callback exception/,
    +     'plain callback exception crosses the matcher boundary');
    +is($exception_scalar, 4,
    +   'scalar mutation before a callback exception persists');
    +is_deeply(\@exception_values, ['kept'],
    +          'aggregate mutation before a callback exception persists');
    diff --git a/src/test/resources/unit/regex/callback_slot_bytes.t b/src/test/resources/unit/regex/callback_slot_bytes.t
    new file mode 100644
    index 0000000000..7b872eb8cf
    --- /dev/null
    +++ b/src/test/resources/unit/regex/callback_slot_bytes.t
    @@ -0,0 +1,34 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +
    +my @raw = (
    +    ["\x{1e}", 'reserved opening byte'],
    +    ["\x{1e}B0\x{1f}", 'block-slot-shaped bytes'],
    +    ["\x{1e}C12\x{1f}", 'condition-slot-shaped bytes'],
    +    ["\x{1e}D9\x{1f}", 'dynamic-slot-shaped bytes'],
    +    ["\x{1e}\x{1e}", 'doubled reserved opening bytes'],
    +    ["\x{1e}B\x{1f}", 'slot without an id'],
    +    ["\x{1e}X0\x{1f}", 'slot with an unknown kind'],
    +    ["\x{1e}B999", 'slot without a closing byte'],
    +);
    +
    +for my $case (@raw) {
    +    my ($text, $label) = @$case;
    +    ok($text =~ /^$text$/, "$label round-trips without a callback table");
    +
    +    my $calls = 0;
    +    my $pattern = qr/^(?{ ++$calls })$text$/;
    +    ok($text =~ $pattern, "$label round-trips beside a genuine callback");
    +    is($calls, 1, "$label cannot manufacture or suppress a callback");
    +}
    +
    +my $calls = 0;
    +my $slot_start = "\x{1e}";
    +my $slot_tail = "B0\x{1f}";
    +my $split = qr/^(?{ ++$calls })$slot_start$slot_tail$/;
    +ok("\x{1e}B0\x{1f}" =~ $split,
    +    'separate interpolations cannot assemble a trusted slot');
    +is($calls, 1, 'split slot-shaped bytes execute only the genuine callback');
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/callback_token_provenance.t b/src/test/resources/unit/regex/callback_token_provenance.t
    new file mode 100644
    index 0000000000..c5fbfb0277
    --- /dev/null
    +++ b/src/test/resources/unit/regex/callback_token_provenance.t
    @@ -0,0 +1,86 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +
    +our ($genuine, $ordinary, $dynamic);
    +our $raw_call = '(?{=CALL:0})';
    +our $raw_dynamic = '(?{=DYNAMIC:0})';
    +our $raw_ordinary = '(?{ ++$main::ordinary })';
    +our $raw_dynamic_perl = '(??{ ++$main::dynamic; "A" })';
    +
    +sub reset_counts { ($genuine, $ordinary, $dynamic) = (0, 0, 0) }
    +sub counts { [$genuine, $ordinary, $dynamic] }
    +
    +sub rejected_without_re_eval {
    +    my ($label, $operation) = @_;
    +    reset_counts();
    +    my $ok = eval { $operation->(); 1 };
    +    my $error = $@;
    +    ok(!$ok, "$label is rejected without use re eval");
    +    like($error, qr/^Eval-group not allowed at runtime, use re 'eval'/,
    +        "$label reports runtime eval-group authorization diagnostic");
    +    is_deeply(counts(), [0, 0, 0], "$label executes no callback before rejection");
    +}
    +
    +rejected_without_re_eval('raw CALL token beside genuine callback',
    +    sub { "" =~ /(?{ ++$main::genuine })$raw_call/ });
    +rejected_without_re_eval('raw DYNAMIC token beside genuine callback',
    +    sub { "" =~ /(?{ ++$main::genuine })$raw_dynamic/ });
    +rejected_without_re_eval('two raw tokens beside genuine callback',
    +    sub { "" =~ /(?{ ++$main::genuine })$raw_call$raw_dynamic/ });
    +rejected_without_re_eval('ordinary interpolated callback',
    +    sub { "" =~ /(?{ ++$main::genuine })$raw_ordinary/ });
    +rejected_without_re_eval('ordinary interpolated dynamic expression',
    +    sub { "A" =~ /(?{ ++$main::genuine })$raw_dynamic_perl/ });
    +
    +{
    +    use re 'eval';
    +
    +    for my $case (
    +        ['raw CALL token', sub { "" =~ /(?{ ++$main::genuine })$raw_call/ }],
    +        ['raw DYNAMIC token', sub { "" =~ /(?{ ++$main::genuine })$raw_dynamic/ }],
    +    ) {
    +        reset_counts();
    +        my $ok = eval { $case->[1]->(); 1 };
    +        my $error = $@;
    +        ok(!$ok, "$case->[0] remains invalid Perl source with use re eval");
    +        like($error, qr/^syntax error at \(eval \d+\) line 1, near "/,
    +            "$case->[0] reports the Perl source syntax error");
    +        is_deeply(counts(), [0, 0, 0], "$case->[0] executes no callback on compile failure");
    +    }
    +
    +    reset_counts();
    +    my $ok = eval { "" =~ /(?{ ++$main::genuine })$raw_call$raw_dynamic/; 1 };
    +    my $error = $@;
    +    ok(!$ok, 'two raw tokens remain invalid Perl source with use re eval');
    +    my @syntax_errors = $error =~ /^syntax error at \(eval \d+\) line 1, near "/mg;
    +    cmp_ok(scalar @syntax_errors, '>=', 1,
    +        'raw markers retain a Perl source syntax diagnostic');
    +    is_deeply(counts(), [0, 0, 0], 'two raw markers execute no callbacks on compile failure');
    +
    +    reset_counts();
    +    my $matched;
    +    $ok = eval { $matched = "" =~ /(?{ ++$main::genuine })$raw_ordinary/; 1 };
    +    is($@, '', 'ordinary interpolated callback compiles with use re eval');
    +    ok($ok, 'ordinary interpolated callback executes without exception');
    +    ok($matched, 'ordinary interpolated callback pattern matches');
    +    is_deeply(counts(), [1, 1, 0], 'genuine and interpolated callbacks each execute once');
    +
    +    reset_counts();
    +    $ok = eval { $matched = "A" =~ /(?{ ++$main::genuine })$raw_dynamic_perl/; 1 };
    +    is($@, '', 'ordinary interpolated dynamic expression compiles with use re eval');
    +    ok($ok, 'ordinary interpolated dynamic expression executes without exception');
    +    ok($matched, 'ordinary interpolated dynamic expression returns a matching program');
    +    is_deeply(counts(), [1, 0, 1], 'genuine and dynamic callbacks each execute once');
    +
    +    reset_counts();
    +    my $left = '(?{ ++$main::ordinary })';
    +    my $right = '(?{ $main::ordinary += 10 })';
    +    $ok = eval { $matched = "" =~ /(?{ ++$main::genuine })$left$right/; 1 };
    +    is($@, '', 'multiple ordinary callback interpolations compile with use re eval');
    +    ok($ok, 'multiple ordinary callback interpolations execute without exception');
    +    ok($matched, 'multiple ordinary callback interpolations match');
    +    is_deeply(counts(), [1, 11, 0], 'multiple interpolations execute in pattern order');
    +}
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/called_keep_inverted_publication.t b/src/test/resources/unit/regex/called_keep_inverted_publication.t
    new file mode 100644
    index 0000000000..c67d485573
    --- /dev/null
    +++ b/src/test/resources/unit/regex/called_keep_inverted_publication.t
    @@ -0,0 +1,75 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +use threads;
    +
    +for my $pattern (
    +    q{(?=a\K)}, q{(?!a\K)}, q{(?<=a\K)}, q{(?a\K)(?=(?&x))/;
    +my $subject = 'aa';
    +ok($subject =~ $called, 'called KEEP matches inside positive lookahead');
    +ok(!defined($&), 'inverted whole-match text is undef');
    +is($-[0], 2, 'called KEEP preserves the inverted whole-match start');
    +is($+[0], 1, 'called KEEP preserves the lookahead end');
    +is($1, 'a', 'ordinary called-group text remains materialized');
    +is($-[1], 0, 'ordinary called-group start remains valid');
    +is($+[1], 1, 'ordinary called-group end remains valid');
    +
    +my $defined = qr/(?(DEFINE)(?a\K))(?=(?&x))/;
    +$subject = 'a';
    +ok($subject =~ $defined, 'DEFINE called KEEP matches inside positive lookahead');
    +ok(!defined($&), 'DEFINE inverted whole-match text is undef');
    +is($-[0], 1, 'DEFINE called KEEP preserves the inverted start');
    +is($+[0], 0, 'DEFINE lookahead preserves the zero-width end');
    +
    +for my $case (
    +    [ positive_behind => 'a', qr/(?(DEFINE)(?a\K))(?<=(?&x))/, 1, 1 ],
    +    [ negative_ahead  => 'b', qr/(?(DEFINE)(?a\K))(?!(?&x))/,  0, 0 ],
    +    [ negative_behind => 'a', qr/(?(DEFINE)(?a\K))(?create(sub {
    +        for (1 .. 40) {
    +            my $input = 'aa';
    +            return 0 unless $input =~ $called;
    +            return 0 if defined($&);
    +            return 0 unless $-[0] == 2 && $+[0] == 1 && $1 eq 'a';
    +        }
    +        return 1;
    +    })
    +} 1 .. 2;
    +ok($_->join, 'thread reuse keeps inverted match text and offsets isolated')
    +    for @workers;
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/charset_subject_and_xdigit.t b/src/test/resources/unit/regex/charset_subject_and_xdigit.t
    new file mode 100644
    index 0000000000..bdfa7bcff1
    --- /dev/null
    +++ b/src/test/resources/unit/regex/charset_subject_and_xdigit.t
    @@ -0,0 +1,19 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 10;
    +
    +my $nbsp = chr 0xA0;
    +ok($nbsp !~ qr/(?d:\s)/, 'byte NBSP is not whitespace under /d');
    +ok($nbsp =~ qr/(?d:\S)/, 'byte NBSP is non-whitespace under /d');
    +ok($nbsp !~ qr/(?d:[_[:space:]])/, 'byte NBSP is not POSIX space under /d');
    +ok($nbsp =~ qr/(?d:[_[:^space:]])/, 'byte NBSP is POSIX non-space under /d');
    +
    +utf8::upgrade($nbsp);
    +ok($nbsp =~ qr/(?d:\s)/, 'upgraded NBSP is whitespace under /d');
    +ok($nbsp =~ qr/(?d:[_[:space:]])/, 'upgraded NBSP is POSIX space under /d');
    +
    +my $fullwidth_five = chr 0xFF15;
    +ok($fullwidth_five =~ qr/(?d:[_[:xdigit:]])/, 'fullwidth digit is POSIX xdigit under /d');
    +ok($fullwidth_five !~ qr/(?d:[_[:^xdigit:]])/, 'fullwidth digit is not POSIX non-xdigit under /d');
    +ok($fullwidth_five =~ qr/(?u:[_[:xdigit:]])/, 'fullwidth digit is POSIX xdigit under /u');
    +ok($fullwidth_five !~ qr/(?u:[_[:^xdigit:]])/, 'fullwidth digit is not POSIX non-xdigit under /u');
    diff --git a/src/test/resources/unit/regex/conditional_not_terminated_diagnostic.t b/src/test/resources/unit/regex/conditional_not_terminated_diagnostic.t
    new file mode 100644
    index 0000000000..313b28f43c
    --- /dev/null
    +++ b/src/test/resources/unit/regex/conditional_not_terminated_diagnostic.t
    @@ -0,0 +1,7 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 1;
    +
    +my $compiled = eval q{ qr/(?(1)x/; 1 };
    +like($@, qr/^Switch \(\?\(condition\)\.\.\. not terminated in regex; marked by <-- HERE in m\/\(\?\(1\)x <-- HERE \/ at /,
    +     'unterminated conditional uses the Perl diagnostic');
    diff --git a/src/test/resources/unit/regex/control_verb_diagnostic.t b/src/test/resources/unit/regex/control_verb_diagnostic.t
    new file mode 100644
    index 0000000000..7eb2186ecd
    --- /dev/null
    +++ b/src/test/resources/unit/regex/control_verb_diagnostic.t
    @@ -0,0 +1,13 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 4;
    +
    +for my $case (
    +    [q{qr/(*DOOF)/}, q{Unknown verb pattern 'DOOF'}],
    +    [q{qr/(*script_runfoo)/}, q{Unknown '(*...)' construct 'script_runfoo'}],
    +    [q{qr/(*script_run)/}, q{'(*script_run' requires a terminating ':'}],
    +    [q{qr/(*sr)/}, q{'(*sr' requires a terminating ':'}],
    +) {
    +    my $compiled = eval "$case->[0]; 1";
    +    ok(!$compiled && index($@, $case->[1]) >= 0, 'control verb uses Perl diagnostic');
    +}
    diff --git a/src/test/resources/unit/regex/dynamic_code_array_state_matrix.t b/src/test/resources/unit/regex/dynamic_code_array_state_matrix.t
    new file mode 100644
    index 0000000000..f891de327a
    --- /dev/null
    +++ b/src/test/resources/unit/regex/dynamic_code_array_state_matrix.t
    @@ -0,0 +1,147 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +use Tie::Array;
    +use re 'eval';
    +
    +{
    +    package DynamicCodeArrayStateMatrix::TiedScalar;
    +    our $fetches = 0;
    +    sub TIESCALAR { bless [undef], __PACKAGE__ }
    +    sub STORE { $_[0][0] = $_[1] }
    +    sub FETCH { ++$fetches; $_[0][0] }
    +}
    +
    +my @array;
    +our @global;
    +my @refs = (0, \@array, 2);
    +tie my @tied, 'Tie::StdArray';
    +{
    +    my $bb = 'B';
    +    my $dd = 'D';
    +    @array = ('A', qr/(??{$bb})/, 'C', qr/(??{$dd})/, 'E');
    +    @global = @array;
    +    @tied = @array;
    +}
    +
    +like('A B C D E', qr/^@array$/, 'lexical array preserves executable qr elements');
    +like('A B C D E', qr/^@global$/, 'package array preserves executable qr elements');
    +like('A B C D E', qr/^@{$refs[1]}$/, 'array reference preserves executable qr elements');
    +like('A B C D E', qr/^@tied$/, 'tied array preserves executable qr elements');
    +
    +{
    +    local $" = '-';
    +    like('A-B-C-D-E', qr/^@array$/,
    +        'localized separator composes lexical executable elements');
    +    like('A-B-C-D-E', qr/^@tied$/,
    +        'localized separator composes tied executable elements');
    +}
    +
    +{
    +    my $leaf = 'Z';
    +    my $inner = qr/(??{$leaf})/;
    +    my $nested = qr/(??{$inner})/;
    +    my @nested = ('N', $nested, 'X');
    +    like('N Z X', qr/^@nested$/,
    +        'array element can return a second executable qr');
    +    $leaf = 'Q';
    +    like('N Q X', qr/^@nested$/,
    +        'nested executable array element retains its lexical cell');
    +}
    +
    +{
    +    my @mutations;
    +    my $branch = qr/(?{ push @mutations, 'failed' })b/;
    +    my @parts = ($branch);
    +    ok('ac' =~ /^(?:a@parts|a(?{ push @mutations, 'kept' })c)$/,
    +        'failed executable array branch backtracks to a later alternative');
    +    is_deeply(\@mutations, ['failed', 'kept'],
    +        'interpolated qr callback mutation survives branch backtracking');
    +}
    +
    +{
    +    my $message = 'array callback exploded';
    +    my @bad = (qr/(??{ die $message })/);
    +    my $error = '';
    +    eval { 'x' =~ /^@bad$/ };
    +    $error = $@;
    +    like($error, qr/array callback exploded/,
    +        'exception from executable array element propagates');
    +
    +    my $value = 'x';
    +    my @good = (qr/(??{$value})/);
    +    like('x', qr/^@good$/,
    +        'a later executable array remains usable after an exception');
    +}
    +
    +{
    +    my $token = '[a-z]';
    +    my @parts = (qr/(??{$token})/);
    +    my $subject = 'a1b';
    +    my @seen;
    +    push @seen, $& while $subject =~ /@parts/g;
    +    is(join('', @seen), 'ab', '/g reuses executable array source');
    +
    +    pos($subject) = 1;
    +    ok(!($subject =~ /\G@parts/gc), '/gc executable array can fail at pos');
    +    is(pos($subject), 1, '/c preserves pos after executable array failure');
    +    $token = '1';
    +    ok($subject =~ /\G@parts/gc && $& eq '1',
    +        '/gc executable array reuses its callback at preserved pos');
    +}
    +
    +{
    +    my $value = 'a';
    +    my @parts = (qr/(??{$value})/);
    +    sub match_once_array { $_[0] =~ /^@parts$/o }
    +
    +    ok(match_once_array('a'), '/o compiles the executable array once');
    +    $value = 'b';
    +    @parts = (qr/c/);
    +    ok(match_once_array('b'), '/o retains the original callback lexical cell');
    +    ok(!match_once_array('c'), '/o does not replace the original array template');
    +}
    +
    +{
    +    my $value = 'T';
    +    tie my $slot, 'DynamicCodeArrayStateMatrix::TiedScalar';
    +    $slot = qr/(??{$value})/;
    +    $DynamicCodeArrayStateMatrix::TiedScalar::fetches = 0;
    +    like('T', qr/^$slot$/, 'tied scalar can supply an executable qr');
    +    is($DynamicCodeArrayStateMatrix::TiedScalar::fetches, 1,
    +        'tied executable scalar is fetched exactly once');
    +}
    +
    +{
    +    my $trusted = 'Q';
    +    my $runtime = 'R';
    +    my @mixed = ('L', qr/(??{$trusted})/, '(??{$runtime})');
    +    like('L Q R', qr/^@mixed$/,
    +        'array composes trusted qr and runtime callback source');
    +    $trusted = 'S';
    +    $runtime = 'T';
    +    like('L S T', qr/^@mixed$/,
    +        'mixed array source retains both lexical cells');
    +
    +    tie my @mixed_tied, 'Tie::StdArray';
    +    @mixed_tied = @mixed;
    +    local $" = '-';
    +    like('L-S-T', qr/^@mixed_tied$/,
    +        'tied mixed array composes under a localized separator');
    +}
    +
    +{
    +    my @invalid = ('(?{ this is not perl })');
    +    my $error = '';
    +    eval { qr/@invalid/ };
    +    $error = $@;
    +    like($error, qr/syntax error|Bareword/,
    +        'invalid runtime source reports a compilation exception');
    +
    +    my $value = 'recovered';
    +    my @valid = ('(??{$value})');
    +    like('recovered', qr/^@valid$/,
    +        'runtime source compiler recovers after a compilation exception');
    +}
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/dynamic_conditional_source_diagnostic.t b/src/test/resources/unit/regex/dynamic_conditional_source_diagnostic.t
    new file mode 100644
    index 0000000000..9e198aa45a
    --- /dev/null
    +++ b/src/test/resources/unit/regex/dynamic_conditional_source_diagnostic.t
    @@ -0,0 +1,17 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +
    +for my $source (
    +    q{use re 'eval'; qr/(?(??{}))/},
    +    q{use re 'strict'; use re 'eval'; qr/(?(??{}))/},
    +) {
    +    my $compiled = eval $source;
    +    ok(!$compiled, 'dynamic regex code is invalid as a conditional operand');
    +    like($@, qr/^Unknown switch condition \(\?\(\.\.\.\)\) in regex;/,
    +        'reports the conditional diagnostic');
    +    like($@, qr/m\/\(\?\(\? <-- HERE \?\{\}\)\)\//,
    +        'retains and marks the original dynamic callback spelling');
    +}
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/dynamic_overload_code_array.t b/src/test/resources/unit/regex/dynamic_overload_code_array.t
    new file mode 100644
    index 0000000000..b736516726
    --- /dev/null
    +++ b/src/test/resources/unit/regex/dynamic_overload_code_array.t
    @@ -0,0 +1,77 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +
    +{
    +local $" = '-';
    +
    +my $A = 'A';
    +my $B = 'B';
    +my $C = 'C';
    +my $E = 'E';
    +my $a = 'aa';
    +my $b = 'bb';
    +my $e = 'ee';
    +my @r = (qr/(??{$B})/);
    +
    +{
    +    my $B = 'Q';
    +    push @r, qr/(??{$B})/;
    +}
    +
    +{
    +    package Local::LcConcat;
    +    use overload
    +        '""' => sub { ${$_[0]} },
    +        '.' => sub {
    +            my ($x, $y) = @_[ $_[2] ? (1, 0) : (0, 1) ];
    +            my ($xx, $yy) = ("$x", "$y");
    +            lc("$xx=$yy");
    +        };
    +}
    +
    +my $r = qr/(??{$E})/;
    +bless $r, 'Local::LcConcat';
    +
    +use re 'eval';
    +
    +like('=ee', qr/^$r$/, 'overloaded scalar keeps executable qr source');
    +{
    +    no re 'eval';
    +    eval q{ my $x = qr/^$r$/; 1 };
    +    like($@, qr/Eval-group not allowed/,
    +        'overloaded scalar runtime source still requires re eval');
    +}
    +like('aa=ee', qr/^(??{$A})$r$/, 'literal callback precedes overloaded scalar');
    +like('xaa=ee', qr/^X(??{$A})$r$/, 'literal prefix precedes overloaded scalar');
    +my $pattern = qr/^X(??{$A})$r(??{$C})$/;
    +like('xaa=eeC', $pattern, 'callbacks surround overloaded scalar');
    +unlike('', $pattern, 'surrounded overloaded scalar rejects empty subject');
    +unlike('XA=EC', $pattern, 'surrounded overloaded scalar preserves case transform');
    +
    +push @r, $r;
    +
    +like('bb-bb-=ee', qr/^@r$/, 'array carries overloaded executable scalar');
    +{
    +    no re 'eval';
    +    eval q{ my $x = qr/^@r$/; 1 };
    +    like($@, qr/Eval-group not allowed/,
    +        'overloaded array runtime source still requires re eval');
    +}
    +SKIP: {
    +    skip 'overloaded executable array interpolation requires Perl 5.44', 3
    +        if $^V lt v5.44;
    +    like('aabb-bb-=ee', qr/^(??{$A})@r$/,
    +        'literal callback precedes overloaded array');
    +    like('xaabb-bb-=ee', qr/^X(??{$A})@r$/,
    +        'literal prefix precedes overloaded array');
    +    $pattern = qr/^X(??{$A})@r(??{$C})$/;
    +    like('xaabb-bb-=eeC', $pattern, 'callbacks surround overloaded array');
    +}
    +$pattern = qr/^X(??{$A})@r(??{$C})$/;
    +unlike('', $pattern, 'surrounded overloaded array rejects empty subject');
    +unlike('XAB-B-=EC', $pattern,
    +    'surrounded overloaded array preserves separator and case transform');
    +}
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/dynamic_overload_lexical_tracking.t b/src/test/resources/unit/regex/dynamic_overload_lexical_tracking.t
    new file mode 100644
    index 0000000000..76a9705480
    --- /dev/null
    +++ b/src/test/resources/unit/regex/dynamic_overload_lexical_tracking.t
    @@ -0,0 +1,35 @@
    +use strict;
    +use warnings;
    +no strict 'refs';
    +
    +print "1..2\n";
    +
    +sub report {
    +    my ($ok, $name) = @_;
    +    print($ok ? "ok" : "not ok", " - $name\n");
    +}
    +
    +sub run_case {
    +    my $E = 'E';
    +    my $e = 'ee';
    +
    +    {
    +        package Local::RuntimeRegexNoTestMore;
    +        use overload
    +            '""' => sub { ${$_[0]} },
    +            '.' => sub {
    +                my ($x, $y) = @_[ $_[2] ? (1, 0) : (0, 1) ];
    +                my ($xx, $yy) = ("$x", "$y");
    +                lc("$xx=$yy");
    +            };
    +    }
    +
    +    my $r = qr/(??{$E})/;
    +    bless $r, 'Local::RuntimeRegexNoTestMore';
    +    use re 'eval';
    +    report('=ee' =~ qr/^$r$/, 'runtime source sees containing lexical');
    +    report('aa=ee' =~ qr/^(??{'aa'})$r$/,
    +        'literal callback and overloaded source compose');
    +}
    +
    +run_case();
    diff --git a/src/test/resources/unit/regex/dynamic_result_warning_scope.t b/src/test/resources/unit/regex/dynamic_result_warning_scope.t
    new file mode 100644
    index 0000000000..12607923ba
    --- /dev/null
    +++ b/src/test/resources/unit/regex/dynamic_result_warning_scope.t
    @@ -0,0 +1,46 @@
    +use strict;
    +use warnings;
    +use re 'eval';
    +
    +print "1..4\n";
    +
    +{
    +    no warnings 'uninitialized';
    +    my @warnings;
    +    local $SIG{__WARN__} = sub { push @warnings, shift };
    +    my $ok = eval { 'x' =~ /(??{})/; 1 };
    +    print $ok && !@warnings
    +        ? "ok 1 - dynamic undef result honors lexical no warnings\n"
    +        : "not ok 1 - dynamic undef result honors lexical no warnings: $@ @warnings\n";
    +}
    +
    +{
    +    use warnings NONFATAL => 'uninitialized';
    +    my @warnings;
    +    local $SIG{__WARN__} = sub { push @warnings, shift };
    +    'x' =~ /(??{})/;
    +    print grep(/uninitialized value/i, @warnings)
    +        ? "ok 2 - dynamic undef result emits enabled warning\n"
    +        : "not ok 2 - dynamic undef result emits enabled warning\n";
    +}
    +
    +{
    +    use warnings FATAL => 'uninitialized';
    +    eval { 'x' =~ /(??{})/ };
    +    print $@ =~ /uninitialized value/i
    +        ? "ok 3 - dynamic undef result honors lexical fatal warning\n"
    +        : "not ok 3 - dynamic undef result honors lexical fatal warning: $@\n";
    +}
    +
    +{
    +    use warnings FATAL => 'uninitialized';
    +    my ($ok, @warnings);
    +    {
    +        no warnings 'uninitialized';
    +        local $SIG{__WARN__} = sub { push @warnings, shift };
    +        $ok = eval q{ use re 'eval'; 'x' =~ /(??{})/; 1 };
    +    }
    +    print $ok && !@warnings
    +        ? "ok 4 - eval STRING preserves disabled callback warning scope\n"
    +        : "not ok 4 - eval STRING preserves disabled callback warning scope: $@ @warnings\n";
    +}
    diff --git a/src/test/resources/unit/regex/dynamic_source_boundaries.t b/src/test/resources/unit/regex/dynamic_source_boundaries.t
    new file mode 100644
    index 0000000000..2a930b2637
    --- /dev/null
    +++ b/src/test/resources/unit/regex/dynamic_source_boundaries.t
    @@ -0,0 +1,57 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +
    +{
    +    use re 'eval';
    +
    +    ok('x' =~ /(??{})/,
    +        'an undefined dynamic pattern result is an empty pattern');
    +
    +    my $subject = 'snofooefoofoowaa';
    +    ok($subject =~ /(?foo)(??{ $+{n} })/,
    +        'dynamic source can use a named capture from its prefix');
    +    is($+{n}, 'foo', 'dynamic named-capture source preserves the capture value');
    +
    +    ok($subject =~ /(?Pfoo)(??{ $+{n} })/,
    +        'dynamic source accepts Python-style named capture syntax');
    +    is($+{n}, 'foo', 'Python-style named capture feeds dynamic source');
    +
    +    ok($subject =~ /(?'n'foo)(??{ $+{n} })/,
    +        'dynamic source accepts apostrophe named capture syntax');
    +    is($+{n}, 'foo', 'apostrophe named capture feeds dynamic source');
    +
    +}
    +
    +my @literal_patterns = (
    +    [q|(?#( (?{1+)a|,       'a',       'comment text is not executable source'],
    +    [q|ab[(?{1]|,            'ab1',     'character-class text is not executable source'],
    +    [q|ab[(?{1\](?{2]|,     'ab2',     'escaped class close keeps text non-executable'],
    +    [q|ab[c\](??{"]d|,     'abcd',    'class text after an escaped bracket is non-executable'],
    +);
    +
    +ok('a' =~ m'(?#( (?{1+)a',
    +    'apostrophe-delimited comment text stays inside the regex literal');
    +ok('a' =~ m'a# (?{1+'x,
    +    'extended-mode line comments hide callback-looking text');
    +ok('ab1' =~ m'ab[(?{1]',
    +    'character-class callback-looking text stays inside the regex literal');
    +ok('ab2' =~ m'ab[(?{1\](?{2]',
    +    'escaped class close keeps callback-looking text inside the class');
    +ok("ab\\;c" =~ m'ab\\[(??{1;})]c',
    +    'apostrophe delimiter handles callback-looking text after a literal bracket');
    +ok('abcd' =~ m'ab[c\](??{"]d',
    +    'apostrophe delimiter handles callback-looking text after an escaped bracket');
    +
    +{
    +    use re 'eval';
    +
    +    for my $case (@literal_patterns) {
    +        my ($pattern, $subject, $description) = @{$case};
    +        my $regex = eval { qr/$pattern/ };
    +        ok(defined($regex) && $subject =~ $regex, $description)
    +            or diag($@);
    +    }
    +}
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/dynamic_trailing_backslash_diagnostics.t b/src/test/resources/unit/regex/dynamic_trailing_backslash_diagnostics.t
    new file mode 100644
    index 0000000000..11cf6b46bd
    --- /dev/null
    +++ b/src/test/resources/unit/regex/dynamic_trailing_backslash_diagnostics.t
    @@ -0,0 +1,20 @@
    +use strict;
    +use warnings;
    +use utf8;
    +use Test::More;
    +
    +for my $pattern ('\\', "ネ\\") {
    +    eval { qr/$pattern/ };
    +    my $error = $@;
    +    $error =~ s/ at \Q${\__FILE__}\E line \d+\.\n\z//;
    +    is($error, "Trailing \\ in regex m/$pattern/",
    +        'dynamic trailing backslash uses the Perl diagnostic');
    +}
    +
    +my $valid = '\\\\';
    +my $regex = eval { qr/$valid/ };
    +ok(defined($regex), 'paired trailing backslashes remain valid');
    +is($@, '', 'valid paired backslashes do not report a compile error');
    +ok("\\" =~ $regex, 'valid paired backslashes retain match semantics');
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/dynamic_user_property_cache_context.t b/src/test/resources/unit/regex/dynamic_user_property_cache_context.t
    new file mode 100644
    index 0000000000..65a3304f2c
    --- /dev/null
    +++ b/src/test/resources/unit/regex/dynamic_user_property_cache_context.t
    @@ -0,0 +1,113 @@
    +use strict;
    +use warnings;
    +use v5.16;
    +use utf8;
    +use charnames ':full';
    +use re 'eval';
    +use Test::More;
    +use lib 'src/test/resources/unit/lib';
    +
    +our ($forward, $forward_negative, $mode_sensitive, $mode_folded, $retry_boom,
    +    $with_callout, $callout_count, $stateful_charname, $gc_runner);
    +our ($order_im, $order_mi);
    +{
    +    use Phase36Cname;
    +    BEGIN {
    +        $Phase36Cname::Evil = 'A';
    +        $stateful_charname = eval q{qr/^\N{EVIL}\p{InCacheKana}$/};
    +        die $@ if $@;
    +    }
    +}
    +BEGIN {
    +    $forward = qr/\p{InCacheKana}/;
    +    $forward_negative = qr/\P{InCacheKana}/;
    +    $mode_sensitive = qr/\p{InCacheMode}/;
    +    $mode_folded = qr/\p{InCacheMode}/i;
    +    $retry_boom = qr/\p{InCacheRetryBoom}/;
    +    $with_callout = qr/(?{ ++$main::callout_count })\p{InCacheKana}/;
    +    $order_im = qr/\p{InCacheOrder}/im;
    +    $order_mi = qr/\p{InCacheOrder}/mi;
    +    $gc_runner = eval q{sub {
    +        my $subject = "\x{3040}x";
    +        pos($subject) = 0;
    +        my @events;
    +        for (1 .. 2) {
    +            my $matched = $subject =~ /\p{InCacheGc}/gc ? 1 : 0;
    +            push @events, $matched, pos($subject);
    +        }
    +        return \@events;
    +    }};
    +    die $@ if $@;
    +}
    +
    +sub InCacheKana { "3040\t309f\n30a0\t30ff\n" }
    +sub InCacheMode { $_[0] ? "0200\n" : "0100\n" }
    +sub InCacheRetryBoom { die "cache retry boom\n" }
    +sub InCacheGc { "3040\n" }
    +sub InCacheOrder { "0500\n" }
    +sub CacheFixture::InScoped { "0400\n" }
    +
    +is($Phase36Cname::Evil, 'AB',
    +    'custom charname translator runs once during initial construction');
    +ok("A\x{3040}" =~ $stateful_charname,
    +    'deferred recompilation preserves the original named expansion');
    +is($Phase36Cname::Evil, 'AB',
    +    'deferred recompilation does not rerun the custom charname translator');
    +
    +ok("\x{3040}" =~ $forward, 'forward-deferred property resolves at first use');
    +ok("\x{303f}" =~ $forward_negative, 'forward-deferred complement resolves at first use');
    +
    +my $fresh_positive = eval q{qr/\p{InCacheKana}/};
    +is($@, '', 'fresh positive property compiles after deferred resolution');
    +ok("\x{3040}" =~ $fresh_positive, 'fresh positive property uses resolved cache');
    +ok("\x{303f}" !~ $fresh_positive, 'fresh positive property does not reuse placeholder');
    +
    +my $fresh_negative = eval q{qr/\P{InCacheKana}/};
    +is($@, '', 'fresh negative property compiles after deferred resolution');
    +ok("\x{303f}" =~ $fresh_negative, 'fresh negative property uses resolved cache');
    +ok("\x{3040}" !~ $fresh_negative, 'fresh negative property excludes resolved member');
    +
    +ok("\x{0100}" =~ $mode_sensitive, 'sensitive callback mode keeps its own cache entry');
    +ok("\x{0200}" !~ $mode_sensitive, 'sensitive callback mode excludes folded-only member');
    +ok("\x{0200}" =~ $mode_folded, 'folded callback mode keeps its own cache entry');
    +ok("\x{0100}" !~ $mode_folded, 'folded callback mode excludes sensitive-only member');
    +
    +my $qualified = eval q{qr/\p{CacheFixture::InScoped}/};
    +is($@, '', 'qualified user property compiles');
    +ok("\x{0400}" =~ $qualified, 'qualified user property matches its member');
    +ok("\x{0401}" !~ $qualified, 'qualified user property excludes adjacent scalar');
    +
    +my @patterns = ($fresh_positive, $fresh_negative, $qualified);
    +sub nested_match { $_[0] =~ $_[1] }
    +ok(nested_match("\x{3040}", $patterns[0]), 'array-held regex survives nested call');
    +ok(nested_match("\x{303f}", $patterns[1]), 'array-held complement survives nested call');
    +
    +my $global = "\x{3040}\x{3041}";
    +my @global_matches = $global =~ /($fresh_positive)/g;
    +is_deeply(\@global_matches, ["\x{3040}", "\x{3041}"],
    +    'global matching reuses resolved compiled property');
    +
    +$callout_count = 0;
    +ok("\x{3040}" =~ $with_callout,
    +    'deferred property recompilation preserves executable callouts');
    +is($callout_count, 1, 'preserved callout executes exactly once');
    +
    +is_deeply($gc_runner->(), [1, 1, 0, 1],
    +    'deferred literal global match preserves pos after gc failure');
    +
    +ok("\x{0500}" =~ $order_im,
    +    'first raw modifier order resolves without another placeholder cache hit');
    +ok("\x{0501}" !~ $order_im,
    +    'first raw modifier order preserves nonmembership');
    +ok("\x{0500}" =~ $order_mi,
    +    'equivalent second modifier order resolves independently');
    +ok("\x{0501}" !~ $order_mi,
    +    'equivalent second modifier order preserves nonmembership');
    +
    +for my $attempt (1 .. 2) {
    +    my $matched = eval { "A" =~ $retry_boom; 1 };
    +    ok(!$matched, "failed deferred callback remains fatal on attempt $attempt");
    +    like($@, qr/cache retry boom/, "failed deferred callback error repeats on attempt $attempt");
    +}
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/dynamic_user_property_cache_context_threads.t b/src/test/resources/unit/regex/dynamic_user_property_cache_context_threads.t
    new file mode 100644
    index 0000000000..985ead6bab
    --- /dev/null
    +++ b/src/test/resources/unit/regex/dynamic_user_property_cache_context_threads.t
    @@ -0,0 +1,30 @@
    +use strict;
    +use warnings;
    +use v5.16;
    +use utf8;
    +use charnames ':full';
    +use threads;
    +use Test::More;
    +
    +our $forward;
    +BEGIN { $forward = qr/\p{InThreadCacheKana}/ }
    +sub InThreadCacheKana { "3040\t309f\n30a0\t30ff\n" }
    +
    +my $result = threads->create(sub {
    +    my $initial_member = "\x{3040}" =~ $forward ? 1 : 0;
    +    my $fresh = eval q{qr/\p{InThreadCacheKana}/};
    +    return [
    +        $initial_member,
    +        $@,
    +        "\x{3040}" =~ $fresh ? 1 : 0,
    +        "\x{303f}" =~ $fresh ? 1 : 0,
    +    ];
    +})->join;
    +
    +is_deeply(
    +    $result,
    +    [1, '', 1, 0],
    +    'thread clone preserves deferred property compilation context and cache safety',
    +);
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/empty_control_verb_diagnostics.t b/src/test/resources/unit/regex/empty_control_verb_diagnostics.t
    new file mode 100644
    index 0000000000..975563409d
    --- /dev/null
    +++ b/src/test/resources/unit/regex/empty_control_verb_diagnostics.t
    @@ -0,0 +1,10 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 4;
    +
    +for my $pattern ('(*)', '(*)b') {
    +    my $ok = eval "qr/$pattern/; 1";
    +    ok(!$ok, "$pattern is rejected");
    +    ok(index($@, "Unknown verb pattern ''") >= 0,
    +        "$pattern reports an empty verb pattern");
    +}
    diff --git a/src/test/resources/unit/regex/equivalent_range_warning.t b/src/test/resources/unit/regex/equivalent_range_warning.t
    new file mode 100644
    index 0000000000..6d831e5a19
    --- /dev/null
    +++ b/src/test/resources/unit/regex/equivalent_range_warning.t
    @@ -0,0 +1,26 @@
    +use strict;
    +use warnings;
    +no warnings 'experimental::regex_sets';
    +use Test::More tests => 6;
    +
    +sub compile_with_warnings {
    +    my ($source) = @_;
    +    my @warnings;
    +    local $SIG{__WARN__} = sub { push @warnings, @_ };
    +    eval $source;
    +    return ($@, @warnings);
    +}
    +
    +my ($error, @warnings) = compile_with_warnings(q{qr/(?[[ : - \x3A ] ])/});
    +is($error, '', 'equivalent colon range compiles');
    +is(scalar @warnings, 1, 'equivalent colon range warns once');
    +like($warnings[0], qr/^": - \\x3A " is more clearly written simply as ":"/,
    +    'colon warning preserves both endpoint spellings');
    +
    +($error, @warnings) = compile_with_warnings(q{qr/(?[[ \t - \x09 ] ])/});
    +is($error, '', 'equivalent tab range compiles');
    +like($warnings[0], qr/^"\\t - \\x09 " is more clearly written simply as "\\t"/,
    +    'tab warning uses the canonical escape');
    +
    +($error, @warnings) = compile_with_warnings(q{qr/(?[[ % - % ] ])/});
    +is_deeply(\@warnings, [], 'identically spelled endpoints do not warn');
    diff --git a/src/test/resources/unit/regex/extended_class_missing_operator_diagnostics.t b/src/test/resources/unit/regex/extended_class_missing_operator_diagnostics.t
    new file mode 100644
    index 0000000000..9ea3e70cc0
    --- /dev/null
    +++ b/src/test/resources/unit/regex/extended_class_missing_operator_diagnostics.t
    @@ -0,0 +1,15 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 3;
    +
    +no warnings 'experimental::regex_sets';
    +
    +for my $case (
    +    [ q{qr/(?[ \cK \t ])/}, 'Operand with no preceding operator' ],
    +    [ q{qr/(?[ \cK ( \t ) ])/}, q{Unexpected '(' with no preceding operator} ],
    +    [ q{qr/(?[ \cK + ) ])/}, q{Unexpected ')'} ],
    +) {
    +    my ($expression, $expected) = @$case;
    +    my $compiled = eval "$expression; 1";
    +    ok(!$compiled && index($@, $expected) >= 0, $expected);
    +}
    diff --git a/src/test/resources/unit/regex/extended_class_operator_diagnostic.t b/src/test/resources/unit/regex/extended_class_operator_diagnostic.t
    new file mode 100644
    index 0000000000..693e5fed7c
    --- /dev/null
    +++ b/src/test/resources/unit/regex/extended_class_operator_diagnostic.t
    @@ -0,0 +1,8 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 1;
    +
    +no warnings 'experimental::regex_sets';
    +my $compiled = eval q{ qr/(?[ + \t ])/; 1 };
    +ok(!$compiled && $@ =~ /Unexpected binary operator '\+' with no preceding operand/,
    +   'extended-class binary operator without an operand uses the Perl diagnostic');
    diff --git a/src/test/resources/unit/regex/extended_empty_posix_leaf.t b/src/test/resources/unit/regex/extended_empty_posix_leaf.t
    new file mode 100644
    index 0000000000..1006b0af98
    --- /dev/null
    +++ b/src/test/resources/unit/regex/extended_empty_posix_leaf.t
    @@ -0,0 +1,19 @@
    +use strict;
    +use warnings;
    +no warnings 'experimental::regex_sets';
    +no warnings qw(syntax regexp);
    +use Test::More tests => 12;
    +
    +like(':', qr/(?[ [:] ])/, 'empty POSIX-looking leaf is an ordinary class');
    +unlike('a', qr/(?[ [:] ])/, 'empty POSIX-looking leaf contains only colon');
    +like('a', qr/(?[ (?# comment) [a] ])/, 'parenthesized comment is ignored');
    +unlike('b', qr/(?[ (?# comment) [a] ])/, 'comment contributes no members');
    +
    +like(chr(ord('#') ^ 64), qr/(?[\c#])/, '\\c# matches its control character');
    +unlike('x', qr/(?[\c#])/, '\\c# excludes an ordinary character');
    +like("\c[", qr/(?[\c[])/, '\\c[ matches its control character');
    +unlike('x', qr/(?[\c[])/, '\\c[ excludes an ordinary character');
    +like("\c\\", qr/(?[\c\])/, '\\c\\ matches its control character');
    +unlike('x', qr/(?[\c\])/, '\\c\\ excludes an ordinary character');
    +like("\c]", qr/(?[\c]])/, '\\c] matches its control character');
    +unlike('x', qr/(?[\c]])/, '\\c] excludes an ordinary character');
    diff --git a/src/test/resources/unit/regex/extended_scoped_interpolation.t b/src/test/resources/unit/regex/extended_scoped_interpolation.t
    new file mode 100644
    index 0000000000..7d71311d81
    --- /dev/null
    +++ b/src/test/resources/unit/regex/extended_scoped_interpolation.t
    @@ -0,0 +1,33 @@
    +use strict;
    +use warnings;
    +no warnings 'experimental::regex_sets';
    +use Test::More tests => 14;
    +
    +my @positive = (
    +    [ q{(?[ (?^:(?[ [x] ])) ])}, 'one scoped wrapper' ],
    +    [ q{(?[ (?^:(?x:(?[ [x] ]))) ])}, 'two scoped wrappers' ],
    +    [ q{(?[ (?^:(?x:(?i:(?[ [x] ])))) ])}, 'three scoped wrappers' ],
    +);
    +
    +for my $case (@positive) {
    +    my ($pattern, $name) = @$case;
    +    my $regex = eval "qr/$pattern/";
    +    is($@, '', "$name compiles");
    +    like('x', $regex, "$name matches its member");
    +    unlike('y', $regex, "$name excludes a nonmember");
    +}
    +
    +my $restored = qr/(?[ (?^:(?i:(?[ [a] ]))) - [A] ])/;
    +like('a', $restored, 'nested ignore-case contributes lowercase member');
    +unlike('A', $restored,
    +        'nested ignore-case scope is restored before subtraction');
    +
    +for my $pattern (
    +    q{(?[ (?^:(?x:[x])) ])},
    +    q{(?[ (?^:(?x:([x]))) ])},
    +    q{(?[ (?^:(?x:(?i:[x]))) ])},
    +) {
    +    my $ok = eval "qr/$pattern/; 1";
    +    ok(!$ok && $@ =~ /Expecting interpolated extended charclass/,
    +        'nested scoped chain still requires an extended-class leaf');
    +}
    diff --git a/src/test/resources/unit/regex/extended_set_failure_precedence.t b/src/test/resources/unit/regex/extended_set_failure_precedence.t
    new file mode 100644
    index 0000000000..395dd755c4
    --- /dev/null
    +++ b/src/test/resources/unit/regex/extended_set_failure_precedence.t
    @@ -0,0 +1,23 @@
    +use strict;
    +use warnings;
    +no warnings 'experimental::regex_sets';
    +use Test::More tests => 4;
    +
    +sub compile_error {
    +    my ($source) = @_;
    +    eval { qr/$source/ };
    +    return $@;
    +}
    +
    +my @cases = (
    +    ['/(?[(\\c]) /', qr/^Syntax error in \(\?\[\.\.\.\]\) in regex/],
    +    ['(?[(\\c])', qr/^Syntax error in \(\?\[\.\.\.\]\) in regex/],
    +    ['(?[ ! ! (\\w])', qr/^Unmatched \( in regex/],
    +    ['(?[ ! ( ! (\\w)])', qr/^Unmatched \( in regex/],
    +);
    +
    +for my $case (@cases) {
    +    my ($source, $expected) = @$case;
    +    like(compile_error($source), $expected,
    +        "$source preserves extended-set failure precedence");
    +}
    diff --git a/src/test/resources/unit/regex/false_class_range_diagnostics.t b/src/test/resources/unit/regex/false_class_range_diagnostics.t
    new file mode 100644
    index 0000000000..da33978656
    --- /dev/null
    +++ b/src/test/resources/unit/regex/false_class_range_diagnostics.t
    @@ -0,0 +1,16 @@
    +use strict;
    +use warnings;
    +no warnings 'experimental::regex_sets';
    +use Test::More tests => 4;
    +
    +for my $case (
    +    [ '(?[[a-\d]])',  'a-\d'  ],
    +    [ '(?[[\w-x]])',  '\w-'    ],
    +    [ '(?[[a-\pM]])', 'a-\pM' ],
    +    [ '(?[[\pM-x]])', '\pM-'   ],
    +) {
    +    my ($pattern, $range) = @$case;
    +    eval "qr/$pattern/";
    +    like($@, qr/^False \[\] range "\Q$range\E" in regex; marked by <-- HERE/,
    +        "$pattern reports its false class range");
    +}
    diff --git a/src/test/resources/unit/regex/forward_named_backreference.t b/src/test/resources/unit/regex/forward_named_backreference.t
    new file mode 100644
    index 0000000000..5bbf961dc6
    --- /dev/null
    +++ b/src/test/resources/unit/regex/forward_named_backreference.t
    @@ -0,0 +1,18 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 4;
    +
    +my $brace = eval q{qr/(?\g{later})(?x)(?&before)/};
    +ok(defined($brace) && !$@,
    +   'forward g-brace named backreference compiles before its capture');
    +
    +my $angle = eval q{qr/(?\k)(?x)(?&before)/};
    +ok(defined($angle) && !$@,
    +   'forward k-angle named backreference compiles before its capture');
    +
    +my $missing = eval q{qr/(?\g{missing})(?x)/};
    +ok(!defined($missing) && $@ =~ /Reference to nonexistent named group/,
    +   'a named backreference missing from the complete pattern is rejected');
    +
    +ok('xx' !~ $brace,
    +   'an unset forward backreference does not consume a later capture');
    diff --git a/src/test/resources/unit/regex/frontend_regex_diagnostic_provenance.t b/src/test/resources/unit/regex/frontend_regex_diagnostic_provenance.t
    new file mode 100644
    index 0000000000..e89e24b9a6
    --- /dev/null
    +++ b/src/test/resources/unit/regex/frontend_regex_diagnostic_provenance.t
    @@ -0,0 +1,31 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +
    +ok('abbbbc' =~ /\N{ 3 , 4 }/, 'spaced numeric braces remain a quantifier');
    +is($&, 'abbb', 'spaced non-newline quantifier keeps its match');
    +
    +my @literal_warnings;
    +{
    +    local $SIG{__WARN__} = sub { push @literal_warnings, join '', @_ };
    +    eval q{qr/[A\EB]c/};
    +}
    +like(join('', @literal_warnings), qr/^Useless use of \\E/,
    +    'literal unpaired E has its compile-time warning');
    +
    +my $interpolated = '\E';
    +my @interpolated_warnings;
    +my $compiled;
    +{
    +    local $SIG{__WARN__} = sub { push @interpolated_warnings, join '', @_ };
    +    $compiled = qr/[A${interpolated}B]/;
    +}
    +unlike(join('', @interpolated_warnings), qr/^Useless use of \\E/,
    +    'interpolated E does not gain the literal-only useless warning');
    +ok('E' =~ $compiled, 'interpolated E remains a literal character');
    +
    +eval q{qr/abc\N{def}/};
    +like($@, qr/^Unknown charname 'def'/,
    +    'literal unknown name remains fatal with its spelling');
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/incomplete_group_effect_diagnostics.t b/src/test/resources/unit/regex/incomplete_group_effect_diagnostics.t
    new file mode 100644
    index 0000000000..146ff5848e
    --- /dev/null
    +++ b/src/test/resources/unit/regex/incomplete_group_effect_diagnostics.t
    @@ -0,0 +1,10 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 4;
    +
    +for my $pattern ('(?', 'a(?') {
    +    my $ok = eval "qr/$pattern/; 1";
    +    ok(!$ok, "$pattern is rejected");
    +    ok(index($@, 'Sequence (? incomplete') >= 0,
    +        "$pattern reports an incomplete group effect");
    +}
    diff --git a/src/test/resources/unit/regex/incomplete_named_delimiter_diagnostic.t b/src/test/resources/unit/regex/incomplete_named_delimiter_diagnostic.t
    new file mode 100644
    index 0000000000..49b32c8ac3
    --- /dev/null
    +++ b/src/test/resources/unit/regex/incomplete_named_delimiter_diagnostic.t
    @@ -0,0 +1,14 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 4;
    +
    +for my $case (
    +    [q{qr/(?'/}, q{Sequence (?'... not terminated}],
    +    [q{qr/(?[0]; 1";
    +    ok(!$compiled && index($@, $case->[1]) >= 0,
    +       'incomplete named delimiter uses the Perl diagnostic');
    +}
    diff --git a/src/test/resources/unit/regex/inline_locale_modifier_diagnostic.t b/src/test/resources/unit/regex/inline_locale_modifier_diagnostic.t
    new file mode 100644
    index 0000000000..41918438e0
    --- /dev/null
    +++ b/src/test/resources/unit/regex/inline_locale_modifier_diagnostic.t
    @@ -0,0 +1,7 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 1;
    +
    +my $compiled = eval q{ qr/(?i-l:foo)/; 1 };
    +ok(!$compiled && index($@, 'Regexp modifier "l" may not appear after the "-"') >= 0,
    +   'inline locale modifier after minus uses the Perl diagnostic');
    diff --git a/src/test/resources/unit/regex/interpolated_global_warning.t b/src/test/resources/unit/regex/interpolated_global_warning.t
    new file mode 100644
    index 0000000000..a1aa221cb5
    --- /dev/null
    +++ b/src/test/resources/unit/regex/interpolated_global_warning.t
    @@ -0,0 +1,38 @@
    +use strict;
    +use Test::More tests => 4;
    +
    +my $fragment = '\m';
    +
    +{
    +    local $^W = 1;
    +    my @warnings;
    +    local $SIG{__WARN__} = sub { push @warnings, @_ };
    +    my $compiled = qr/a$fragment/;
    +    is(scalar @warnings, 1, 'global warning switch diagnoses interpolated escape');
    +}
    +
    +{
    +    local $^W = 1;
    +    my @warnings;
    +    local $SIG{__WARN__} = sub { push @warnings, @_ };
    +    no warnings 'regexp';
    +    my $compiled = qr/a$fragment/;
    +    is(scalar @warnings, 0, 'lexical suppression overrides global warning switch');
    +}
    +
    +{
    +    local $^W;
    +    my @warnings;
    +    local $SIG{__WARN__} = sub { push @warnings, @_ };
    +    my $compiled = qr/a$fragment/;
    +    is(scalar @warnings, 0, 'interpolated escape warning is off by default');
    +}
    +
    +{
    +    use re 'strict';
    +    local $^W;
    +    my @warnings;
    +    local $SIG{__WARN__} = sub { push @warnings, @_ };
    +    my $compiled = qr/a$fragment/;
    +    is(scalar @warnings, 1, 'strict regex mode enables interpolated escape warning');
    +}
    diff --git a/src/test/resources/unit/regex/interpreter_foreach_match_variable_alias.t b/src/test/resources/unit/regex/interpreter_foreach_match_variable_alias.t
    new file mode 100644
    index 0000000000..a85eec860a
    --- /dev/null
    +++ b/src/test/resources/unit/regex/interpreter_foreach_match_variable_alias.t
    @@ -0,0 +1,46 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +
    +my $rx = qr/o/;
    +my $subject = 'ooaoaoao';
    +my $count = 0;
    +
    +'zoo' =~ /z/;
    +for ($') {
    +    for ($count += ($subject =~ /$rx/); $' && /$rx/ && ($count++); ) { }
    +}
    +is($count, 5, 'implicit foreach alias tracks changing postmatch state');
    +
    +'zoo' =~ /z/;
    +for ($') {
    +    'abc' =~ /b/;
    +    is($_, 'c', 'implicit foreach variable keeps a live postmatch alias');
    +}
    +
    +'zoo' =~ /z/;
    +for my $lexical ($') {
    +    'abc' =~ /b/;
    +    is($lexical, 'c', 'lexical foreach variable keeps a live postmatch alias');
    +}
    +
    +our $slot;
    +'zoo' =~ /z/;
    +for $slot ($') {
    +    'abc' =~ /b/;
    +    is($slot, 'c', 'package foreach variable keeps a live postmatch alias');
    +}
    +
    +'zoo' =~ /z/;
    +for $slot ($`) {
    +    'abc' =~ /b/;
    +    is($slot, 'a', 'package foreach variable keeps a live prematch alias');
    +}
    +
    +'zoo' =~ /z/;
    +for $slot ($&) {
    +    'abc' =~ /b/;
    +    is($slot, 'b', 'package foreach variable keeps a live match alias');
    +}
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/joni_extended_class_range_diagnostic.t b/src/test/resources/unit/regex/joni_extended_class_range_diagnostic.t
    new file mode 100644
    index 0000000000..36334cab24
    --- /dev/null
    +++ b/src/test/resources/unit/regex/joni_extended_class_range_diagnostic.t
    @@ -0,0 +1,9 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +
    +my $invalid_range = eval q{ qr/[\xdf-/i; 1 } ? '' : $@;
    +like($invalid_range, qr/^Invalid \[\] range/,
    +     'unterminated character-class range uses the Perl diagnostic');
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/joni_false_class_ranges.t b/src/test/resources/unit/regex/joni_false_class_ranges.t
    new file mode 100644
    index 0000000000..3355ad4168
    --- /dev/null
    +++ b/src/test/resources/unit/regex/joni_false_class_ranges.t
    @@ -0,0 +1,20 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +
    +my @cases = (
    +    [ qr/([a-\d]+)/,                'za-9z', 'a-9', 'backslash d after a-dash' ],
    +    [ qr/([\d-z]+)/,                'a0-za', '0-z', 'backslash d before dash-z' ],
    +    [ qr/([\d-\s]+)/,              'a0- z', '0- ', 'backslash d through dash-space' ],
    +    [ qr/([a-[:digit:]]+)/,          'za-9z', 'a-9', 'POSIX digit after a-dash' ],
    +    [ qr/([[:digit:]-z]+)/,          '=0-z=', '0-z', 'POSIX digit before dash-z' ],
    +    [ qr/([[:digit:]-[:alpha:]]+)/, '=0-z=', '0-z', 'POSIX digit and alpha around dash' ],
    +);
    +
    +for my $case (@cases) {
    +    my ($regex, $input, $want, $name) = @$case;
    +    my ($got) = $input =~ $regex;
    +    is($got, $want, $name);
    +}
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/joni_final_capture_clearing.t b/src/test/resources/unit/regex/joni_final_capture_clearing.t
    new file mode 100644
    index 0000000000..a6d163a878
    --- /dev/null
    +++ b/src/test/resources/unit/regex/joni_final_capture_clearing.t
    @@ -0,0 +1,39 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +
    +sub captures {
    +    my ($text, $pattern) = @_;
    +    return unless $text =~ $pattern;
    +    return ($&, $^N, $+, join q{|}, map { defined $_ ? $_ : q{} } ($1, $2, $3, $4));
    +}
    +
    +my $recursive_named = [ captures('madamimadam', qr/^(?(?.)((?&PAL)|.?)\k)$/) ];
    +is_deeply(
    +    $recursive_named,
    +    [ 'madamimadam', 'madamimadam', 'adamimada', 'madamimadam|m|adamimada|' ],
    +    'recursive named call publishes final closed captures',
    +);
    +
    +my $relative_call = [ captures('abc abccba cba', qr/(([abc]+) \g-1)(([abc]+) \g{-1})/) ];
    +is_deeply(
    +    $relative_call,
    +    [ 'abc abccba cba', 'cba cba', 'cba', 'abc abc|abc|cba cba|cba' ],
    +    'ordinary relative calls retain their final capture iteration',
    +);
    +
    +my $define_call = [ captures('aa', qr/(?(DEFINE)(?(?&B)+)(?a))(?&A)/) ];
    +is_deeply(
    +    $define_call,
    +    [ 'aa', undef, undef, '|||' ],
    +    'DEFINE calls publish captures from their final iteration',
    +);
    +
    +my $recursive_backref = [ captures('aba', qr/^(.\1?)(?1)$/) ];
    +is_deeply(
    +    $recursive_backref,
    +    [ 'aba', 'a', 'a', 'a|||' ],
    +    'recursive backreference retains the final capture',
    +);
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/joni_numeric_escape_policy.t b/src/test/resources/unit/regex/joni_numeric_escape_policy.t
    new file mode 100644
    index 0000000000..af27d64221
    --- /dev/null
    +++ b/src/test/resources/unit/regex/joni_numeric_escape_policy.t
    @@ -0,0 +1,84 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +
    +sub compile_case {
    +    my ($source) = @_;
    +    my @warnings;
    +    local $SIG{__WARN__} = sub { push @warnings, @_ };
    +    my $regex = eval $source;
    +    return ($regex, $@, \@warnings);
    +}
    +
    +sub succeeds_with_warning {
    +    my ($name, $source, $warning) = @_;
    +    my ($regex, $error, $warnings) = compile_case($source);
    +    ok($regex, "$name compiles");
    +    is($error, '', "$name is not fatal");
    +    is(scalar @$warnings, 1, "$name emits one warning");
    +    like($warnings->[0], $warning, "$name warning text and marker");
    +}
    +
    +sub dies_without_warning {
    +    my ($name, $source, $error_pattern) = @_;
    +    my ($regex, $error, $warnings) = compile_case($source);
    +    ok(!$regex, "$name does not compile");
    +    like($error, $error_pattern, "$name fatal text and marker");
    +    is(scalar @$warnings, 0, "$name emits no warning before dying");
    +}
    +
    +succeeds_with_warning(
    +    'non-strict braced octal', q{qr/\o{789}/},
    +    qr/^Non-octal character '8'.*m\/\\o\{789\} <-- HERE /s);
    +succeeds_with_warning(
    +    'non-strict braced hex', q{qr/\x{defg}/},
    +    qr/^Non-hex character 'g'.*m\/\\x\{defg\} <-- HERE /s);
    +succeeds_with_warning(
    +    'non-strict short octal', q{qr/\08/},
    +    qr/^Non-octal character '8'.*Resolved as "\\0008".*m\/\\08 <-- HERE /s);
    +succeeds_with_warning(
    +    'non-strict class short octal', q{qr/[\08]/},
    +    qr/^Non-octal character '8'.*m\/\[\\08 <-- HERE \]/s);
    +
    +dies_without_warning(
    +    'strict braced octal',
    +    q{no warnings 'experimental::re_strict'; use re 'strict'; qr/\o{789}/},
    +    qr/^Non-octal character.*m\/\\o\{78 <-- HERE 9\}/s);
    +dies_without_warning(
    +    'strict class braced hex',
    +    q{no warnings 'experimental::re_strict'; use re 'strict'; qr/[\x{defg}]/},
    +    qr/^Non-hex character.*m\/\[\\x\{defg <-- HERE \}\]/s);
    +dies_without_warning(
    +    'extended-class braced octal',
    +    q{no warnings 'experimental::regex_sets'; qr/(?[ \o{1038} ])/},
    +    qr/^Non-octal character.*m\/\(\?\[ \\o\{1038 <-- HERE \} \]\)/s);
    +dies_without_warning(
    +    'extended-class braced hex',
    +    q{no warnings 'experimental::regex_sets'; qr/(?[ \x{defg} ])/},
    +    qr/^Non-hex character.*m\/\(\?\[ \\x\{defg <-- HERE \} \]\)/s);
    +dies_without_warning(
    +    'strict long unbraced hex',
    +    q{no warnings 'experimental::re_strict'; use re 'strict'; qr/\xABC/},
    +    qr/^Use \\x\{\.\.\.\} for more than two hex characters.*m\/\\xABC <-- HERE /s);
    +dies_without_warning(
    +    'strict empty braced hex',
    +    q{no warnings 'experimental::re_strict'; use re 'strict'; qr/\x{}/},
    +    qr/^Empty \\x\{\}.*m\/\\x\{\} <-- HERE /s);
    +dies_without_warning(
    +    'strict terminal hex escape',
    +    q{no warnings 'experimental::re_strict'; use re 'strict'; qr/\x{100}\x/},
    +    qr/^Empty \\x.*m\/\\x\{100\}\\x <-- HERE /s);
    +
    +for my $case (
    +    ['valid strict octal', q{no warnings 'experimental::re_strict'; use re 'strict'; qr/[\000]/}],
    +    ['valid strict braced octal', q{no warnings 'experimental::re_strict'; use re 'strict'; qr/\o{707}/}],
    +    ['valid strict braced hex', q{no warnings 'experimental::re_strict'; use re 'strict'; qr/\x{def}/}],
    +) {
    +    my ($name, $source) = @$case;
    +    my ($regex, $error, $warnings) = compile_case($source);
    +    ok($regex, "$name compiles");
    +    is($error, '', "$name is not fatal");
    +    is(scalar @$warnings, 0, "$name is quiet");
    +}
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/joni_ordinary_capture_region.t b/src/test/resources/unit/regex/joni_ordinary_capture_region.t
    new file mode 100644
    index 0000000000..cfb6c70a7a
    --- /dev/null
    +++ b/src/test/resources/unit/regex/joni_ordinary_capture_region.t
    @@ -0,0 +1,8 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +
    +my $match = 'ababa' =~ /(?ab)(?&pair)(?a)/ ? "$1-$2" : undef;
    +is($match, 'ab-a', 'ordinary named subpattern call retains earlier and later captures');
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/joni_posix_diagnostic_policy.t b/src/test/resources/unit/regex/joni_posix_diagnostic_policy.t
    new file mode 100644
    index 0000000000..a6f5df2e9a
    --- /dev/null
    +++ b/src/test/resources/unit/regex/joni_posix_diagnostic_policy.t
    @@ -0,0 +1,100 @@
    +use strict;
    +use warnings;
    +use utf8;
    +use Test::More;
    +
    +sub compile_pattern {
    +    my ($pattern, $strict, $mods, $suppress_regexp) = @_;
    +    $mods //= '';
    +    my @warnings;
    +    my ($regex, $error);
    +    {
    +        local $SIG{__WARN__} = sub { push @warnings, @_ };
    +        my $source = q{no warnings 'experimental::regex_sets'; }
    +            . ($strict
    +                ? q{no warnings 'experimental::re_strict'; use re 'strict'; }
    +                : '')
    +            . ($suppress_regexp ? q{no warnings 'regexp'; } : '')
    +            . 'qr/' . $pattern . '/' . $mods;
    +        $regex = eval $source;
    +        $error = $@;
    +    }
    +    return ($regex, $error, \@warnings);
    +}
    +
    +my @cases = (
    +    [ 'outside_valid',      '[:alpha:]',
    +      [ 'POSIX syntax [: :] belongs inside character classes' ] ],
    +    [ 'outside_invalid',    '[:zog:]',
    +      [ q{POSIX syntax [: :] belongs inside character classes (but this one isn't fully valid)} ] ],
    +    [ 'outside_incomplete', '[:blank]',
    +      [ q{POSIX syntax [: :] belongs inside character classes (but this one isn't fully valid)} ] ],
    +    [ 'outside_collating',  '[.zog.]',
    +      [ q{POSIX syntax [. .] belongs inside character classes (but this one isn't implemented)} ] ],
    +    [ 'adjacent_outside',   '[[:cntrl:]][:^ascii:]',
    +      [ 'POSIX syntax [: :] belongs inside character classes' ] ],
    +    [ 'missing_colon',      '[[:digit]]',
    +      [ q{Assuming NOT a POSIX class since there is no terminating ':'} ] ],
    +    [ 'missing_outer',      '[[:digit:foo]',
    +      [ q{Assuming NOT a POSIX class since there is no terminating ']'} ] ],
    +    [ 'near_name',          '[[:dgit]]',
    +      [ q{Assuming NOT a POSIX class since there is no terminating ':'} ] ],
    +    [ 'uppercase',          '[[:DIGIT]]',
    +      [ 'Assuming NOT a POSIX class since the name must be all lowercase letters',
    +        q{Assuming NOT a POSIX class since there is no terminating ':'} ] ],
    +    [ 'no_start_colon',     '[[digit]',
    +      [ q{Assuming NOT a POSIX class since there must be a starting ':'},
    +        q{Assuming NOT a POSIX class since there is no terminating ':'} ] ],
    +    [ 'caret_before_colon', '[[^word]',
    +      [ q{Assuming NOT a POSIX class since the '^' must come after the colon},
    +        q{Assuming NOT a POSIX class since there must be a starting ':'},
    +        q{Assuming NOT a POSIX class since there is no terminating ':'} ] ],
    +    [ 'missing_open',       '[foo:lower:]]',
    +      [ q{Assuming NOT a POSIX class since it doesn't start with a '['} ] ],
    +    [ 'semicolon',          '[[;upper;]]',
    +      [ 'Assuming NOT a POSIX class since a semi-colon was found instead of a colon',
    +        'Assuming NOT a POSIX class since a semi-colon was found instead of a colon' ] ],
    +    [ 'missing_open_semis', '[foo;punct;]]',
    +      [ q{Assuming NOT a POSIX class since it doesn't start with a '['},
    +        'Assuming NOT a POSIX class since a semi-colon was found instead of a colon',
    +        'Assuming NOT a POSIX class since a semi-colon was found instead of a colon' ] ],
    +);
    +
    +for my $strict (0, 1) {
    +    for my $case (@cases) {
    +        my ($name, $pattern, $expected) = @$case;
    +        my ($regex, $error, $warnings) = compile_pattern($pattern, $strict);
    +        ok(defined($regex), "$name compiles" . ($strict ? ' under strict' : ''));
    +        is($error, '', "$name is nonfatal" . ($strict ? ' under strict' : ''));
    +        is(scalar(@$warnings), scalar(@$expected),
    +            "$name warning count" . ($strict ? ' under strict' : ''));
    +        for my $index (0 .. $#$expected) {
    +            like($warnings->[$index], qr/^\Q$expected->[$index]\E in regex; marked by <-- HERE/,
    +                "$name warning $index preserves order and positioned rendering");
    +        }
    +    }
    +}
    +
    +for my $case (
    +    [ 'far_name'       => '[[:dgt]]' ],
    +    [ 'extended_short' => '(?[[:w:]])' ],
    +    [ 'wide_standard'  => "\x{30cd}[[:\x{30cd}:]]\x{30cd}" ],
    +    [ 'wide_extended'  => "\x{30cd}(?[[:\x{30cd}:]])\x{30cd}" ],
    +    [ 'valid_standard' => '[[:digit:]]' ],
    +    [ 'valid_extended' => '(?[[:digit:]])' ],
    +) {
    +    my ($name, $pattern) = @$case;
    +    my ($regex, $error, $warnings) = compile_pattern($pattern, 0);
    +    ok(defined($regex), "$name valid control compiles");
    +    is($error, '', "$name valid control is nonfatal");
    +    is(scalar(@$warnings), 0, "$name valid control is warning-free");
    +}
    +
    +{
    +    my ($regex, $error, $warnings) = compile_pattern('[:alpha:]', 0, '', 1);
    +    ok(defined($regex), 'regexp warning suppression keeps malformed POSIX syntax compilable');
    +    is($error, '', 'regexp warning suppression stays nonfatal');
    +    is(scalar(@$warnings), 0, 'regexp warning suppression is honored');
    +}
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/joni_possessive_literal_region.t b/src/test/resources/unit/regex/joni_possessive_literal_region.t
    new file mode 100644
    index 0000000000..8d6052c564
    --- /dev/null
    +++ b/src/test/resources/unit/regex/joni_possessive_literal_region.t
    @@ -0,0 +1,18 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +
    +my @cases = (
    +    [ qr/fooa++b/,     'fooaaaaab', 'possessive plus' ],
    +    [ qr/fooa*+b/,     'fooaaaaab', 'possessive star' ],
    +    [ qr/fooa{1,5}+b/, 'fooaaaaab', 'possessive bounded repeat' ],
    +    [ qr/fooa?+b/,     'fooab',     'possessive optional repeat' ],
    +);
    +
    +for my $case (@cases) {
    +    my ($pattern, $input, $name) = @$case;
    +    my $match = $input =~ /$pattern/ ? $& : undef;
    +    is($match, $input, "$name retains its full literal region");
    +}
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/joni_recursive_backreference.t b/src/test/resources/unit/regex/joni_recursive_backreference.t
    new file mode 100644
    index 0000000000..f137c8f5cd
    --- /dev/null
    +++ b/src/test/resources/unit/regex/joni_recursive_backreference.t
    @@ -0,0 +1,8 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +
    +my $match = 'abbaccaddedcb' =~ /(?:\1|a)([bcd])\1(?:(?R)|e)\1/ ? $& : undef;
    +is($match, 'abbaccaddedcb', 'whole-pattern recursion preserves backreferences');
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/joni_recursive_capture_publication.t b/src/test/resources/unit/regex/joni_recursive_capture_publication.t
    new file mode 100644
    index 0000000000..4355f3da5a
    --- /dev/null
    +++ b/src/test/resources/unit/regex/joni_recursive_capture_publication.t
    @@ -0,0 +1,11 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +
    +my $match = 'foofoobar' =~ /(?foo(?(R)bar))?(?1)/ ? $1 : undef;
    +is($match, 'foo', 'recursive numbered call restores its caller capture');
    +
    +$match = 'xfoofoobar' =~ /(x)(?foo(?(R&A)bar))?(?&A)/ ? $2 : undef;
    +is($match, 'foo', 'recursive named call restores its caller capture');
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/joni_repeat_capture_lifetime.t b/src/test/resources/unit/regex/joni_repeat_capture_lifetime.t
    new file mode 100644
    index 0000000000..2e1a77b88c
    --- /dev/null
    +++ b/src/test/resources/unit/regex/joni_repeat_capture_lifetime.t
    @@ -0,0 +1,30 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +
    +# perl5_t/t/re/re_tests row 483 records the old capture-retention result as
    +# pre-5.37.10 behavior. The development host is 5.34; PerlOnJava targets 5.44.
    +plan skip_all => 'requires Perl 5.37.10 final-iteration capture semantics'
    +    if $] < 5.037010;
    +
    +sub captures {
    +    return map { defined($_) ? $_ : '' } @_;
    +}
    +
    +ok('foobar' =~ /((foo)|(bar))*/, 'alternating repeated capture matches');
    +is_deeply([captures($1, $2, $3)], [qw(bar), '', 'bar'],
    +    'only captures from the final successful iteration remain');
    +
    +ok('foobar' =~ /(?:(f)(o)(o)|(b)(a)(r))*/, 'disjoint repeated alternatives match');
    +is_deeply([captures($1, $2, $3, $4, $5, $6)], ['', '', '', qw(b a r)],
    +    'captures from the previous alternative are cleared');
    +
    +ok('aba' =~ /^(a(b)?)+$/, 'optional capture in a repeat matches');
    +is_deeply([captures($1, $2)], ['a', ''],
    +    'optional capture omitted by the final iteration is cleared');
    +
    +ok('ace' =~ /(([ab]+)|([cd]+)|([ef]+))+/, 'multi-alternative repeat matches');
    +is_deeply([captures($1, $2, $3, $4)], ['e', '', '', 'e'],
    +    'all inactive alternatives from prior iterations are cleared');
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/joni_whole_pattern_recursion.t b/src/test/resources/unit/regex/joni_whole_pattern_recursion.t
    new file mode 100644
    index 0000000000..e34370b406
    --- /dev/null
    +++ b/src/test/resources/unit/regex/joni_whole_pattern_recursion.t
    @@ -0,0 +1,9 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +
    +my $input = 'phoofoofoobarbarbarr';
    +my $match = $input =~ /foo(?R)?bar/ ? $& : undef;
    +is($match, 'foofoobarbar', 'whole-pattern recursion with (?R)');
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/lazy_anychar_implicit_anchor.t b/src/test/resources/unit/regex/lazy_anychar_implicit_anchor.t
    new file mode 100644
    index 0000000000..ff7b0e35f1
    --- /dev/null
    +++ b/src/test/resources/unit/regex/lazy_anychar_implicit_anchor.t
    @@ -0,0 +1,20 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +
    +my $same_line = 'abxx';
    +ok($same_line =~ /.*?x/, 'lazy leading dot-star finds the first suffix');
    +is($&, 'abx', 'lazy matching still keeps its shortest extent');
    +is($-[0], 0, 'lazy leading dot-star begins at the line start');
    +
    +my $after_newline = "before\nx";
    +ok($after_newline =~ /.*?x/, 'lazy dot-star searches following lines');
    +is($&, 'x', 'non-dotall lazy dot-star does not cross a newline');
    +is($-[0], 7, 'implicit anchoring advances to the next line start');
    +
    +my $alternative = 'ba';
    +ok($alternative =~ /a|.*?x/, 'an alternative before dot-star remains searchable');
    +is($&, 'a', 'an alternative is not incorrectly anchored to the buffer start');
    +is($-[0], 1, 'the alternative retains its later start offset');
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/left_brace_warning_cardinality.t b/src/test/resources/unit/regex/left_brace_warning_cardinality.t
    new file mode 100644
    index 0000000000..e9e9d935f0
    --- /dev/null
    +++ b/src/test/resources/unit/regex/left_brace_warning_cardinality.t
    @@ -0,0 +1,42 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +
    +for my $pattern (
    +    ':{4,a}',
    +    'xa{3\\,4}y',
    +    '\\${[^\\}]*}',
    +    '.{',
    +    '[x]{',
    +    '\\p{Latin}{',
    +) {
    +    my @warnings;
    +    {
    +        local $SIG{__WARN__} = sub { push @warnings, @_ };
    +        my $regex = eval { qr/$pattern/ };
    +        ok(defined($regex), "$pattern remains compilable");
    +    }
    +    is(scalar(@warnings), 1, "$pattern emits exactly one warning");
    +    like($warnings[0], qr/^Unescaped left brace in regex is passed through/,
    +        "$pattern retains the Perl warning text");
    +}
    +
    +for my $pattern ('^{', 'foo|{') {
    +    my @warnings;
    +    local $SIG{__WARN__} = sub { push @warnings, @_ };
    +    my $regex = eval { qr/$pattern/ };
    +    ok(defined($regex) && !@warnings,
    +        "$pattern remains an allowed quiet brace context");
    +}
    +
    +{
    +    no warnings 'regexp';
    +    my @warnings;
    +    local $SIG{__WARN__} = sub { push @warnings, @_ };
    +    my $pattern = ':{4,a}';
    +    my $regex = eval { qr/$pattern/ };
    +    ok(defined($regex) && !@warnings,
    +        'regexp warning suppression applies to the single retained warning');
    +}
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/linebreak_byte_nel.t b/src/test/resources/unit/regex/linebreak_byte_nel.t
    new file mode 100644
    index 0000000000..2e4c72ee45
    --- /dev/null
    +++ b/src/test/resources/unit/regex/linebreak_byte_nel.t
    @@ -0,0 +1,30 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 14;
    +
    +my $byte_nel = chr(0x85);
    +ok($byte_nel =~ /\A\R\z/, 'byte NEL is a line break');
    +ok($byte_nel !~ /\A\V\z/, 'byte NEL is not non-vertical whitespace');
    +
    +my $unicode_nel = $byte_nel;
    +utf8::upgrade($unicode_nel);
    +ok($unicode_nel =~ /\A\R\z/, 'Unicode NEL is a line break');
    +ok($unicode_nel !~ /\A\V\z/, 'Unicode NEL is not non-vertical whitespace');
    +ok("\x{2028}" =~ /\A\R\z/, 'Unicode line separator is a line break');
    +ok("\x{2029}" =~ /\A\R\z/, 'Unicode paragraph separator is a line break');
    +
    +my $mixed = "\r\n" . $byte_nel . "\r\n\n";
    +my ($capture) = "foo${mixed}bar" =~ /foo(\R+)bar/;
    +is($capture, $mixed, 'quantified line break consumes CRLF, NEL, CRLF, LF');
    +
    +my ($breaks, $tail) = "${mixed}b" =~ /\A(\R+)(\V)\z/;
    +is($breaks, $mixed, 'quantified line break stops after the full sequence');
    +is($tail, 'b', 'non-vertical escape captures the following byte');
    +
    +my ($nonvertical, $nel) = "o${byte_nel}" =~ /\A(\V)(\R)\z/;
    +is($nonvertical, 'o', 'non-vertical byte precedes byte NEL');
    +is($nel, $byte_nel, 'line-break capture consumes byte NEL after V');
    +
    +ok("\r\n" =~ /\A\R\z/, 'CRLF remains one line-break atom');
    +ok("\r" =~ /\A\R\z/, 'CR remains a line break');
    +ok("\n" =~ /\A\R\z/, 'LF remains a line break');
    diff --git a/src/test/resources/unit/regex/literal_regex_compile_order.t b/src/test/resources/unit/regex/literal_regex_compile_order.t
    new file mode 100644
    index 0000000000..27b9d5871b
    --- /dev/null
    +++ b/src/test/resources/unit/regex/literal_regex_compile_order.t
    @@ -0,0 +1,16 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 3;
    +
    +my $error = do {
    +    local $@;
    +    eval q{ use re Debug => 'ALL'; qr{(?{a})(?\g{c}}) };
    +    $@;
    +};
    +
    +like($error, qr/Unmatched \( in regex/,
    +     'malformed literal regex is diagnosed before the later source token');
    +like($error, qr/m\/\(\?\{a\}\)\( <-- HERE \?/,
    +     'diagnostic retains the original executable callback source');
    +unlike($error, qr/syntax error.*near/s,
    +       'later source syntax does not replace the regex diagnostic');
    diff --git a/src/test/resources/unit/regex/lookbehind_length_diagnostic_renderer.t b/src/test/resources/unit/regex/lookbehind_length_diagnostic_renderer.t
    new file mode 100644
    index 0000000000..779222b122
    --- /dev/null
    +++ b/src/test/resources/unit/regex/lookbehind_length_diagnostic_renderer.t
    @@ -0,0 +1,8 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 2;
    +
    +my $compiled = eval q{ qr/(?<= a{255})/; 1 };
    +ok(!$compiled, 'overlong lookbehind does not compile');
    +like($@, qr/^Lookbehind longer than 255 not implemented in regex m\/\(\?<= a\{255\}\)\/ at /,
    +     'overlong lookbehind uses the unmarked Perl diagnostic');
    diff --git a/src/test/resources/unit/regex/malformed_posix_warnings.t b/src/test/resources/unit/regex/malformed_posix_warnings.t
    new file mode 100644
    index 0000000000..b9ec0dcb7c
    --- /dev/null
    +++ b/src/test/resources/unit/regex/malformed_posix_warnings.t
    @@ -0,0 +1,26 @@
    +use strict;
    +use warnings;
    +no warnings 'experimental::regex_sets';
    +use Test::More tests => 8;
    +
    +for my $source (
    +    q{qr/[[:digit]]/},
    +    q{qr/[[:DIGIT]]/},
    +    q{qr/[[^word]/},
    +) {
    +    my @warnings;
    +    {
    +        local $SIG{__WARN__} = sub { push @warnings, @_ };
    +        eval $source;
    +    }
    +    is($@, '', "$source compiles as literal class text");
    +    ok(@warnings, "$source reports its malformed POSIX-like spelling");
    +}
    +
    +my @extended_warnings;
    +{
    +    local $SIG{__WARN__} = sub { push @extended_warnings, @_ };
    +    eval q{qr/(?[[:word]])/};
    +}
    +is($@, '', 'direct extended-class spelling compiles as literal class text');
    +ok(@extended_warnings, 'direct extended-class literal reports the missing colon');
    diff --git a/src/test/resources/unit/regex/named_capture_tied_hash.t b/src/test/resources/unit/regex/named_capture_tied_hash.t
    new file mode 100644
    index 0000000000..472960161a
    --- /dev/null
    +++ b/src/test/resources/unit/regex/named_capture_tied_hash.t
    @@ -0,0 +1,51 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 32;
    +
    +'hlagh' =~ /(?.)(?.)(?.).*(?$)/;
    +
    +is($+{a}, 'h', '%+ fetches the first participating duplicate capture');
    +is($-{a}[0], 'h', '%- fetches the first duplicate capture');
    +is($-{a}[1], 'a', '%- fetches every duplicate capture');
    +
    +for my $operation (
    +    sub { $+{a} = 'changed' },
    +    sub { delete $+{a} },
    +    sub { %+ = () },
    +) {
    +    eval { $operation->() };
    +    like($@, qr/read-only/, 'named capture hashes are read-only');
    +}
    +
    +my $plus = tied %+;
    +my $minus = tied %-;
    +isa_ok($plus, 'Tie::Hash::NamedCapture');
    +isa_ok($minus, 'Tie::Hash::NamedCapture');
    +
    +is(Tie::Hash::NamedCapture::FETCH(undef, undef), undef, 'FETCH with undef');
    +eval { Tie::Hash::NamedCapture::STORE(undef, undef, undef) };
    +like($@, qr/Modification of a read-only value attempted/, 'STORE with undef');
    +eval { Tie::Hash::NamedCapture::DELETE(undef, undef) };
    +like($@, qr/Modification of a read-only value attempted/, 'DELETE with undef');
    +eval { Tie::Hash::NamedCapture::CLEAR(undef) };
    +like($@, qr/Modification of a read-only value attempted/, 'CLEAR with undef');
    +is(Tie::Hash::NamedCapture::EXISTS(undef, undef), undef, 'EXISTS with undef');
    +is(Tie::Hash::NamedCapture::FIRSTKEY(undef), undef, 'FIRSTKEY with undef');
    +is(Tie::Hash::NamedCapture::NEXTKEY(undef, undef), undef, 'NEXTKEY with undef');
    +is(Tie::Hash::NamedCapture::SCALAR(undef), undef, 'SCALAR with undef');
    +
    +for my $case (
    +    [FETCH => '$key'],
    +    [STORE => '$key, $value'],
    +    [DELETE => '$key'],
    +    [CLEAR => ''],
    +    [EXISTS => '$key'],
    +    [FIRSTKEY => ''],
    +    [NEXTKEY => '$lastkey'],
    +    [SCALAR => ''],
    +) {
    +    my ($method, $signature) = @$case;
    +    is(eval { $plus->$method(0 .. 3); 1 }, undef, "$method rejects extra arguments");
    +    like($@, qr/Usage: Tie::Hash::NamedCapture::\Q$method\E\(\Q$signature\E\)/,
    +        "$method reports its signature");
    +}
    diff --git a/src/test/resources/unit/regex/named_character_single_diagnostic.t b/src/test/resources/unit/regex/named_character_single_diagnostic.t
    new file mode 100644
    index 0000000000..4b00b113d7
    --- /dev/null
    +++ b/src/test/resources/unit/regex/named_character_single_diagnostic.t
    @@ -0,0 +1,15 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 2;
    +
    +my @warnings;
    +{
    +    local $SIG{__WARN__} = sub { push @warnings, join '', @_ };
    +    eval "#line 41 named_character_single_diagnostic.t\nqr/abc\\N{def}/";
    +}
    +
    +is($@,
    +    "Unknown charname 'def' at named_character_single_diagnostic.t line 41, within pattern\n",
    +    'an unknown literal charname has one exact lexical diagnostic');
    +is(scalar @warnings, 0,
    +    'native compilation does not emit a second warning');
    diff --git a/src/test/resources/unit/regex/named_group_start_diagnostic.t b/src/test/resources/unit/regex/named_group_start_diagnostic.t
    new file mode 100644
    index 0000000000..2e03071ad1
    --- /dev/null
    +++ b/src/test/resources/unit/regex/named_group_start_diagnostic.t
    @@ -0,0 +1,7 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 1;
    +
    +my $compiled = eval q{qr/(?<;name>match)/; 1};
    +ok(!$compiled && index($@, 'Group name must start with a non-digit word character') >= 0,
    +   'invalid named-group start uses the Perl diagnostic');
    diff --git a/src/test/resources/unit/regex/named_sequence_class_range_warnings.t b/src/test/resources/unit/regex/named_sequence_class_range_warnings.t
    new file mode 100644
    index 0000000000..19cf9b274a
    --- /dev/null
    +++ b/src/test/resources/unit/regex/named_sequence_class_range_warnings.t
    @@ -0,0 +1,28 @@
    +use strict;
    +use warnings;
    +use charnames ':full';
    +use Test::More;
    +
    +my @patterns = (
    +    q{[^\N{LATIN CAPITAL LETTER A WITH MACRON AND GRAVE}]},
    +    q{[\x03-\N{LATIN CAPITAL LETTER A WITH MACRON AND GRAVE}]},
    +    q{[\N{LATIN CAPITAL LETTER A WITH MACRON AND GRAVE}-\x{10FFFF}]},
    +);
    +
    +for my $index (0 .. $#patterns) {
    +    my @warnings;
    +    my $regex;
    +    {
    +        local $SIG{__WARN__} = sub { push @warnings, @_ };
    +        $regex = eval "qr/$patterns[$index]/";
    +    }
    +    ok(defined $regex, "single-character context $index compiles");
    +    is(scalar @warnings, 1, "single-character context $index warns once");
    +    like($warnings[0],
    +        qr/Using just the first character returned by \\N\{\} in character class/,
    +        "single-character context $index uses the named-sequence warning");
    +    like($warnings[0], qr/\\N\{U\+100\.300\} <-- HERE /,
    +        "single-character context $index renders the canonical sequence");
    +}
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/native_adapter_retirement.t b/src/test/resources/unit/regex/native_adapter_retirement.t
    new file mode 100644
    index 0000000000..bdb3f2bfd3
    --- /dev/null
    +++ b/src/test/resources/unit/regex/native_adapter_retirement.t
    @@ -0,0 +1,16 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 10;
    +
    +our $REGMARK;
    +
    +ok('a' =~ /(*:seen)a/, 'abbreviated MARK matches');
    +is($REGMARK, 'seen', 'abbreviated MARK publishes its name');
    +ok('[' =~ /[a[]/, 'nested opening bracket is a literal class member');
    +ok('a' =~ /[a[]/, 'ordinary member survives a literal opening bracket');
    +ok(' ' !~ /[a b]/xx, '/xx ignores unescaped horizontal class whitespace');
    +ok(' ' =~ /[a\ b]/xx, '/xx preserves escaped class whitespace');
    +ok(' ' !~ /(?xx:[a b])/, 'scoped /xx ignores class whitespace');
    +ok(' ' =~ /(?x:[a b])/, 'scoped /x preserves class whitespace');
    +ok(' ' =~ /(?xx:(?-x:[a b]))/, 'nested -x restores class whitespace');
    +ok('a' =~ /(?)a/, 'empty group is zero width');
    diff --git a/src/test/resources/unit/regex/native_callback_backtrack_transaction.t b/src/test/resources/unit/regex/native_callback_backtrack_transaction.t
    new file mode 100644
    index 0000000000..8de3a52e66
    --- /dev/null
    +++ b/src/test/resources/unit/regex/native_callback_backtrack_transaction.t
    @@ -0,0 +1,29 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 10;
    +
    +my @lexical;
    +ok('abc' !~ /^a(?{ push @lexical, 1 })b(?{ push @lexical, 2 })$/,
    +   'path with two plain callbacks fails');
    +is_deeply(\@lexical, [], 'both lexical mutations unwind in reverse order');
    +
    +our @package;
    +ok('abc' !~ /^a(?{ push @package, 1 })b(?{ push @package, 2 })$/,
    +   'package mutation path with two callbacks fails');
    +is_deeply(\@package, [], 'both package mutations unwind in reverse order');
    +
    +my @dynamic;
    +ok('abc' !~ /^a(??{ push @dynamic, 1; 'b' })$/,
    +   'dynamic callback nested program fails');
    +is_deeply(\@dynamic, [1], 'dynamic expression mutation survives failure');
    +
    +my @nested;
    +ok('abc' !~ /^(??{ qr{a(?{ push @nested, 1 })b(?{ push @nested, 2 })} })$/,
    +   'returned program containing plain callbacks fails');
    +is_deeply(\@nested, [1, 2],
    +          'plain callback mutations inside a dynamic program survive failure');
    +
    +my @condition;
    +ok('ac' !~ /^a(?(?{ push @condition, 1; 1 })b|c)$/,
    +   'conditional callback chooses a failing branch');
    +is_deeply(\@condition, [1], 'conditional expression mutation survives failure');
    diff --git a/src/test/resources/unit/regex/native_callback_destructive_commit.t b/src/test/resources/unit/regex/native_callback_destructive_commit.t
    new file mode 100644
    index 0000000000..6cd62160c9
    --- /dev/null
    +++ b/src/test/resources/unit/regex/native_callback_destructive_commit.t
    @@ -0,0 +1,17 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +
    +for my $verb (qw(FAIL PRUNE SKIP THEN COMMIT)) {
    +    my @events;
    +    my $pattern = qr/\A(?{ push @events, $verb })(*$verb)(*FAIL)\z/;
    +    ok('x' !~ $pattern, "$verb path fails");
    +    is_deeply(\@events, [$verb], "$verb commits callback mutation");
    +}
    +
    +my @marked;
    +ok('x' !~ /\A(?{ push @marked, 'MARK' })(*MARK:plain)z\z/,
    +   'MARK path fails normally');
    +is_deeply(\@marked, [], 'MARK does not commit callback mutation');
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/native_compile_diagnostics.t b/src/test/resources/unit/regex/native_compile_diagnostics.t
    new file mode 100644
    index 0000000000..0eb33fa972
    --- /dev/null
    +++ b/src/test/resources/unit/regex/native_compile_diagnostics.t
    @@ -0,0 +1,135 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +
    +sub compile_error {
    +    my ($source) = @_;
    +    local $@;
    +    eval $source;
    +    return $@;
    +}
    +
    +like(
    +    compile_error("qr'a" . chr(92)),
    +    qr/^Search pattern not terminated/,
    +    'unterminated apostrophe-delimited pattern is diagnosed',
    +);
    +like(
    +    compile_error(q{qr/abc)/}),
    +    qr/^Unmatched \) in regex/,
    +    'unmatched closing parenthesis is diagnosed',
    +);
    +
    +for my $reference ('\\g-1', '\\g{-1}', '\\g{ -1 }') {
    +    like(
    +        compile_error("qr/$reference/"),
    +        qr/^Reference to nonexistent or unclosed group in regex/,
    +        "unclosed relative group reference $reference is diagnosed",
    +    );
    +}
    +
    +for my $reference ('\\g0', '\\g-0', '\\g{0}', '\\g{ 0 }', '\\g{-0}', '\\g{ -0 }') {
    +    like(
    +        compile_error("qr/$reference/"),
    +        qr/^Reference to invalid group 0 in regex/,
    +        "group zero reference $reference is diagnosed",
    +    );
    +}
    +
    +like(
    +    compile_error(q{qr/(?(1?)a|b)/}),
    +    qr/^Switch condition not recognized in regex/,
    +    'malformed conditional switch is diagnosed',
    +);
    +like(
    +    compile_error(q{qr/(?(1)a|b|c)/}),
    +    qr/^Switch \(\?\(condition\)\.\.\. contains too many branches in regex/,
    +    'conditional switch with three branches is diagnosed',
    +);
    +
    +my @permissive_posix = (
    +    [qr/([[:]+)/,  'a:[b]:', ':[' ],
    +    [qr/([[=]+)/,  'a=[b]=', '=[' ],
    +    [qr/([[.]+)/,  'a.[b].', '.[' ],
    +    [qr/[a[:]b[:c]/, 'abc',  'abc'],
    +);
    +for my $case (@permissive_posix) {
    +    my ($regex, $subject, $expected) = @$case;
    +    ok($subject =~ /$regex/, 'incomplete POSIX-looking syntax remains a valid pattern');
    +    is($&, $expected, 'incomplete POSIX-looking syntax preserves Perl match semantics');
    +}
    +
    +my @warning;
    +my $reversed;
    +{
    +    local $SIG{__WARN__} = sub { push @warning, @_ };
    +    $reversed = eval q{qr/((def){37,17})?ABC/};
    +}
    +ok('ABC' =~ /$reversed/, 'reversed quantifier bounds compile as an impossible optional group');
    +like(
    +    join('', @warning),
    +    qr/^Quantifier \{n,m\} with n > m can't match in regex/,
    +    'reversed quantifier bounds emit Perl warning',
    +);
    +
    +my @suppressed_warning;
    +{
    +    no warnings 'regexp';
    +    local $SIG{__WARN__} = sub { push @suppressed_warning, @_ };
    +    qr/((def){37,17})?ABC/;
    +}
    +is(scalar(@suppressed_warning), 0,
    +    q{no warnings 'regexp' suppresses the reversed-bounds warning});
    +
    +my $nonfatal = eval q{
    +    use warnings FATAL => 'all';
    +    no warnings 'regexp';
    +    qr/((def){37,17})?ABC/;
    +    1;
    +};
    +ok($nonfatal, q{no warnings 'regexp' overrides fatal warnings for reversed bounds});
    +
    +my $outer_nonfatal;
    +{
    +    use warnings FATAL => 'all';
    +    no warnings 'regexp';
    +    $outer_nonfatal = eval q{ qr/((def){37,17})?ABC/; 1 };
    +}
    +ok($outer_nonfatal,
    +    q{eval STRING inherits the caller's no warnings 'regexp' scope});
    +
    +my ($misc_error, $syntax_error);
    +{
    +    use warnings FATAL => 'all';
    +    no warnings 'regexp';
    +    eval q{ qr/[A\EB]/ };
    +    $misc_error = $@;
    +    eval q{ qr/\c1/ };
    +    $syntax_error = $@;
    +}
    +like($misc_error, qr/^Useless use of \\E/,
    +    q{no warnings 'regexp' retains fatal misc regex diagnostics});
    +like($syntax_error, qr/^"\\c1" is more clearly written simply as "q"/,
    +    q{no warnings 'regexp' retains fatal syntax regex diagnostics});
    +
    +my ($match_misc_error, $match_syntax_error);
    +{
    +    use warnings FATAL => 'all';
    +    no warnings 'regexp';
    +    eval q{ 'ABc' =~ m/[A\EB]c/ };
    +    $match_misc_error = $@;
    +    eval q{ 'q' =~ m/\c1/ };
    +    $match_syntax_error = $@;
    +}
    +like($match_misc_error, qr/^Useless use of \\E/,
    +    q{match use retains fatal misc diagnostics when regexp warnings are off});
    +like($match_syntax_error, qr/^"\\c1" is more clearly written simply as "q"/,
    +    q{match use retains fatal syntax diagnostics when regexp warnings are off});
    +
    +like(
    +    compile_error(q{qr/abc\N{def}/}),
    +    qr/^Unknown charname 'def'/,
    +    'unknown named character is diagnosed at regex compilation',
    +);
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/native_dynamic_pattern_contract.t b/src/test/resources/unit/regex/native_dynamic_pattern_contract.t
    new file mode 100644
    index 0000000000..9e19421fa3
    --- /dev/null
    +++ b/src/test/resources/unit/regex/native_dynamic_pattern_contract.t
    @@ -0,0 +1,72 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +
    +my $evaluations = 0;
    +ok('ab' =~ /^(??{ ++$evaluations; 'ab|a' })b$/,
    +    'nested alternatives backtrack into the outer suffix');
    +is($evaluations, 1, 'one dynamic entry retains its nested alternatives');
    +
    +my $repeat_count = 0;
    +ok('aa' =~ /^(?:(??{ ++$repeat_count; 'a' })){2}$/,
    +    'a quantified dynamic program executes at each entry');
    +is($repeat_count, 2, 'quantified dynamic expression is reevaluated');
    +
    +my ($seen_capture, $entry_pos);
    +ok('abc' =~ /^(a)(??{ $seen_capture = $1; $entry_pos = pos; '(b)' })(c)$/,
    +    'dynamic program sees provisional state and may contain captures');
    +is($seen_capture, 'a', 'dynamic expression sees the preceding outer capture');
    +is($entry_pos, 1, 'pos reports the dynamic entry offset');
    +is($1, 'a', 'outer capture before the dynamic program is preserved');
    +is($2, 'c', 'nested captures do not consume outer capture numbers');
    +
    +my $returned_qr = qr/b/i;
    +ok('aB' =~ /^a(??{ $returned_qr })$/,
    +    'dynamic expression accepts a compiled qr value');
    +ok(!('aB' =~ /^a(??{ qr{b} })$/i),
    +    'returned qr retains its own modifiers');
    +ok('aB' =~ /^a(??{ 'b' })$/i,
    +    'returned string inherits outer modifiers');
    +
    +my $seed;
    +ok('seed' =~ /^(?{ $seed = 'seed' })(??{ $^R })$/,
    +    'dynamic expression sees the prior callback result');
    +is($^R, 'seed', 'successful dynamic execution preserves callback result');
    +
    +my $failed_effects = 0;
    +ok(!('x' =~ /^(??{ ++$failed_effects; 'y' })$/),
    +    'a returned program may fail normally');
    +is($failed_effects, 1, 'ordinary dynamic side effects survive failure');
    +
    +my $unreached = 0;
    +ok('x' =~ /^x|y(??{ ++$unreached; 'z' })$/,
    +    'an earlier branch can bypass a dynamic program');
    +is($unreached, 0, 'an unreached dynamic expression is not executed');
    +
    +my $exception_ok = eval { 'x' =~ /^(??{ die "dynamic boom\n" })$/; 1 };
    +ok(!$exception_ok, 'dynamic exception aborts matching');
    +is($@, "dynamic boom\n", 'dynamic exception propagates unchanged');
    +
    +{
    +    no warnings 'uninitialized';
    +    ok('a' =~ /^a(??{ undef })$/, 'undef dynamic result is an empty pattern');
    +}
    +ok('a' =~ /^a(??{ '' })$/, 'empty dynamic result is an empty pattern');
    +
    +my $wide = "\x{100}";
    +ok($wide =~ /^(??{ $wide })$/u, 'Unicode dynamic source preserves its scalar');
    +{
    +    use bytes;
    +    my $octet = "\xE9";
    +    ok($octet =~ /^(??{ $octet })$/,
    +        'byte-mode dynamic source preserves its octet provenance');
    +}
    +
    +my $recursive;
    +$recursive = qr{ \( (?: [^()]+ | (??{ $recursive }) )* \) }x;
    +ok('(a(b)c)' =~ /^$recursive$/,
    +    'self-referential dynamic qr matches nested input');
    +ok(!('(a(b)' =~ /^$recursive$/),
    +    'self-referential dynamic qr still rejects unbalanced input');
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/native_escape_named_reference_diagnostics.t b/src/test/resources/unit/regex/native_escape_named_reference_diagnostics.t
    new file mode 100644
    index 0000000000..f189dee728
    --- /dev/null
    +++ b/src/test/resources/unit/regex/native_escape_named_reference_diagnostics.t
    @@ -0,0 +1,45 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +
    +for my $case (
    +    ['\c`', ' ', qr/^"\\c`" is more clearly written simply as "\\ "/],
    +    ['\c1', 'q', qr/^"\\c1" is more clearly written simply as "q"/],
    +) {
    +    my ($pattern, $subject, $expected) = @$case;
    +    my @warnings;
    +    my $compiled;
    +    {
    +        local $SIG{__WARN__} = sub { push @warnings, join '', @_ };
    +        $compiled = qr/$pattern/;
    +    }
    +    like(join('', @warnings), $expected, "$pattern has the Perl clarity warning");
    +    ok($subject =~ $compiled, "$pattern retains its Perl character value");
    +}
    +
    +for my $pattern (q{foo \k'n'}, q{foo \k}, q{foo \k'_0_'}, q{foo \k<_0_>}) {
    +    eval { qr/$pattern/ };
    +    like($@, qr/^Reference to nonexistent named group/,
    +        "$pattern reports a nonexistent named group");
    +}
    +
    +for my $pattern (q{foo \k'0'}, q{foo \k<12>}, q{foo \k'1a'}) {
    +    eval { qr/$pattern/ };
    +    like($@, qr/^Group name must start with a non-digit word character/,
    +        "$pattern rejects a digit-leading group name");
    +}
    +
    +my $brace_backref = q{(?as) (\w+) \k{ as } (\w+)};
    +ok('as easy as pie' =~ /$brace_backref/ && "$1-$2-$3" eq 'as-easy-pie',
    +    'brace named backreference trims surrounding whitespace');
    +
    +my $angle_space = q{(?as) (\w+) \k< as> (\w+)};
    +eval { qr/$angle_space/ };
    +like($@, qr/^Group name must start with a non-digit word character/,
    +    'angle named backreference rejects leading whitespace');
    +
    +my $g_backref = q{(?'n'foo) \g{ n }};
    +ok('..foo foo..' =~ /$g_backref/ && $1 eq 'foo',
    +    'g-brace named backreference trims surrounding whitespace');
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/native_extended_class_escape_diagnostic.t b/src/test/resources/unit/regex/native_extended_class_escape_diagnostic.t
    new file mode 100644
    index 0000000000..a8c3df0692
    --- /dev/null
    +++ b/src/test/resources/unit/regex/native_extended_class_escape_diagnostic.t
    @@ -0,0 +1,25 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +
    +sub compile_error {
    +    my ($pattern) = @_;
    +    local $@;
    +    eval { qr/$pattern/ };
    +    return $@;
    +}
    +
    +for my $escape ('8', 'y', 'z') {
    +    my $pattern = "(?[ \\$escape ])";
    +    my $error = compile_error($pattern);
    +    like($error, qr/^Unrecognized escape \\\Q$escape\E in character class in regex;/,
    +        "extended class reports unrecognized \\$escape");
    +}
    +
    +for my $pattern ('(?[ \\n ])', '(?[ [\\]] ])') {
    +    my $compiled = eval { qr/$pattern/ };
    +    ok($compiled, "$pattern retains its recognized escape")
    +        or diag($@);
    +}
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/native_extended_class_leaf_boundary.t b/src/test/resources/unit/regex/native_extended_class_leaf_boundary.t
    new file mode 100644
    index 0000000000..444e8c74b1
    --- /dev/null
    +++ b/src/test/resources/unit/regex/native_extended_class_leaf_boundary.t
    @@ -0,0 +1,15 @@
    +use strict;
    +use warnings;
    +use utf8;
    +use Test::More;
    +
    +for my $pattern ('ネ(?[[[:ネ: ])ネ', 'ï(?[[[:ï: ])ï') {
    +    my $compiled = eval { qr/$pattern/ };
    +    ok(!$compiled, "$pattern is rejected");
    +    like($@, qr/^Syntax error in \(\?\[\.\.\.\]\) in regex;/,
    +        "$pattern reports extended-class syntax");
    +    like($@, qr/\Q$pattern\E <-- HERE /,
    +        "$pattern marks the end of the malformed outer class");
    +}
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/native_grammar_diagnostic_positions.t b/src/test/resources/unit/regex/native_grammar_diagnostic_positions.t
    new file mode 100644
    index 0000000000..dda95dbce2
    --- /dev/null
    +++ b/src/test/resources/unit/regex/native_grammar_diagnostic_positions.t
    @@ -0,0 +1,31 @@
    +use strict;
    +use warnings;
    +no warnings 'experimental::regex_sets';
    +use Test::More tests => 20;
    +
    +sub compile_error {
    +    my ($source) = @_;
    +    eval "qr/$source/";
    +    return $@;
    +}
    +
    +my @cases = (
    +    ['(?(1x))', qr/^Switch condition not recognized.*\(\?\(1x\s+<-- HERE \)\)/s],
    +    ['(?(1)x|y|z)', qr/^Switch \(\?\(condition\)\.\.\. contains too many branches.*x\|y\|\s+<-- HERE z/s],
    +    ['\\x{100}(?(', qr/^Unknown switch condition \(\?\(\.\.\.\)\).*\(\?\(\s+<-- HERE/s],
    +    ['(?[a])', qr/^Unexpected character.*\(\?\[a\s+<-- HERE \]\)/s],
    +    ['(?[ \\cK \\t ])', qr/^Operand with no preceding operator.*\\cK \\t\s+<-- HERE  \]\)/s],
    +    ['(?[ \\p{Digit} & (?(?[ \\p{Thai} | \\p{Lao} ]))])',
    +     qr/^Unexpected character.*\\p\{Digit\} & \(\?\s+<-- HERE \(/s],
    +    ['\\x{ 1 ', qr/^Missing right brace on \\x\{\}.*\\x\{ 1\s+<-- HERE  /s],
    +    ['[\\x{ A ]', qr/^Missing right brace on \\x\{\}.*\[\\x\{ A\s+<-- HERE  \]/s],
    +    ['\\o{ 1 ', qr/^Missing right brace on \\o\{\}.*\\o\{ 1\s+<-- HERE  /s],
    +    ['[\\o{ 7 ]', qr/^Missing right brace on \\o\{\}.*\[\\o\{ 7\s+<-- HERE  \]/s],
    +);
    +
    +for my $case (@cases) {
    +    my ($source, $expected) = @$case;
    +    my $error = compile_error($source);
    +    ok(length($error), "$source is rejected");
    +    like($error, $expected, "$source preserves grammar diagnostic identity");
    +}
    diff --git a/src/test/resources/unit/regex/native_group_name_start_policy.t b/src/test/resources/unit/regex/native_group_name_start_policy.t
    new file mode 100644
    index 0000000000..fe934e998d
    --- /dev/null
    +++ b/src/test/resources/unit/regex/native_group_name_start_policy.t
    @@ -0,0 +1,21 @@
    +use strict;
    +use warnings;
    +use utf8;
    +use Test::More;
    +
    +for my $name ('_name', 'éname', 'Ⅳname') {
    +    my $pattern = "(?<$name>x)";
    +    my $compiled = eval { qr/$pattern/ };
    +    ok($compiled, "$name is a valid Perl group name start")
    +        or diag($@);
    +}
    +
    +for my $name ('‿name', "\x{301}name") {
    +    my $pattern = "(?<$name>x)";
    +    my $compiled = eval { qr/$pattern/ };
    +    ok(!$compiled, "$name is not a valid Perl group name start");
    +    like($@, qr/^Group name must start with a non-digit word character in regex;/,
    +        "$name reports the Perl group-name diagnostic");
    +}
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/native_invalid_range_diagnostic.t b/src/test/resources/unit/regex/native_invalid_range_diagnostic.t
    new file mode 100644
    index 0000000000..80683745b7
    --- /dev/null
    +++ b/src/test/resources/unit/regex/native_invalid_range_diagnostic.t
    @@ -0,0 +1,18 @@
    +use strict;
    +use warnings;
    +use utf8;
    +use Test::More;
    +
    +for my $case (
    +    [ '[z-a]',       'z-a',       '[z-a' ],
    +    [ '[ネ-a]ネ',    'ネ-a',      '[ネ-a' ],
    +) {
    +    my ($pattern, $range, $marked_prefix) = @$case;
    +    eval { qr/$pattern/ };
    +    my $error = $@;
    +    like($error,
    +        qr/^Invalid \[\] range "\Q$range\E" in regex; marked by <-- HERE in m\/\Q$marked_prefix\E <-- HERE /,
    +        "$pattern reports the range and marks its end");
    +}
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/native_named_character_diagnostics.t b/src/test/resources/unit/regex/native_named_character_diagnostics.t
    new file mode 100644
    index 0000000000..7946a6db18
    --- /dev/null
    +++ b/src/test/resources/unit/regex/native_named_character_diagnostics.t
    @@ -0,0 +1,43 @@
    +use strict;
    +use warnings;
    +use utf8;
    +use Test::More;
    +
    +my $outside = '\N{ U+0100 }';
    +ok("\x{100}" =~ /$outside/, 'spaced U+ resolves outside a class');
    +
    +my $inside = '[\N{ U+0100 }]';
    +ok("\x{100}" =~ /$inside/, 'spaced U+ resolves inside a class');
    +
    +my $non_newline_once = '\N {1}';
    +ok('ab' =~ /$non_newline_once/x,
    +    'extended whitespace before a non-newline quantifier compiles');
    +is($&, 'a', 'non-newline quantifier retains its match');
    +
    +my $non_newline_range = '\N {3,4}';
    +ok('abbbbc' =~ /$non_newline_range/x,
    +    'extended whitespace before a non-newline range compiles');
    +is($&, 'abbb', 'non-newline range retains its match');
    +
    +my @invalid = (
    +    ['abc\N{def}', '', qr/^Unknown charname 'def'/,
    +        'unknown name remains fatal with its name preserved'],
    +    ['abc\N {U+41}', 'x', qr/^Missing braces on \\N\{\}/,
    +        'space under x does not separate N from brace'],
    +    ['abc\N {SPACE}', 'x', qr/^Missing braces on \\N\{\}/,
    +        'named space under x reports missing braces'],
    +    ['\N(?#comment){SPACE}', '', qr/^Missing braces on \\N\{\}/,
    +        'comment between N and brace reports missing braces'],
    +);
    +
    +for my $case (@invalid) {
    +    my ($pattern, $modifiers, $expected, $label) = @$case;
    +    if ($modifiers eq 'x') {
    +        eval { qr/$pattern/x };
    +    } else {
    +        eval { qr/$pattern/ };
    +    }
    +    like($@, $expected, $label);
    +}
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/native_nested_quantifier_position.t b/src/test/resources/unit/regex/native_nested_quantifier_position.t
    new file mode 100644
    index 0000000000..dea559d4ba
    --- /dev/null
    +++ b/src/test/resources/unit/regex/native_nested_quantifier_position.t
    @@ -0,0 +1,24 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +
    +sub compile_error {
    +    my ($pattern) = @_;
    +    local $@;
    +    eval { qr/$pattern/ };
    +    return $@;
    +}
    +
    +for my $case (
    +    [ 'x**',    'x** <-- HERE ' ],
    +    [ "\x{30cd}**\x{30cd}", "\x{30cd}** <-- HERE \x{30cd}" ],
    +) {
    +    my ($pattern, $marked) = @$case;
    +    my $error = compile_error($pattern);
    +    like($error, qr/^Nested quantifiers in regex;/,
    +        "$pattern uses the Perl nested-quantifier diagnostic");
    +    like($error, qr/\Q$marked\E/,
    +        "$pattern marks immediately after the second quantifier");
    +}
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/native_numeric_backreference_boundaries.t b/src/test/resources/unit/regex/native_numeric_backreference_boundaries.t
    new file mode 100644
    index 0000000000..22d6b44f2b
    --- /dev/null
    +++ b/src/test/resources/unit/regex/native_numeric_backreference_boundaries.t
    @@ -0,0 +1,32 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +
    +for my $pattern (q{\87}, q{a\87}, q{a\97}) {
    +    my $compiled = eval "qr/$pattern/";
    +    like($@, qr/Reference to nonexistent group in regex/,
    +         "$pattern is a nonexistent decimal backreference");
    +}
    +
    +for my $digits (qw(2147483648 2147483649 2147483650
    +                   4294967296 4294967297 4294967298)) {
    +    for my $prefix ('', 'a') {
    +        for my $form ("\\g$digits}", "\\g{$digits}", "\\g{ $digits }") {
    +            my $compiled = eval "qr/${prefix}(.)$form/";
    +            like($@, qr/Reference to nonexistent group in regex/,
    +                 "$form rejects overflow safely after ${prefix}capture");
    +        }
    +    }
    +
    +    my ($octal, $tail) = $digits =~ /^([0-7]{1,3})(.*)$/;
    +    for my $prefix ('', 'a') {
    +        my $pattern = "${prefix}(.)\\$digits";
    +        my $compiled = eval "qr/$pattern/";
    +        ok(defined($compiled), "$pattern compiles as octal plus literal tail");
    +        my $subject = $prefix . 'b' . chr(oct($octal)) . $tail;
    +        ok($subject =~ $compiled && $1 eq 'b',
    +           "$pattern matches its octal boundary without integer overflow");
    +    }
    +}
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/native_policy_diagnostic_identity.t b/src/test/resources/unit/regex/native_policy_diagnostic_identity.t
    new file mode 100644
    index 0000000000..9bac5157ca
    --- /dev/null
    +++ b/src/test/resources/unit/regex/native_policy_diagnostic_identity.t
    @@ -0,0 +1,28 @@
    +use strict;
    +use warnings;
    +no warnings 'experimental::regex_sets';
    +use Test::More tests => 14;
    +
    +sub compile_error {
    +    my ($source) = @_;
    +    eval "qr/$source/";
    +    return $@;
    +}
    +
    +my @cases = (
    +    ['((?# comment)?:foo)', qr/^In '\(\?\.\.\.\)', the '\(' and '\?' must be adjacent.*\)\?\s+<-- HERE :foo/s],
    +    ['((?# comment)*FAIL)', qr/^In '\(\*VERB\.\.\.\)', the '\(' and '\*' must be adjacent.*\)\*\s+<-- HERE FAIL/s],
    +    ['((?# comment)*script_run:foo)', qr/^In '\(\*\.\.\.\)', the '\(' and '\*' must be adjacent.*\)\*\s+<-- HERE script_run/s],
    +    ["(?\x{e9})", qr/^Sequence \(\?\x{e9}\.\.\.\) not recognized.*\(\?\x{e9}\s+<-- HERE \)/s],
    +    ['(?[ \\p{Digit} & (?^(?[ \\p{Thai} | \\p{Lao} ]))])',
    +     qr/^Sequence \(\?\^\(\.\.\.\) not recognized.*\(\?\^\(\s+<-- HERE \?\[/s],
    +    ['(?[ \\xabcdef ])', qr/^Use \\x\{\.\.\.\} for more than two hex characters.*\\xabc\s+<-- HERE def/s],
    +    ['(?[ \\x{} ])', qr/^Empty \\x\{\}.*\\x\{\}\s+<-- HERE  \]\)/s],
    +);
    +
    +for my $case (@cases) {
    +    my ($source, $expected) = @$case;
    +    my $error = compile_error($source);
    +    ok(length($error), "$source is rejected");
    +    like($error, $expected, "$source preserves native policy identity");
    +}
    diff --git a/src/test/resources/unit/regex/no_utf8_pm_load.t b/src/test/resources/unit/regex/no_utf8_pm_load.t
    new file mode 100644
    index 0000000000..0cb06d9aca
    --- /dev/null
    +++ b/src/test/resources/unit/regex/no_utf8_pm_load.t
    @@ -0,0 +1,11 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 3;
    +
    +ok(!exists $INC{'utf8.pm'}, 'utf8 pragma is not reported loaded at startup');
    +
    +"\0" =~ /[\001-\xFF]/i;
    +ok(!exists $INC{'utf8.pm'}, 'Latin-1 case folding does not load utf8 pragma');
    +
    +require utf8;
    +ok(exists $INC{'utf8.pm'}, 'explicit require records utf8 pragma in INC');
    diff --git a/src/test/resources/unit/regex/non_octal_zero_warning_policy.t b/src/test/resources/unit/regex/non_octal_zero_warning_policy.t
    new file mode 100644
    index 0000000000..37b58c7198
    --- /dev/null
    +++ b/src/test/resources/unit/regex/non_octal_zero_warning_policy.t
    @@ -0,0 +1,32 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +
    +for my $case (
    +    [ '\\08',     '\\0008' ],
    +    [ '\\018',    '\\0018' ],
    +    [ '[\\08]',   '\\0008' ],
    +    [ '[\\018]',  '\\0018' ],
    +) {
    +    my ($pattern, $resolved) = @$case;
    +    my @warnings;
    +    {
    +        local $SIG{__WARN__} = sub { push @warnings, @_ };
    +        my $regex = eval { qr/$pattern/ };
    +        ok(defined($regex), "$pattern remains compilable");
    +    }
    +    is(scalar(@warnings), 1, "$pattern emits one warning");
    +    like($warnings[0],
    +        qr/^Non-octal character '8' terminates \\0 early\.  Resolved as "\Q$resolved\E" in regex; marked by <-- HERE/,
    +        "$pattern reports Perl's resolved escape");
    +}
    +
    +{
    +    no warnings 'regexp';
    +    local $SIG{__WARN__} = sub { fail('regexp warning suppression is honored') };
    +    my $pattern = '\\08';
    +    my $regex = eval { qr/$pattern/ };
    +    ok(defined($regex), 'suppressed non-octal warning leaves a valid regex');
    +}
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/nul_delimited_substitution_diagnostic.t b/src/test/resources/unit/regex/nul_delimited_substitution_diagnostic.t
    new file mode 100644
    index 0000000000..7bfff52ff6
    --- /dev/null
    +++ b/src/test/resources/unit/regex/nul_delimited_substitution_diagnostic.t
    @@ -0,0 +1,20 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 2;
    +
    +my $nul = "\0";
    +my $malformed = 'use warnings; s' . $nul
    +    . '0(?(?!00000000000000000000000000·000000)\500000000'
    +    . $nul
    +    . '0000000000000000000000000000000000000000000000000000'
    +    . '·00000000000000000000000000000000'
    +    . $nul
    +    . '0';
    +
    +eval $malformed;
    +like($@, qr/Switch \(\?\(condition\)\.\.\. not terminated/,
    +    'NUL-delimited substitution reaches the native pattern diagnostic');
    +
    +eval 'qr/a/0';
    +like($@, qr/Unknown regexp modifier "\/0"/,
    +    'numeric modifier on a valid pattern remains an error');
    diff --git a/src/test/resources/unit/regex/null_string_quantifier_warning.t b/src/test/resources/unit/regex/null_string_quantifier_warning.t
    new file mode 100644
    index 0000000000..801ddbce92
    --- /dev/null
    +++ b/src/test/resources/unit/regex/null_string_quantifier_warning.t
    @@ -0,0 +1,29 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 8;
    +
    +sub compile_warnings {
    +    my ($source) = @_;
    +    my @warnings;
    +    {
    +        local $SIG{__WARN__} = sub { push @warnings, @_ };
    +        my $compiled = eval "qr/$source/";
    +        ok($compiled, "$source compiles");
    +    }
    +    return @warnings;
    +}
    +
    +my @word_boundary = compile_warnings('\\b*');
    +is(scalar @word_boundary, 1, 'unbounded word boundary emits one warning');
    +like($word_boundary[0],
    +     qr/\\b\* matches null string many times.*m\/\\b\* <-- HERE \/ at/s,
    +     'word-boundary warning carries source and end position');
    +
    +my @lookahead = compile_warnings('(?=a)+');
    +is(scalar @lookahead, 1, 'unbounded lookahead emits one warning');
    +like($lookahead[0],
    +     qr/\(\?=a\)\+ matches null string many times.*\(\?=a\)\+ <-- HERE \/ at/s,
    +     'lookahead warning carries source and end position');
    +
    +my @bounded = compile_warnings('\\b?');
    +is(scalar @bounded, 0, 'bounded zero-width assertion remains quiet');
    diff --git a/src/test/resources/unit/regex/numeric_backreference_source_diagnostics.t b/src/test/resources/unit/regex/numeric_backreference_source_diagnostics.t
    new file mode 100644
    index 0000000000..bf59545ae8
    --- /dev/null
    +++ b/src/test/resources/unit/regex/numeric_backreference_source_diagnostics.t
    @@ -0,0 +1,41 @@
    +use strict;
    +use utf8;
    +use Test::More;
    +
    +sub compile_error {
    +    my ($source) = @_;
    +    local $@;
    +    eval $source;
    +    return $@;
    +}
    +
    +my @ascii = (
    +    [ q{/(x)\2/}, qr/Reference to nonexistent group.*m\/\(x\)\\2.*<-- HERE/ ],
    +    [ q{/\87/},   qr/Reference to nonexistent group.*m\/\\87.*<-- HERE/ ],
    +    [ q{/a\87/},  qr/Reference to nonexistent group.*m\/a\\87.*<-- HERE/ ],
    +    [ q{/a\97/},  qr/Reference to nonexistent group.*m\/a\\97.*<-- HERE/ ],
    +);
    +
    +for my $case (@ascii) {
    +    like(compile_error($case->[0]), $case->[1],
    +        "numeric backreference marker for $case->[0]");
    +    like(compile_error("use re 'strict'; $case->[0]"), $case->[1],
    +        "strict numeric backreference marker for $case->[0]");
    +}
    +
    +my $unicode = q{use utf8; /(ネ)\2ネ/};
    +my $unicode_expected = qr/Reference to nonexistent group.*m\/\(ネ\)\\2.*<-- HERE.*ネ/;
    +like(compile_error($unicode), $unicode_expected,
    +    'Unicode numeric backreference marker uses character offsets');
    +like(compile_error("use re 'strict'; $unicode"), $unicode_expected,
    +    'strict Unicode numeric backreference marker uses character offsets');
    +
    +my $byte = chr 0xef;
    +my $byte_source = q{my $b = chr 0xef; qr/($b)\2$b/};
    +my $byte_expected = qr/Reference to nonexistent group.*\\2.*<-- HERE/;
    +like(compile_error($byte_source), $byte_expected,
    +    'byte-backed interpolated numeric backreference has a marker');
    +like(compile_error("use re 'strict'; $byte_source"), $byte_expected,
    +    'strict byte-backed numeric backreference has a marker');
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/perl_backreference_casefold_closure.t b/src/test/resources/unit/regex/perl_backreference_casefold_closure.t
    new file mode 100644
    index 0000000000..9f19fcb111
    --- /dev/null
    +++ b/src/test/resources/unit/regex/perl_backreference_casefold_closure.t
    @@ -0,0 +1,14 @@
    +use strict;
    +use warnings;
    +use utf8;
    +use re '/u';
    +use Test::More;
    +
    +ok("\x{212A}K" =~ /\A(?\x{212A})\k\z/i,
    +   'named backreference folds Kelvin sign to K');
    +ok("\x{00C5}\x{212B}" =~ /\A(?\x{00C5})\k\z/i,
    +   'named backreference folds A-ring to Angstrom sign');
    +ok(!("\x{212A}K" =~ /\A(?aa:(?\x{212A})\k)\z/i),
    +   'ASCII-strict backreference rejects Kelvin to K');
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/perl_byte_class_fold_policy.t b/src/test/resources/unit/regex/perl_byte_class_fold_policy.t
    new file mode 100644
    index 0000000000..1bc1d8a116
    --- /dev/null
    +++ b/src/test/resources/unit/regex/perl_byte_class_fold_policy.t
    @@ -0,0 +1,75 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +no warnings 'experimental::regex_sets';
    +
    +my $byte_upper = chr 0xC0;
    +my $byte_lower = chr 0xE0;
    +my $byte_positive = qr/(?d:[$byte_lower\x{5f}])/i;
    +my $byte_negative = qr/(?d:[^$byte_lower])/i;
    +
    +ok($byte_upper !~ $byte_positive,
    +    'byte-backed default class does not fold Latin-1');
    +ok($byte_upper =~ $byte_negative,
    +    'byte-backed negated class keeps the Latin-1 sibling');
    +ok('A' =~ /(?d:[a_])/i,
    +    'byte-backed default class still folds ASCII');
    +ok('ss' !~ /(?d:[$byte_upper\x{DF}_])/i,
    +    'byte-backed default class does not expand a non-ASCII multi-fold');
    +ok($byte_upper =~ /(?d:\p{Lowercase})/i,
    +    'byte-backed Unicode property retains a Latin-1 simple fold');
    +ok($byte_upper =~ /(?d:[\p{Lowercase}_])/i,
    +    'composed byte-backed Unicode property retains a Latin-1 simple fold');
    +ok($byte_upper !~ /(?d:[^\p{Lowercase}])/i,
    +    'negated byte-backed Unicode property excludes its simple-fold sibling');
    +ok($byte_upper !~ /(?d:\P{Lowercase})/i,
    +    'complemented byte-backed Unicode property excludes its fold sibling');
    +ok($byte_upper !~ /(?d:[\P{Lowercase}_])/i,
    +    'composed complemented property excludes its fold sibling');
    +ok('ss' =~ /(?d:\p{Lowercase})/i,
    +    'byte-backed Unicode property retains a non-ASCII multi-fold');
    +
    +my $unicode_upper = chr 0xC0;
    +my $unicode_lower = chr 0xE0;
    +utf8::upgrade($unicode_upper);
    +utf8::upgrade($unicode_lower);
    +my $unicode_positive = qr/(?d:[$unicode_lower\x{5f}])/i;
    +my $unicode_negative = qr/(?d:[^$unicode_lower])/i;
    +
    +ok($unicode_upper =~ $unicode_positive,
    +    'upgraded default class folds Latin-1');
    +ok($unicode_upper !~ $unicode_negative,
    +    'upgraded negated class excludes the folded sibling');
    +ok('ss' =~ /(?d:[$unicode_upper\x{DF}_])/i,
    +    'upgraded default class retains a non-ASCII multi-fold');
    +
    +ok(chr(0xFF) =~ /(?d:[\x{178}_])/i,
    +    'an above-byte class promotes a byte subject to Unicode folding');
    +ok('K' =~ /(?d:[\x{212A}_])/i,
    +    'an above-byte class retains an ASCII-crossing Unicode fold');
    +
    +ok($byte_upper =~ /(?d:(?[ \p{Lowercase} + [_] ]))/i,
    +    'property union retains property fold provenance');
    +ok($byte_upper =~ /(?d:(?[ \p{Lowercase} & [\x{e0}] ]))/i,
    +    'property intersection retains surviving property provenance');
    +ok($byte_upper =~ /(?d:(?[ \p{Lowercase} - [a] ]))/i,
    +    'property subtraction retains surviving property provenance');
    +ok($byte_upper !~ /(?d:(?[ [\x{e0}] - \p{Uppercase} ]))/i,
    +    'literal subtraction does not inherit unrelated property provenance');
    +ok($byte_upper !~
    +        /(?d:(?[ ([\x{e0}] + \p{Uppercase}) - \p{Uppercase} ]))/i,
    +    'removed property source does not promote a surviving literal sibling');
    +ok($byte_upper =~ /(?d:(?[ \p{Lowercase} ^ [a] ]))/i,
    +    'property symmetric difference retains unrelated property provenance');
    +ok($byte_upper !~ /(?d:(?[ ! \p{Lowercase} ]))/i,
    +    'property complement excludes its folded sibling');
    +ok($byte_upper =~ /(?d:(?[ ! ! \p{Lowercase} ]))/i,
    +    'double property complement restores its folded sibling');
    +ok($byte_lower =~
    +        /(?d:(?[ ([\x{e0}] + \p{Hex_Digit}) - \p{Hex_Digit} ]))/i,
    +    'literal survives removal of disjoint property sources');
    +ok($byte_upper =~
    +        /(?d:(?[ ([\x{e0}] + \p{Hex_Digit}) - \p{Hex_Digit} ]))/i,
    +    'surviving extended-set literal keeps its Perl fold sibling');
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/perl_simple_casefold_closure.t b/src/test/resources/unit/regex/perl_simple_casefold_closure.t
    new file mode 100644
    index 0000000000..9fafd5455d
    --- /dev/null
    +++ b/src/test/resources/unit/regex/perl_simple_casefold_closure.t
    @@ -0,0 +1,19 @@
    +use strict;
    +use warnings;
    +use utf8;
    +use Test::More;
    +
    +ok("\x{212A}" =~ /\A(?d:k)\z/i,
    +    'default charset literal folds ASCII k to Kelvin sign');
    +ok("\x{212B}" =~ /\A(?u:\x{00e5})\z/i,
    +    'Unicode literal folds A-ring to Angstrom sign');
    +ok("\x{212A}K" =~ /\A(?a:kk)\z/i,
    +    'ASCII charset literal preserves Perl simple-class closure across a sequence');
    +ok("\x{212A}" =~ /\A(?d:[k])\z/i,
    +    'default charset character class folds ASCII k to Kelvin sign');
    +ok("\x{212A}" =~ /\A(?d:[K])\z/i,
    +    'default charset uppercase character class folds Kelvin sign');
    +ok("\x{212A}" !~ /\A(?aa:k)\z/i,
    +    'ASCII strict literal forbids the ASCII to non-ASCII crossing');
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/posix_literal_fallback.t b/src/test/resources/unit/regex/posix_literal_fallback.t
    new file mode 100644
    index 0000000000..ac3f9203d9
    --- /dev/null
    +++ b/src/test/resources/unit/regex/posix_literal_fallback.t
    @@ -0,0 +1,18 @@
    +use strict;
    +use warnings;
    +no warnings 'experimental::regex_sets';
    +use Test::More tests => 6;
    +
    +for my $source (
    +    q{qr/[[:w:]]/},
    +    q{qr/[[:FOO:]]/},
    +    q{qr/(?[[:w:]])/},
    +) {
    +    my @warnings;
    +    {
    +        local $SIG{__WARN__} = sub { push @warnings, @_ };
    +        eval $source;
    +    }
    +    is($@, '', "$source compiles as literal class text");
    +    is_deeply(\@warnings, [], "$source compiles without POSIX diagnostics");
    +}
    diff --git a/src/test/resources/unit/regex/posix_outside_class_warning.t b/src/test/resources/unit/regex/posix_outside_class_warning.t
    new file mode 100644
    index 0000000000..4fd046c12f
    --- /dev/null
    +++ b/src/test/resources/unit/regex/posix_outside_class_warning.t
    @@ -0,0 +1,25 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 8;
    +
    +for my $case (
    +    [ '[:alpha:]', 'a', qr/POSIX syntax \[: :] belongs inside character classes in regex/,
    +      'valid POSIX spelling' ],
    +    [ '[:zog:]', 'z', qr/POSIX syntax \[: :] belongs inside character classes \(but this one isn't fully valid\) in regex/,
    +      'invalid POSIX spelling' ],
    +    [ '[.zog.]', 'z', qr/POSIX syntax \[\. \.\] belongs inside character classes \(but this one isn't implemented\) in regex/,
    +      'unimplemented collating spelling' ],
    +    [ '[=zog=]', 'z', qr/POSIX syntax \[= =\] belongs inside character classes \(but this one isn't implemented\) in regex/,
    +      'unimplemented equivalence spelling' ],
    +) {
    +    my ($source, $subject, $warning, $label) = @$case;
    +    my @warnings;
    +    my $compiled;
    +    {
    +        local $SIG{__WARN__} = sub { push @warnings, @_ };
    +        $compiled = eval "qr/$source/";
    +    }
    +    like(join('', @warnings), $warning, "$label warns at construction");
    +    ok(defined($compiled) && $subject =~ $compiled,
    +       "$label retains ordinary character-class semantics");
    +}
    diff --git a/src/test/resources/unit/regex/posix_reserved_syntax.t b/src/test/resources/unit/regex/posix_reserved_syntax.t
    new file mode 100644
    index 0000000000..9f9f7d9f1f
    --- /dev/null
    +++ b/src/test/resources/unit/regex/posix_reserved_syntax.t
    @@ -0,0 +1,80 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +
    +sub compile_result {
    +    my ($source) = @_;
    +    my @warnings;
    +    local $SIG{__WARN__} = sub { push @warnings, @_ };
    +    my $rx = eval "qr/$source/";
    +    return ($rx, $@, join '', @warnings);
    +}
    +
    +sub compile_error {
    +    my ($source) = @_;
    +    my (undef, $error) = compile_result($source);
    +    return $error;
    +}
    +
    +ok('A' =~ /[[:alpha:]]/, 'named POSIX class remains valid');
    +ok('7' !~ /[[:alpha:]]/, 'named POSIX class retains membership');
    +
    +like(
    +    compile_error('[[=foo=]]'),
    +    qr/POSIX syntax \[= =\] is reserved for future extensions/,
    +    'equivalence-class POSIX syntax is reserved',
    +);
    +like(
    +    compile_error('[[=foo=]]'),
    +    qr/marked by.*\[\[=foo=\]/s,
    +    'reserved equivalence diagnostic identifies its source',
    +);
    +like(
    +    compile_error('[[.foo.]]'),
    +    qr/POSIX syntax \[\. \.\] is reserved for future extensions/,
    +    'collating-element POSIX syntax is reserved',
    +);
    +like(
    +    compile_error('[[.foo.]]'),
    +    qr/marked by.*\[\[\.foo\.\]/s,
    +    'reserved collating diagnostic identifies its source',
    +);
    +like(
    +    compile_error('[[=alpha=]]'),
    +    qr/POSIX syntax \[= =\] is reserved for future extensions/,
    +    'reserved equivalence syntax is independent of the name',
    +);
    +like(
    +    compile_error('[[.alpha.]]'),
    +    qr/POSIX syntax \[\. \.\] is reserved for future extensions/,
    +    'reserved collating syntax is independent of the name',
    +);
    +
    +like(
    +    compile_error('[[:barf:]]'),
    +    qr/POSIX class \[:barf:\] unknown/,
    +    'unknown named POSIX class remains distinct from reserved syntax',
    +);
    +
    +for my $literal ('[[=]]', '[[=fo\\=o=]]', '[[.fo\\.o.]]') {
    +    my ($rx, $error, $warnings) = compile_result($literal);
    +    ok(defined($rx), "$literal remains ordinary class syntax");
    +    is($error, '', "$literal has no fatal POSIX diagnostic");
    +    is($warnings, '', "$literal has no POSIX warning");
    +}
    +
    +my $unicode_error = eval q{use utf8; qr/[[=foo=]]/; 1} ? '' : $@;
    +like(
    +    $unicode_error,
    +    qr/POSIX syntax \[= =\] is reserved for future extensions/,
    +    'reserved syntax is recognized in UTF-8 source',
    +);
    +
    +my $byte_error = eval q{use bytes; qr/[[.foo.]]/; 1} ? '' : $@;
    +like(
    +    $byte_error,
    +    qr/POSIX syntax \[\. \.\] is reserved for future extensions/,
    +    'reserved syntax is recognized in byte source',
    +);
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/property_spaced_caret.t b/src/test/resources/unit/regex/property_spaced_caret.t
    new file mode 100644
    index 0000000000..1cfad18c8d
    --- /dev/null
    +++ b/src/test/resources/unit/regex/property_spaced_caret.t
    @@ -0,0 +1,15 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 4;
    +
    +my $inside = "\x{80}";
    +my $outside = 'A';
    +
    +ok($outside =~ /\p{  ^  In Latin 1 Supplement  }/,
    +   'inner caret negates a positive property after whitespace');
    +ok($inside =~ /\P{  ^  In Latin 1 Supplement  }/,
    +   'outer P and inner caret cancel after whitespace');
    +ok($outside =~ /\p{  ^  In Latin 1 Supplement  }/i,
    +   'spaced inner caret is preserved under case folding');
    +ok($outside =~ /[\p{  ^  In Latin 1 Supplement  }]/,
    +   'spaced inner caret works inside a character class');
    diff --git a/src/test/resources/unit/regex/quantifier_warning_positions.t b/src/test/resources/unit/regex/quantifier_warning_positions.t
    new file mode 100644
    index 0000000000..b22212304a
    --- /dev/null
    +++ b/src/test/resources/unit/regex/quantifier_warning_positions.t
    @@ -0,0 +1,33 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 8;
    +
    +my @warnings;
    +{
    +    local $SIG{__WARN__} = sub { push @warnings, @_ };
    +    eval q{qr/x{3,1}/};
    +}
    +is($@, '', 'descending interval remains a nonfatal pattern');
    +is(scalar @warnings, 1, 'descending interval warns once');
    +like($warnings[0],
    +    qr/^Quantifier \{n,m\} with n > m can't match in regex; marked by <-- HERE in m\/x\{3,1\} <-- HERE \//,
    +    'descending interval warning points after the quantifier');
    +
    +@warnings = ();
    +{
    +    local $SIG{__WARN__} = sub { push @warnings, @_ };
    +    eval q{qr/a{1,1}?/};
    +}
    +is($@, '', 'fixed non-greedy interval remains a valid pattern');
    +is(scalar @warnings, 1, 'fixed non-greedy interval warns once');
    +like($warnings[0],
    +    qr/^Useless use of greediness modifier '\?' in regex; marked by <-- HERE in m\/a\{1,1\}\? <-- HERE \//,
    +    'fixed non-greedy warning points after the modifier');
    +
    +@warnings = ();
    +{
    +    local $SIG{__WARN__} = sub { push @warnings, @_ };
    +    eval q{qr/a{1,2}?/};
    +}
    +is($@, '', 'variable non-greedy interval remains valid');
    +is_deeply(\@warnings, [], 'variable non-greedy interval remains useful and silent');
    diff --git a/src/test/resources/unit/regex/re_debug_named_options.t b/src/test/resources/unit/regex/re_debug_named_options.t
    new file mode 100644
    index 0000000000..e4f96d64f7
    --- /dev/null
    +++ b/src/test/resources/unit/regex/re_debug_named_options.t
    @@ -0,0 +1,17 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 2;
    +
    +{
    +    use re Debug => 'ALL';
    +    my $regex = qr/phase36_named_debug_option/;
    +    ok('phase36_named_debug_option' =~ $regex,
    +       q{Debug => 'ALL' preserves ordinary matching});
    +}
    +
    +{
    +    no re Debug => 'ALL';
    +    my $regex = qr/phase36_named_debug_disabled/;
    +    ok('phase36_named_debug_disabled' =~ $regex,
    +       q{no re Debug => 'ALL' preserves ordinary matching});
    +}
    diff --git a/src/test/resources/unit/regex/re_optimization_introspection.t b/src/test/resources/unit/regex/re_optimization_introspection.t
    new file mode 100644
    index 0000000000..e4b7742207
    --- /dev/null
    +++ b/src/test/resources/unit/regex/re_optimization_introspection.t
    @@ -0,0 +1,29 @@
    +use strict;
    +use warnings;
    +use re ();
    +use Test::More;
    +
    +my $exact = re::optimization(qr/abc/);
    +is(ref($exact), 'HASH', 'optimization returns a hash reference');
    +is($exact->{minlen}, 3, 'exact minimum length');
    +is($exact->{minlenret}, 3, 'returned minimum length');
    +is($exact->{anchored}, 'abc', 'fixed-offset exact string is anchored');
    +is($exact->{'anchored min offset'}, 0, 'anchored offset');
    +is($exact->{checking}, 'anchored', 'anchored string is checked');
    +is($exact->{isall}, 1, 'plain exact pattern is entirely optimized');
    +is(re::optimization(qr/a()bc/)->{isall}, 0,
    +    'capture op prevents an all-exact optimization');
    +
    +my $floating = re::optimization(qr/x?abc/);
    +is($floating->{minlen}, 3, 'optional prefix does not raise minimum length');
    +is($floating->{floating}, 'abc', 'variable-offset exact string is floating');
    +is($floating->{'floating min offset'}, 0, 'floating minimum offset');
    +is($floating->{'floating max offset'}, 1, 'floating maximum offset');
    +is($floating->{checking}, 'floating', 'floating string is checked');
    +
    +my $empty = re::optimization(qr//);
    +is($empty->{minlen}, 0, 'empty pattern minimum length');
    +is($empty->{checking}, 'none', 'empty pattern has no exact check');
    +ok(!defined(re::optimization('abc')), 'non-regex input returns undef');
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/recursive_dynamic_escaped_charclass.t b/src/test/resources/unit/regex/recursive_dynamic_escaped_charclass.t
    new file mode 100644
    index 0000000000..b4d3444bb7
    --- /dev/null
    +++ b/src/test/resources/unit/regex/recursive_dynamic_escaped_charclass.t
    @@ -0,0 +1,14 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 2;
    +use re 'eval';
    +
    +our @recursive;
    +my $dynamic = '(??{$main::recursive [1]})';
    +my $compiled = qr/\((?:(?>[^\(\)]+)|$dynamic)*\)/;
    +$main::recursive[1] = $compiled;
    +
    +ok('((text))' =~ /\A$compiled\z/,
    +    'escaped first character-class member does not hide a dynamic callback');
    +ok('(text)' =~ /\A$compiled\z/,
    +    'recursive dynamic regexp still matches a non-nested value');
    diff --git a/src/test/resources/unit/regex/recursive_lookbehind_prevalidation.t b/src/test/resources/unit/regex/recursive_lookbehind_prevalidation.t
    new file mode 100644
    index 0000000000..96c12a0c33
    --- /dev/null
    +++ b/src/test/resources/unit/regex/recursive_lookbehind_prevalidation.t
    @@ -0,0 +1,18 @@
    +use strict;
    +use warnings;
    +no warnings 'experimental::vlb';
    +use Test::More;
    +
    +my $recursive = 'aa';
    +ok($recursive =~ /(?a)(?(?=(?&W))(?<=(?&W)))(?&BB)/,
    +    'native recursive subpattern determines lookbehind width');
    +is($&, 'a',
    +    'recursive lookbehind publishes the expected whole match');
    +
    +my $error = '';
    +eval q{qr/(?a{256})(?<=(?&WIDE))/};
    +$error = $@;
    +like($error, qr/^Lookbehind longer than 255 not implemented in regex/,
    +    'native recursive lookbehind still enforces the width ceiling');
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/regex_compile_diagnostic_identity.t b/src/test/resources/unit/regex/regex_compile_diagnostic_identity.t
    new file mode 100644
    index 0000000000..fdda345aa1
    --- /dev/null
    +++ b/src/test/resources/unit/regex/regex_compile_diagnostic_identity.t
    @@ -0,0 +1,17 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 4;
    +
    +my $single_quote_source = q{qr'abc} . chr(92) . q{N{def}'};
    +eval $single_quote_source;
    +like($@,
    +     qr/^Unknown charname 'def' in regex/,
    +     'apostrophe-delimited regex defers unknown charname to regex compilation');
    +unlike($@, qr/within pattern/,
    +       'apostrophe-delimited diagnostic does not claim interpolating source');
    +
    +eval q{qr/(?<%)b/};
    +like($@, qr/^Group name must start with a non-digit word character in regex;/,
    +     'invalid named-capture first character keeps the corpus wording');
    +like($@, qr/m\/\(\?<% <-- HERE \)b\//,
    +     'unterminated named capture marks the invalid first character');
    diff --git a/src/test/resources/unit/regex/regex_literal_callback_escape_parity.t b/src/test/resources/unit/regex/regex_literal_callback_escape_parity.t
    new file mode 100644
    index 0000000000..a9a5784d66
    --- /dev/null
    +++ b/src/test/resources/unit/regex/regex_literal_callback_escape_parity.t
    @@ -0,0 +1,36 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +
    +ok('ab[1c' =~ m'ab\[(??{1})c',
    +    'one backslash leaves a callback outside an escaped opening bracket');
    +
    +ok('ab\\[1c' =~ m'ab\\\[(??{1})c',
    +    'three backslashes leave a callback outside an escaped opening bracket');
    +
    +ok("ab\\;c" =~ m'ab\\[(??{1;})]c',
    +    'two backslashes leave callback-looking text inside a class');
    +
    +ok("ab\\\\1c" =~ m'ab\\\\[(??{1})]c',
    +    'four backslashes preserve even parity before a character class');
    +
    +ok(']1' =~ m'[a\]](??{1})',
    +    'escaped class close is followed by an active callback after the real close');
    +
    +ok('ab2' =~ m'ab[(?{1\](?{2]',
    +    'callback-looking text after an escaped close remains inside a class');
    +
    +ok('ab[1c' =~ m'ab\[(??{1}) c'x,
    +    'escaped opening bracket preserves callback extraction under /x');
    +
    +ok('a#' =~ m{
    +    a\#(??{q{}})
    +}x,
    +    'escaped hash under /x does not turn the following callback into a comment');
    +
    +ok('a' =~ m{
    +    a # (??{ die "comment callback executed" })
    +}x,
    +    'an unescaped hash under /x still hides callback-looking comment text');
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/regex_strict_default_warning_cache.t b/src/test/resources/unit/regex/regex_strict_default_warning_cache.t
    new file mode 100644
    index 0000000000..6cb75abb87
    --- /dev/null
    +++ b/src/test/resources/unit/regex/regex_strict_default_warning_cache.t
    @@ -0,0 +1,37 @@
    +use strict;
    +use Test::More;
    +
    +sub captured_eval {
    +    my ($source) = @_;
    +    my @warnings;
    +    local $^W;
    +    local $SIG{__WARN__} = sub { push @warnings, @_ };
    +    my $result = eval $source;
    +    return ($result, $@, join('', @warnings));
    +}
    +
    +my $pattern = q{/(?c)\x{100}/};
    +my $strict = q{no warnings 'experimental::re_strict'; use re 'strict'; };
    +
    +my (undef, $suppressed_error, $suppressed_warning) =
    +    captured_eval("$strict no warnings 'regexp'; $pattern");
    +is($suppressed_error, '',
    +    'strict regex compiles when its ordinary warning is disabled');
    +is($suppressed_warning, '',
    +    'an explicit no warnings regexp scope suppresses the strict warning');
    +
    +my (undef, $default_error, $default_warning) =
    +    captured_eval("$strict $pattern");
    +is($default_error, '',
    +    'the same strict regex compiles after the suppressed cache warmup');
    +like($default_warning, qr/Useless \(\?c\)/,
    +    're strict enables its warning by default after cache reuse');
    +
    +my (undef, $suppressed_again_error, $suppressed_again_warning) =
    +    captured_eval("$strict no warnings 'regexp'; $pattern");
    +is($suppressed_again_error, '',
    +    'the cached strict regex remains usable in a later suppressed scope');
    +is($suppressed_again_warning, '',
    +    'cached default-on warnings still honor explicit suppression');
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/regexp_destroy_lifecycle.t b/src/test/resources/unit/regex/regexp_destroy_lifecycle.t
    new file mode 100644
    index 0000000000..62c0f1fd67
    --- /dev/null
    +++ b/src/test/resources/unit/regex/regexp_destroy_lifecycle.t
    @@ -0,0 +1,29 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 3;
    +
    +BEGIN { undef &Regexp::DESTROY }
    +
    +my $destroyed = 0;
    +{
    +    no warnings 'redefine';
    +    sub Regexp::DESTROY { $destroyed++ }
    +}
    +
    +{
    +    my $rx = qr//;
    +}
    +is($destroyed, 1, 'plain qr object invokes Regexp::DESTROY at scope exit');
    +
    +{
    +    my $captured = bless {}, 'RegexDestroyCapture';
    +    my $rx = qr/(?{ $captured })/;
    +}
    +is($destroyed, 2,
    +    'callback-bearing qr object invokes Regexp::DESTROY at scope exit');
    +
    +{
    +    my $source = bless qr/x/, 'RegexDestroySubclass';
    +    my $rx = qr/$source/i;
    +    is(ref($rx), 'Regexp', 'new qr wrapper uses the implicit Regexp class');
    +}
    diff --git a/src/test/resources/unit/regex/remaining_native_diagnostic_identity.t b/src/test/resources/unit/regex/remaining_native_diagnostic_identity.t
    new file mode 100644
    index 0000000000..f1182421a7
    --- /dev/null
    +++ b/src/test/resources/unit/regex/remaining_native_diagnostic_identity.t
    @@ -0,0 +1,30 @@
    +use strict;
    +use warnings;
    +no warnings 'experimental::regex_sets';
    +use Test::More tests => 20;
    +
    +sub compile_error {
    +    my ($source) = @_;
    +    eval "qr/$source/";
    +    return $@;
    +}
    +
    +my @cases = (
    +    ['\\p{x', qr/^Missing right brace on \\p\{\}.*\\p\{\s+<-- HERE x/s],
    +    ['[\\P{x]', qr/^Missing right brace on \\P\{\}.*\[\\P\{\s+<-- HERE x\]/s],
    +    ["\\c\x{100}", qr/^Character following "\\c" must be printable ASCII.*\\c\x{100}\s+<-- HERE/s],
    +    ['(?[ \\cK + ])', qr/^Incomplete expression within '\(\?\[ \]\)'.*\\cK \+\s+<-- HERE \]\)/s],
    +    ['(?[ ( ) ])', qr/^Incomplete expression within '\(\?\[ \]\)'.*\( \)\s+<-- HERE/s],
    +    ['(?[ \\t ]', qr/^Unexpected '\]' with no following '\)' in \(\?\[\.\.\..*\\t \]\s+<-- HERE/s],
    +    ['(?[ \\05 ])', qr/^Need exactly 3 octal digits.*\\05\s+<-- HERE \]\)/s],
    +    ['(?[[[:w:]]])', qr/^Unexpected '\]' with no following '\)' in \(\?\[\.\.\..*\[\[:w:\]\]\s+<-- HERE \]\)/s],
    +    ['(?[ [ \\t ]', qr/^Syntax error in \(\?\[\.\.\.\]\).*\[ \\t \]\s+<-- HERE/s],
    +    ['(?[ \\t + \\e # comment ])', qr/^Syntax error in \(\?\[\.\.\.\]\).*# comment \]\)\s+<-- HERE/s],
    +);
    +
    +for my $case (@cases) {
    +    my ($source, $expected) = @$case;
    +    my $error = compile_error($source);
    +    ok(length($error), "$source is rejected");
    +    like($error, $expected, "$source preserves diagnostic identity");
    +}
    diff --git a/src/test/resources/unit/regex/repeat_capture_condition_previous.t b/src/test/resources/unit/regex/repeat_capture_condition_previous.t
    new file mode 100644
    index 0000000000..6a0b0b5308
    --- /dev/null
    +++ b/src/test/resources/unit/regex/repeat_capture_condition_previous.t
    @@ -0,0 +1,9 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +
    +ok('baaa' =~ /((?(1)a|b))+/, 'repeated capture condition matches');
    +is($&, $] >= 5.037010 ? 'baaa' : 'b',
    +    'condition sees the preceding iteration while its capture is open');
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/repeat_self_backref_previous.t b/src/test/resources/unit/regex/repeat_self_backref_previous.t
    new file mode 100644
    index 0000000000..98a2efb143
    --- /dev/null
    +++ b/src/test/resources/unit/regex/repeat_self_backref_previous.t
    @@ -0,0 +1,26 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 8;
    +
    +ok('aaaaaaaaaa' =~ /^(a\1?){4}$/,
    +    'optional self-backref sees the prior repeat iteration');
    +is($1, 'aaaa', 'optional self-backref publishes the final capture');
    +
    +ok('aaaaaaaaaa' =~ /^(a(?(1)\1)){4}$/,
    +    'conditional self-backref sees the prior repeat iteration');
    +is($1, 'aaaa', 'conditional self-backref publishes the final capture');
    +
    +ok('aaaaaa' =~ /^(a\1?){4}$/,
    +    'optional self-backref can consume a shorter prior capture');
    +is($1, 'aa', 'shorter self-backref publishes the final capture');
    +
    +my $simple_alt = 'xa=xaaa' =~ /^(xa|=?\1a){2}$/;
    +my $nested_alt = 'xa=xaaa' =~ /^(xa|(?:=|zzzz|)\1a){2}$/;
    +if ($] < 5.037010) {
    +    ok($simple_alt, 'legacy Perl retains self-capture across an alternative');
    +    ok($nested_alt, 'legacy Perl retains self-capture across nested alternatives');
    +}
    +else {
    +    ok(!$simple_alt, 'ordinary alternative invalidates the prior self-capture');
    +    ok(!$nested_alt, 'nested alternative keeps the prior self-capture invalid');
    +}
    diff --git a/src/test/resources/unit/regex/runtime_callback_diagnostics.t b/src/test/resources/unit/regex/runtime_callback_diagnostics.t
    new file mode 100644
    index 0000000000..1537514506
    --- /dev/null
    +++ b/src/test/resources/unit/regex/runtime_callback_diagnostics.t
    @@ -0,0 +1,26 @@
    +use strict;
    +use warnings;
    +use re 'eval';
    +
    +print "1..4\n";
    +
    +my @cases = (
    +    [q!qr'a(?{f()+'!, qr/^Missing right curly or square bracket/,
    +        'unterminated callback expression reports its missing brace'],
    +    [q!qr'a(?{{1}+'!, qr/^Missing right curly or square bracket/,
    +        'unterminated nested callback block reports its missing brace'],
    +    [q!qr' (?{(^{})'!, qr/^syntax error/,
    +        'an earlier callback expression error wins over structural EOF'],
    +    [q!qr'a(?{"{"}})b'!, qr/^Sequence \(\?\{\.\.\.\}\) not terminated with '\)'/,
    +        'extra callback brace reports the missing group terminator'],
    +);
    +
    +my $number = 0;
    +for my $case (@cases) {
    +    my ($source, $expected, $name) = @$case;
    +    eval $source;
    +    ++$number;
    +    print $@ =~ $expected
    +        ? "ok $number - $name\n"
    +        : "not ok $number - $name: $@\n";
    +}
    diff --git a/src/test/resources/unit/regex/runtime_source_internal_context.t b/src/test/resources/unit/regex/runtime_source_internal_context.t
    new file mode 100644
    index 0000000000..26c911f68e
    --- /dev/null
    +++ b/src/test/resources/unit/regex/runtime_source_internal_context.t
    @@ -0,0 +1,42 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +
    +our $strict_calls;
    +our $delimiter_calls;
    +
    +{
    +    use re 'eval';
    +
    +    for my $backslashes (0 .. 3) {
    +        $delimiter_calls = 0;
    +        my $runtime = ('\\' x $backslashes)
    +            . '~(?{ ++$main::delimiter_calls })';
    +        my $subject = ('\\' x int($backslashes / 2)) . '~';
    +        my $matched = eval { $subject =~ /^$runtime$/ };
    +        is($@, '',
    +            "delimiter case $backslashes has no synthetic-source error");
    +        ok($matched,
    +            "runtime source preserves $backslashes backslashes before delimiter");
    +        is($delimiter_calls, 1,
    +            "callback after delimiter case $backslashes executes once");
    +    }
    +}
    +
    +{
    +    no warnings 'experimental::re_strict';
    +    use re 'strict';
    +    use re 'eval';
    +
    +    $strict_calls = 0;
    +    my $runtime = '(?{ ++$main::strict_calls })';
    +    my $matched = eval { '' =~ /^$runtime$/ };
    +    is($@, '',
    +        'runtime callback has no synthetic-source error under lexical re strict');
    +    ok($matched,
    +        'runtime callback compiles under lexical re strict');
    +    is($strict_calls, 1,
    +        'private re strict state does not enter executable source text');
    +}
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/scoped_unicode_byte_folds.t b/src/test/resources/unit/regex/scoped_unicode_byte_folds.t
    new file mode 100644
    index 0000000000..65fc8409b3
    --- /dev/null
    +++ b/src/test/resources/unit/regex/scoped_unicode_byte_folds.t
    @@ -0,0 +1,33 @@
    +use strict;
    +use warnings;
    +use utf8;
    +use Test::More;
    +
    +my $upper = chr 0xC0;
    +my $lower = chr 0xE0;
    +my $upper_bytes = $upper;
    +my $lower_bytes = $lower;
    +utf8::downgrade($upper_bytes);
    +utf8::downgrade($lower_bytes);
    +my $upper_utf8 = $upper;
    +my $lower_utf8 = $lower;
    +utf8::upgrade($upper_utf8);
    +utf8::upgrade($lower_utf8);
    +
    +ok($lower_bytes =~ qr/(?u:\xC0)/i, 'scoped u folds byte-source C0 forward');
    +ok($upper_bytes =~ qr/(?u:\xE0)/i, 'scoped u folds byte-source E0 reverse');
    +ok($lower_utf8 =~ qr/(?u:\xC0)/i, 'scoped u folds UTF-8 subject forward');
    +ok($upper_utf8 =~ qr/(?u:\xE0)/i, 'scoped u folds UTF-8 subject reverse');
    +ok($lower_bytes =~ qr/\xC0/iu, 'top-level u folds byte-source C0');
    +ok($upper_bytes =~ qr/\xE0/iu, 'top-level u folds byte-source E0');
    +
    +ok($lower_bytes !~ qr/(?d:\xC0)/i, 'scoped d keeps Latin-1 byte fold disabled');
    +ok($lower_bytes =~ qr/(?a:\xC0)/i, 'scoped a retains Latin-1 byte folding');
    +ok($lower_bytes =~ qr/(?aa:\xC0)/i, 'scoped aa retains Latin-1 byte folding');
    +
    +ok(chr(0xD7) =~ qr/(?u:\xD7)/i, 'multiplication sign remains literal under u fold');
    +ok(chr(0xF7) =~ qr/(?u:\xF7)/i, 'division sign remains literal under u fold');
    +ok(chr(0xD7) !~ qr/(?u:\xF7)/i, 'D7 and F7 do not fold together');
    +ok(chr(0xDF) =~ qr/(?u:\xDF)/i, 'sharp s remains a direct scalar match');
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/strict_character_class_range_warning.t b/src/test/resources/unit/regex/strict_character_class_range_warning.t
    new file mode 100644
    index 0000000000..d0825fce1f
    --- /dev/null
    +++ b/src/test/resources/unit/regex/strict_character_class_range_warning.t
    @@ -0,0 +1,38 @@
    +use strict;
    +use warnings;
    +no warnings 'experimental::regex_sets';
    +use Test::More tests => 15;
    +
    +sub compile_warnings {
    +    my ($source) = @_;
    +    my @warnings;
    +    my $compiled;
    +    {
    +        local $SIG{__WARN__} = sub { push @warnings, @_ };
    +        $compiled = eval "qr/$source/";
    +    }
    +    ok($compiled, "$source compiles");
    +    return @warnings;
    +}
    +
    +my @cases = (
    +    ['(?[ [ A-a ] ])',
    +     qr/Ranges of ASCII printables should be some subset of "0-9", "A-Z", or "a-z".*A-a\s+<-- HERE/s],
    +    ["(?[ [ \x{1a89}-\x{1a90} ] ])",
    +     qr/Ranges of digits should be from the same group of 10.*\x{1a89}-\x{1a90}\s+<-- HERE/s],
    +    ['(?[ [ \N{U+00}-\x01 ] ])',
    +     qr/Both or neither range ends should be Unicode.*\\N\{U\+00\}-\\x01\s+<-- HERE/s],
    +);
    +
    +for my $case (@cases) {
    +    my ($source, $expected) = @$case;
    +    my @warnings = compile_warnings($source);
    +    is(scalar @warnings, 1, "$source emits one range warning");
    +    like($warnings[0], $expected, "$source reports the warning at its endpoint");
    +}
    +
    +for my $source ('(?[ [ A-Z ] ])', '(?[ [ % - % ] ])',
    +                "(?[ [ \x{1a80}-\x{1a89} ] ])") {
    +    my @warnings = compile_warnings($source);
    +    is(scalar @warnings, 0, "$source is a canonical quiet range");
    +}
    diff --git a/src/test/resources/unit/regex/strict_literal_warnings.t b/src/test/resources/unit/regex/strict_literal_warnings.t
    new file mode 100644
    index 0000000000..0a3c49ca4f
    --- /dev/null
    +++ b/src/test/resources/unit/regex/strict_literal_warnings.t
    @@ -0,0 +1,14 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 6;
    +
    +for my $pattern (q!\b 24;
    +
    +sub compile_warnings {
    +    my ($source) = @_;
    +    my @warnings;
    +    my $compiled;
    +    {
    +        local $SIG{__WARN__} = sub { push @warnings, @_ };
    +        $compiled = eval "no warnings 'experimental::re_strict'; "
    +                       . "use re 'strict'; qr/$source/";
    +    }
    +    ok(defined $compiled, "$source compiles under re strict");
    +    return @warnings;
    +}
    +
    +for my $source (
    +    q{[\N{U+00}-\x01]},
    +    q{[\x00-\N{SOH}]},
    +    q{[\N{DEL}-\o{377}]},
    +    q{[\o{0}-\N{U+01}]},
    +    q{[\000-\N{U+01}]},
    +    q{[\N{DEL}-\377]},
    +) {
    +    my @warnings = compile_warnings($source);
    +    is(scalar @warnings, 1, "$source emits one range-end warning");
    +    like($warnings[0],
    +         qr/Both or neither range ends should be Unicode.*<-- HERE/s,
    +         "$source preserves named-character endpoint provenance");
    +}
    +
    +for my $source (
    +    q{[\N{U+00}-\a]},
    +    q{[\a-\N{U+FF}]},
    +    q{[\N{U+100}-\x{101}]},
    +) {
    +    my @warnings = compile_warnings($source);
    +    is(scalar @warnings, 0,
    +       "$source has two Unicode-equivalent range endpoints");
    +}
    diff --git a/src/test/resources/unit/regex/strict_posix_range_warning.t b/src/test/resources/unit/regex/strict_posix_range_warning.t
    new file mode 100644
    index 0000000000..acee4b2265
    --- /dev/null
    +++ b/src/test/resources/unit/regex/strict_posix_range_warning.t
    @@ -0,0 +1,49 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 8;
    +
    +sub compile_normal {
    +    my ($source) = @_;
    +    my @warnings;
    +    local $SIG{__WARN__} = sub { push @warnings, @_ };
    +    eval $source;
    +    return ($@, @warnings);
    +}
    +
    +my ($error, @warnings) = compile_normal(q{qr/[a-[:digit:]]/});
    +is($error, '', 'literal to POSIX false range is normally nonfatal');
    +like($warnings[0], qr/^False \[\] range "a-\[:digit:\]"/,
    +    'literal to POSIX false range warns');
    +
    +($error, @warnings) = compile_normal(q{qr/[[:digit:]-b]/});
    +is($error, '', 'POSIX to literal false range is normally nonfatal');
    +like($warnings[0], qr/^False \[\] range "\[:digit:\]-"/,
    +    'POSIX to literal false range warns');
    +
    +{
    +    use re 'strict';
    +    local $SIG{__WARN__} = sub {};
    +    eval q{qr/[a-[:digit:]]/};
    +    $error = $@;
    +}
    +like($error, qr/^False \[\] range "a-\[:digit:\]"/,
    +    're strict promotes a literal to POSIX false range');
    +
    +{
    +    use re 'strict';
    +    @warnings = ();
    +    local $SIG{__WARN__} = sub { push @warnings, @_ };
    +    eval q{qr/[A-a]/};
    +}
    +is($@, '', 'strict mixed ASCII range remains nonfatal');
    +like($warnings[0], qr/^Ranges of ASCII printables should be some subset/,
    +    'strict ordinary class receives the ASCII range warning');
    +
    +{
    +    use re 'strict';
    +    @warnings = ();
    +    local $SIG{__WARN__} = sub { push @warnings, @_ };
    +    eval q{qr/[:-\x3A]/};
    +}
    +like($warnings[0], qr/^":-\\x3A" is more clearly written simply as ":"/,
    +    'strict ordinary class canonicalizes equal endpoint spellings');
    diff --git a/src/test/resources/unit/regex/strict_spaced_posix_warning_count.t b/src/test/resources/unit/regex/strict_spaced_posix_warning_count.t
    new file mode 100644
    index 0000000000..a6b2cf7943
    --- /dev/null
    +++ b/src/test/resources/unit/regex/strict_spaced_posix_warning_count.t
    @@ -0,0 +1,23 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 5;
    +
    +my @warnings;
    +my $compiled;
    +{
    +    local $SIG{__WARN__} = sub { push @warnings, @_ };
    +    $compiled = eval q{
    +        no warnings 'experimental::re_strict';
    +        use re 'strict';
    +        qr/[[   ^   :   x d i g i t   :   ]   ]\x{100}/;
    +    };
    +}
    +
    +ok(defined $compiled, 'spaced POSIX candidate compiles under re strict');
    +is(scalar @warnings, 6, 'spaced POSIX candidate emits six warnings');
    +is(scalar(grep { /no blanks are allowed in one/ } @warnings), 4,
    +   'four spacing diagnostics are retained');
    +is(scalar(grep { /the '\^' must come after the colon/ } @warnings), 1,
    +   'the misplaced-caret diagnostic is retained');
    +is(scalar(grep { /Unescaped literal '\]'/ } @warnings), 1,
    +   'the strict lexer emits the closing-bracket warning once');
    diff --git a/src/test/resources/unit/regex/strict_vertical_space_class.t b/src/test/resources/unit/regex/strict_vertical_space_class.t
    new file mode 100644
    index 0000000000..b5b8180c8d
    --- /dev/null
    +++ b/src/test/resources/unit/regex/strict_vertical_space_class.t
    @@ -0,0 +1,21 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 3;
    +
    +my $vertical = "\f";
    +my @warnings;
    +{
    +    local $SIG{__WARN__} = sub { push @warnings, @_ };
    +    eval "no warnings 'experimental::re_strict'; use re 'strict'; qr/[a${vertical}b]/";
    +}
    +like($@,
    +    qr/^Literal vertical space in \[\] is illegal except under \/x in regex; marked by <-- HERE in m\/\[a\f <-- HERE b\]\//,
    +    'strict class rejects literal vertical space at its exact position');
    +is_deeply(\@warnings, [], 'strict rejection emits no secondary warnings');
    +
    +@warnings = ();
    +{
    +    local $SIG{__WARN__} = sub { };
    +    eval "no warnings 'experimental::re_strict'; use re 'strict'; qr/[a${vertical}b]/xx";
    +}
    +is($@, '', 'strict /xx class accepts literal vertical space');
    diff --git a/src/test/resources/unit/regex/unicode_extended_nested_property_fold_policy.t b/src/test/resources/unit/regex/unicode_extended_nested_property_fold_policy.t
    new file mode 100644
    index 0000000000..feba0717ff
    --- /dev/null
    +++ b/src/test/resources/unit/regex/unicode_extended_nested_property_fold_policy.t
    @@ -0,0 +1,37 @@
    +use strict;
    +use warnings;
    +no warnings 'experimental::regex_sets';
    +use Test::More;
    +
    +my $mixed = qr/(?[ [\p{SB=UP}B] ])/i;
    +ok('A' =~ $mixed, 'nested standard leaf retains no-fold property member');
    +ok('a' !~ $mixed, 'nested standard leaf does not fold property-only member');
    +ok('B' =~ $mixed, 'nested standard leaf retains literal member');
    +ok('b' =~ $mixed, 'literal beside no-fold property still folds');
    +
    +my $intersection = qr/(?[ [\p{SB=UP}B] & [AaBb] ])/i;
    +ok('A' =~ $intersection, 'intersection retains no-fold property member');
    +ok('a' !~ $intersection, 'intersection does not fold property-only member');
    +ok('b' =~ $intersection, 'intersection retains folded literal provenance');
    +
    +my $subtraction = qr/(?[ [\p{SB=UP}B] - [A] ])/i;
    +ok('A' !~ $subtraction, 'subtraction removes its folded right operand');
    +ok('a' !~ $subtraction, 'subtraction does not synthesize lowercase property member');
    +ok('b' =~ $subtraction, 'subtraction preserves unrelated folded literal member');
    +
    +our @callback_modes;
    +sub IsNestedPolicy {
    +    push @callback_modes, $_[0] ? 1 : 0;
    +    return "0041\n";
    +}
    +
    +my $callback = eval q{qr/(?[ [\p{IsNestedPolicy}B] ])/i};
    +is($@, '', 'nested callback-owned property leaf compiles');
    +ok('A' =~ $callback && 'a' !~ $callback,
    +    'callback-owned member is not automatically folded');
    +ok('B' =~ $callback && 'b' =~ $callback,
    +    'literal beside callback-owned member keeps folding');
    +is_deeply(\@callback_modes, [1],
    +    'callback-owned leaf resolves once in its local fold mode');
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/unicode_named_constant_pattern_scope.t b/src/test/resources/unit/regex/unicode_named_constant_pattern_scope.t
    new file mode 100644
    index 0000000000..b8ecb98b49
    --- /dev/null
    +++ b/src/test/resources/unit/regex/unicode_named_constant_pattern_scope.t
    @@ -0,0 +1,25 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 5;
    +
    +{
    +    use charnames ':full';
    +    ok('A' =~ '\N{LATIN CAPITAL LETTER A}',
    +        'constant string pattern uses the enclosing standard translator');
    +}
    +
    +{
    +    use lib 'src/test/resources/unit/lib';
    +    use Phase36Cname;
    +
    +    ok('xy' =~ 'x\N{EMPTY-STR}y',
    +        'nested constant string pattern retains its custom translator');
    +    ok('A' =~ /^\N{EVIL}$/,
    +        'literal match compiles its first stateful custom-name result');
    +    ok('AB' =~ qr/^\N{EVIL}$/,
    +        'following qr literal compiles the next custom-name result');
    +}
    +
    +my $error = eval q{ '' =~ '\N{EMPTY-STR}'; 1 } ? '' : $@;
    +like($error, qr/(?:Invalid Unicode character name|Unknown charname)/,
    +    'constant pattern translator does not leak beyond lexical scope');
    diff --git a/src/test/resources/unit/regex/unicode_named_invalid_custom_names.t b/src/test/resources/unit/regex/unicode_named_invalid_custom_names.t
    new file mode 100644
    index 0000000000..8c4ca74256
    --- /dev/null
    +++ b/src/test/resources/unit/regex/unicode_named_invalid_custom_names.t
    @@ -0,0 +1,42 @@
    +use strict;
    +use warnings;
    +use utf8;
    +use Test::More;
    +use threads;
    +use lib 'src/test/resources/unit/regex';
    +
    +local $ENV{JPERL_UNIMPLEMENTED} = 'warn';
    +
    +sub invalid_messages {
    +    {
    +        use LocalPermissiveCharnames;
    +
    +        my @sources = (
    +            q{q() =~ /\N{4F}/},
    +            q{q() =~ /\N{COM,MA}/},
    +            q{q() =~ /\N{A×O}/},
    +            q{use utf8; q() =~ /\N{7 CITIES OF GOLD}/},
    +            q{use utf8; q() =~ /\N{SHARP #}/},
    +            q{use utf8; q() =~ /\N{A ÷ HOUSE}/},
    +            q{use utf8; q() =~ /\N{٤ HORSEMEN}/},
    +            q{use utf8; q() =~ /\N{A 💩 WOULD SMELL}/},
    +        );
    +        my @messages;
    +        for my $source (@sources) {
    +            eval $source;
    +            push @messages, $@;
    +        }
    +        return \@messages;
    +    }
    +}
    +
    +my $expected = qr/Invalid character in \\N\{\.\.\.\}/;
    +my $parent = invalid_messages();
    +like $_, $expected, 'invalid custom charname is diagnosed in parent eval'
    +        for @$parent;
    +
    +my $child = threads->create(sub { invalid_messages() })->join;
    +like $_, $expected, 'invalid custom charname is diagnosed in child eval'
    +        for @$child;
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/unicode_named_nested_scope_transport.t b/src/test/resources/unit/regex/unicode_named_nested_scope_transport.t
    new file mode 100644
    index 0000000000..3768a8a841
    --- /dev/null
    +++ b/src/test/resources/unit/regex/unicode_named_nested_scope_transport.t
    @@ -0,0 +1,34 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +use lib 'src/test/resources/unit/lib';
    +
    +sub compile_nested_custom_names {
    +    {
    +        use Phase36Cname;
    +        BEGIN { $Phase36Cname::Evil = 'A' }
    +
    +        my $passthrough = qr/^\N{foo}[\N{B}\N{b}]$/;
    +        my $first = qr/^(\N{EVIL})$/;
    +        my $second = qr/^(\N{EVIL})$/;
    +        return ($passthrough, $first, $second);
    +    }
    +}
    +
    +my ($passthrough, $first, $second) = compile_nested_custom_names();
    +ok('fooB' =~ $passthrough,
    +    'named-sub lexical charnames translator reaches a literal regex');
    +is($Phase36Cname::Evil, 'ABC',
    +    'each named-sub custom escape resolved once during source compilation');
    +ok('A' =~ $first && $1 eq 'A',
    +    'first named-sub custom expansion remains attached to its regex');
    +ok('AB' =~ $second && $1 eq 'AB',
    +    'identical source in the same nested scope resolves independently');
    +ok('A' =~ $first && $1 eq 'A',
    +    'later compilation does not contaminate the first nested regex');
    +
    +my $outside = eval q{qr/^\N{foo}$/};
    +ok(!defined($outside) && $@ ne '',
    +    'custom translator does not leak outside its lexical block');
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/unicode_named_sequence_single_character_contexts.t b/src/test/resources/unit/regex/unicode_named_sequence_single_character_contexts.t
    new file mode 100644
    index 0000000000..0204eb0ba5
    --- /dev/null
    +++ b/src/test/resources/unit/regex/unicode_named_sequence_single_character_contexts.t
    @@ -0,0 +1,50 @@
    +use strict;
    +use warnings;
    +use charnames ':full';
    +use Test::More;
    +no warnings 'experimental::regex_sets';
    +
    +my $name = 'LATIN CAPITAL LETTER A WITH MACRON AND GRAVE';
    +my $canonical = 'U+100.300';
    +
    +my @fatal = (
    +    [ 'nested extended class',
    +      qq{qr/(?[[^\\N{$name}]])/} ],
    +    [ 'strict negated class',
    +      qq{no warnings 'experimental::re_strict'; use re 'strict'; qr/[^\\N{$name}]/} ],
    +    [ 'strict range end',
    +      qq{no warnings 'experimental::re_strict'; use re 'strict'; qr/[\\x03-\\N{$name}]/} ],
    +    [ 'strict range start',
    +      qq{no warnings 'experimental::re_strict'; use re 'strict'; qr/[\\N{$name}-\\x{10FFFF}]/} ],
    +);
    +
    +for my $case (@fatal) {
    +    my ($label, $source) = @$case;
    +    eval $source;
    +    like($@, qr/^\\N\{\} here is restricted to one character in regex;/,
    +        "$label is fatal");
    +    like($@, qr/\\N\{\Q$canonical\E <-- HERE \}/,
    +        "$label renders the canonical sequence at the marker");
    +}
    +
    +eval qq{qr/(?[[^\\N{$name}]])/};
    +my $nested_rendering = "m/(?[[^\\N{$canonical <-- HERE }]])/";
    +ok(index($@, $nested_rendering) >= 0,
    +    'nested extended diagnostic retains the complete pattern suffix');
    +
    +my $sequence = "\x{100}\x{300}";
    +my $positive = qr/[\N{LATIN CAPITAL LETTER A WITH MACRON AND GRAVE}]/;
    +ok($sequence =~ /\A$positive\z/,
    +    'ordinary positive class still accepts a named sequence');
    +
    +my $warning = '';
    +my $negated;
    +{
    +    local $SIG{__WARN__} = sub { $warning .= join '', @_ };
    +    $negated = eval qq{qr/[^\\N{$name}]/};
    +}
    +ok(defined $negated, 'ordinary non-strict negated class remains accepted');
    +like($warning, qr/Using just the first character returned by \\N\{\}/,
    +    'ordinary non-strict negated class retains its warning');
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/unicode_named_source_mode.t b/src/test/resources/unit/regex/unicode_named_source_mode.t
    new file mode 100644
    index 0000000000..b946e64443
    --- /dev/null
    +++ b/src/test/resources/unit/regex/unicode_named_source_mode.t
    @@ -0,0 +1,29 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +use lib 'src/test/resources/unit/lib';
    +
    +our ($byte_a, $byte_u, $unicode_a, $unicode_u);
    +
    +{
    +    no utf8;
    +    use Phase36CnameMode;
    +    $byte_a = qr/^\N{FOO}$/a;
    +    $byte_u = qr/^\N{BAR}$/u;
    +}
    +
    +{
    +    use utf8;
    +    use Phase36CnameMode;
    +    $unicode_a = qr/^\N{BAZ}$/a;
    +    $unicode_u = qr/^\N{QUX}$/u;
    +}
    +
    +is_deeply(\@Phase36CnameMode::Modes, [qw(B B U U)],
    +    'custom translator input mode follows source bytes, not regex charset flags');
    +ok('A' =~ $byte_a, 'byte-source /a expansion matches');
    +ok('B' =~ $byte_u, 'byte-source /u expansion matches');
    +ok('A' =~ $unicode_a, 'Unicode-source /a expansion matches');
    +ok('B' =~ $unicode_u, 'Unicode-source /u expansion matches');
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/unicode_named_thread_dynamic_eval.t b/src/test/resources/unit/regex/unicode_named_thread_dynamic_eval.t
    new file mode 100644
    index 0000000000..c862d0d29a
    --- /dev/null
    +++ b/src/test/resources/unit/regex/unicode_named_thread_dynamic_eval.t
    @@ -0,0 +1,28 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +use threads;
    +use lib 'src/test/resources/unit/regex';
    +
    +sub child_result {
    +    {
    +        use LocalDynamicCharnames;
    +
    +        my $direct = eval q{'xfooy' =~ /x\N{FOO}y/};
    +        my $nested = eval q{eval q{'bar' =~ /^\N{BAR}$/}};
    +        my $empty  = eval q{'xy' =~ /^x\N{EMPTY}y$/};
    +        my $first  = eval q{'A' =~ /^(\N{EVIL})$/ && $1};
    +        my $second = eval q{'B' =~ /^(\N{EVIL})$/ && $1};
    +        return join ':', map { defined $_ ? $_ : '' }
    +                $direct, $nested, $empty, $first, $second, $@;
    +    }
    +}
    +
    +is(threads->create(\&child_result)->join,
    +        '1:1:1:A:B:',
    +        'dynamic and nested eval retain lexical charnames in a child');
    +is(threads->create(\&child_result)->join,
    +        '1:1:1:A:B:',
    +        'a repeated child receives an independent callback-state clone');
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/unicode_named_thread_literal_transport.t b/src/test/resources/unit/regex/unicode_named_thread_literal_transport.t
    new file mode 100644
    index 0000000000..8d4171f108
    --- /dev/null
    +++ b/src/test/resources/unit/regex/unicode_named_thread_literal_transport.t
    @@ -0,0 +1,33 @@
    +use strict;
    +use warnings;
    +use threads;
    +use Test::More;
    +use lib 'src/test/resources/unit/lib';
    +
    +{
    +    use Phase36Cname;
    +    BEGIN { $Phase36Cname::Evil = 'A' }
    +
    +    sub literal_results {
    +        my $quoted = qr/^\N{foo}$/;
    +        return [
    +            'foo' =~ /^\N{foo}$/ ? 1 : 0,
    +            'foo' =~ $quoted ? 1 : 0,
    +            'xy' =~ 'x\N{EMPTY-STR}y' ? 1 : 0,
    +            'A' =~ /^\N{EVIL}$/ ? 1 : 0,
    +        ];
    +    }
    +
    +    my $direct = literal_results();
    +    my $before_thread = $Phase36Cname::Evil;
    +    my $threaded = threads->create(\&literal_results)->join;
    +
    +    is_deeply($direct, [1, 1, 1, 1],
    +        'direct CV uses its lexical named-character results');
    +    is_deeply($threaded, $direct,
    +        'ithread CV uses the identical pre-resolved named-character results');
    +    is($Phase36Cname::Evil, $before_thread,
    +        'executing the CV in an ithread does not rerun the lexical translator');
    +}
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/unicode_native_property_class_policy.t b/src/test/resources/unit/regex/unicode_native_property_class_policy.t
    new file mode 100644
    index 0000000000..78d6332379
    --- /dev/null
    +++ b/src/test/resources/unit/regex/unicode_native_property_class_policy.t
    @@ -0,0 +1,113 @@
    +use strict;
    +use warnings;
    +use utf8;
    +use Test::More;
    +no warnings qw(experimental::regex_sets experimental::uniprop_wildcards);
    +
    +my @native = (
    +    [ccc => '230',                0x0301, 'canonical combining class'],
    +    [bc  => 'AL',                 0x0627, 'bidi class'],
    +    [dt  => 'Compat',             0x00A8, 'decomposition type'],
    +    [ea  => 'W',                  0x1100, 'East Asian width'],
    +    [nv  => '1',                  0x0031, 'numeric value'],
    +    [jg  => 'Ain',                0x0639, 'joining group'],
    +    [WB  => 'LE',                 0x0041, 'word break'],
    +    [SB  => 'UP',                 0x0041, 'sentence break'],
    +    [LB  => 'CR',                 0x000D, 'line break'],
    +    [VO  => 'TR',                 0x2329, 'vertical orientation'],
    +    [Age => '2.1',                0x20AC, 'Age'],
    +);
    +
    +for my $case (@native) {
    +    my ($property, $value, $code_point, $label) = @$case;
    +    my $pattern = eval "qr/[\\p{$property=$value}_]/i";
    +    is($@, '', "$label compiles natively in a standard class");
    +    ok(chr($code_point) =~ $pattern, "$label retains its member under /i");
    +}
    +
    +ok('a' !~ /[\p{SB=UP}_]/i,
    +    'no-fold sentence-break membership does not gain lowercase under /i');
    +ok('A' =~ /[\p{Lowercase}_]/i,
    +    'foldable binary property retains native case closure');
    +ok('A' !~ /[^\p{Lowercase}]/i,
    +    'outer class negation retains folded binary membership');
    +ok('b' =~ /[B\p{SB=UP}]/i,
    +    'literal beside no-fold property retains its own fold policy');
    +ok('a' !~ /[B\p{SB=UP}]/i,
    +    'no-fold property beside foldable literal stays exact');
    +ok('a' =~ /[\P{SB=UP}]/i && 'A' !~ /[\P{SB=UP}]/i,
    +    'token-level no-fold property negation remains exact under /i');
    +ok('a' =~ /[^\p{SB=UP}]/i && 'A' !~ /[^\p{SB=UP}]/i,
    +    'outer no-fold class negation remains exact under /i');
    +ok('a' =~ /[\p{PosixUpper}]/i,
    +    'POSIX compatibility property retains native fold policy');
    +
    +my $ccc_wildcard = qr/[\p{ccc=:\AAbove\z:}_]/i;
    +ok("\x{0301}" =~ $ccc_wildcard && 'A' !~ $ccc_wildcard,
    +    'no-fold wildcard value resolves natively inside a standard class');
    +my $sentence_wildcard = qr/[\p{SB=:\AUpper\z:}B]/i;
    +ok('A' =~ $sentence_wildcard && 'a' !~ $sentence_wildcard
    +        && 'b' =~ $sentence_wildcard,
    +    'sentence wildcard keeps no-fold property and foldable literal policies');
    +
    +my @generated_wildcards = (
    +    ['Block=:\ABasic_Latin\z:', 'A',       'Block wildcard'],
    +    ['sc=:\ALatin\z:',          'A',       'Script wildcard'],
    +    ['scx=:\ALatin\z:',         'A',       'Script_Extensions wildcard'],
    +    ['nv=:\A1\z:',              '1',       'Numeric_Value wildcard'],
    +    ['jg=:\AAin\z:',            "\x{0639}", 'Joining_Group wildcard'],
    +    ['Age=:\AV2_1\z:',          "\x{20ac}", 'Age wildcard'],
    +);
    +for my $case (@generated_wildcards) {
    +    my ($property, $member, $label) = @$case;
    +    my $pattern = eval "qr/[\\p{$property}_]/i";
    +    is($@, '', "$label compiles inside a standard class");
    +    ok($member =~ $pattern, "$label retains its selected member");
    +}
    +
    +{
    +    ok('A' =~ /(?[ \p{SB=UP} + [_] ])/i,
    +        'extended-class union retains no-fold property membership');
    +    ok('a' !~ /(?[ \p{SB=UP} + [_] ])/i,
    +        'extended-class union does not fold a no-fold property');
    +    ok('A' =~ /(?[ \p{SB=UP} & [A-Z] ])/i,
    +        'extended-class intersection retains native property provenance');
    +    ok('a' !~ /(?[ \p{SB=UP} & [A-Z] ])/i,
    +        'extended intersection does not fold no-fold property membership');
    +    ok('A' !~ /(?[ [A-Z] - \p{SB=UP} ])/i,
    +        'extended-class subtraction removes native property members');
    +    ok('a' =~ /(?[ [A-Z] - \p{SB=UP} ])/i,
    +        'extended subtraction preserves folded literal-only member');
    +    ok('a' =~ /(?[ ! \p{SB=UP} ])/i && 'A' !~ /(?[ ! \p{SB=UP} ])/i,
    +        'extended unary complement retains no-fold property policy');
    +    ok("\x{0301}" =~ /(?[ \p{ccc=:\AAbove\z:} + [_] ])/i,
    +        'no-fold wildcard value resolves natively in an extended class');
    +    ok('A' =~ /(?[ \p{SB=:\AUpper\z:} + [B] ])/i
    +            && 'a' !~ /(?[ \p{SB=:\AUpper\z:} + [B] ])/i
    +            && 'b' =~ /(?[ \p{SB=:\AUpper\z:} + [B] ])/i,
    +        'sentence wildcard retains mixed policy in an extended class');
    +}
    +
    +our ($deferred_class, $extended_collision_error, $callback_fold);
    +BEGIN {
    +    $deferred_class = qr/[\p{InGreek}_]/;
    +    {
    +        no warnings 'experimental::regex_sets';
    +        local $ENV{JPERL_UNIMPLEMENTED} = 'warn';
    +        eval q{qr/(?[ \p{InGreek} + [_] ])/};
    +        $extended_collision_error = $@;
    +    }
    +    $callback_fold = qr/[\p{IsNativeClassFold}_]/i;
    +}
    +sub InGreek { "0600\n" }
    +sub IsNativeClassFold { "0041\n" }
    +ok("\x{0600}" =~ $deferred_class && "\x{0370}" !~ $deferred_class,
    +    'deferred callback outranks colliding built-in in a standard class');
    +like($extended_collision_error, qr/Unknown user-defined property name "InGreek"/,
    +    'forward extended-class collision stays fatal under warn policy');
    +ok('A' =~ $callback_fold && 'a' !~ $callback_fold,
    +    'case-insensitive callback result retains callback-owned fold policy');
    +ok('a' =~ /[\P{IsNativeClassFold}]/i && 'A' !~ /[\P{IsNativeClassFold}]/i,
    +    'case-insensitive callback negation retains callback-owned policy');
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/unicode_native_property_hook_matrix.t b/src/test/resources/unit/regex/unicode_native_property_hook_matrix.t
    new file mode 100644
    index 0000000000..7d2160ebac
    --- /dev/null
    +++ b/src/test/resources/unit/regex/unicode_native_property_hook_matrix.t
    @@ -0,0 +1,35 @@
    +use strict;
    +use warnings;
    +use utf8;
    +use feature 'unicode_eval';
    +no warnings 'experimental::regex_sets';
    +use Test::More;
    +
    +ok("\x{03A9}" =~ /\p{Script=Greek}/, 'Script matches outside a class');
    +ok('A' !~ /\p{Script=Greek}/, 'Script excludes another script');
    +ok("\x{30FC}" =~ /\p{Script_Extensions=Hiragana}/,
    +    'Script_Extensions matches outside a class');
    +ok("\x{03A9}" =~ /[\p{Block=Greek and Coptic}]/,
    +    'Block matches in a standard class');
    +ok('A' =~ /\p{Age=1.1}/, 'Age matches assigned scalar');
    +ok("\x{20AC}" !~ /\p{Present_In=1.1}/,
    +    'Present_In excludes a later scalar');
    +ok('A' =~ /\p{PerlWord}/, 'Perl binary alias matches');
    +ok('!' !~ /\p{PerlWord}/, 'Perl binary alias excludes punctuation');
    +ok('1' =~ /\p{Alphabetic=No}/, 'false binary assignment matches complement');
    +ok('A' !~ /\p{Alphabetic=No}/, 'false binary assignment excludes base set');
    +ok('a' =~ /\p{Uppercase}/i, '/i applies the property fold policy');
    +ok('a' =~ /[\p{Uppercase}]/i, '/i applies inside standard classes');
    +ok("\x{03A9}" =~ /(?[ \p{Script=Greek} & \p{Block=Greek and Coptic} ])/,
    +    'raw properties compose in an extended class');
    +ok('A' !~ /(?[ \p{Script=Greek} & \p{Block=Greek and Coptic} ])/,
    +    'extended intersection excludes nonmembers');
    +{
    +    use bytes;
    +    ok('A' =~ /\p{Script=Latin}/, 'Script resolves in byte mode');
    +    ok("\xE9" =~ /[\p{Script=Latin}]/, 'Script class resolves high byte');
    +    ok('1' =~ /\p{Alphabetic=No}/, 'false binary assignment resolves in byte mode');
    +    ok('a' =~ /\p{Uppercase}/i, 'property fold policy resolves in byte /i mode');
    +}
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/unicode_property_diagnostics.t b/src/test/resources/unit/regex/unicode_property_diagnostics.t
    new file mode 100644
    index 0000000000..39387e03bf
    --- /dev/null
    +++ b/src/test/resources/unit/regex/unicode_property_diagnostics.t
    @@ -0,0 +1,48 @@
    +#!/usr/bin/perl
    +use strict;
    +use warnings;
    +use Test::More;
    +
    +my @cases = (
    +    [ q{qr/\p{gc=:L*:}/},
    +      q{Use of quantifier '*' is not allowed in Unicode property wildcard subpatterns},
    +      q{L* <-- HERE} ],
    +    [ q{qr/\p{gc=:L\G:}/},
    +      q{Use of '\G' is not allowed in Unicode property wildcard subpatterns},
    +      q{L\G <-- HERE} ],
    +    [ q{qr/\p{gc=:(?g)L:}/},
    +      q{Use of modifier 'g' is not allowed in Unicode property wildcard subpatterns},
    +      q{(?g <-- HERE )L} ],
    +    [ q{qr/\p{gc=:(?a)L:}/},
    +      q{Use of modifier 'a' is not allowed in Unicode property wildcard subpatterns},
    +      q{(?a) <-- HERE L} ],
    +    [ q{qr/\p{gc=:(?u)L:}/},
    +      q{Use of modifier 'u' is not allowed in Unicode property wildcard subpatterns},
    +      q{(?u) <-- HERE L} ],
    +    [ q{qr/\p{gc=:(?d)L:}/},
    +      q{Use of modifier 'd' is not allowed in Unicode property wildcard subpatterns},
    +      q{(?d) <-- HERE L} ],
    +    [ q{qr/\p{gc=:(?l)L:}/},
    +      q{Use of modifier 'l' is not allowed in Unicode property wildcard subpatterns},
    +      q{(?l) <-- HERE L} ],
    +    [ q{qr/\p{gc=:(?-m)L:}/},
    +      q{Use of modifier '-m' is not allowed in Unicode property wildcard subpatterns},
    +      q{(?-m <-- HERE )L} ],
    +    [ q{qr/\p{gc=:\pS:}/},
    +      q{Use of '\pS' is not allowed in Unicode property wildcard subpatterns},
    +      q{\pS <-- HERE} ],
    +    [ q{qr/\p{gc=:\PS:}/},
    +      q{Use of '\PS' is not allowed in Unicode property wildcard subpatterns},
    +      q{\PS <-- HERE} ],
    +);
    +
    +for my $case (@cases) {
    +    my ($source, $message, $marked_source) = @$case;
    +    local $@;
    +    eval "no warnings 'experimental'; $source";
    +    ok($@ ne '', "$source is rejected");
    +    like($@, qr/^\Q$message\E/, "$source reports the Perl diagnostic");
    +    like($@, qr/\Q$marked_source\E/, "$source marks the Perl source position");
    +}
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/unicode_user_property_lexical_context.t b/src/test/resources/unit/regex/unicode_user_property_lexical_context.t
    new file mode 100644
    index 0000000000..b782307d5e
    --- /dev/null
    +++ b/src/test/resources/unit/regex/unicode_user_property_lexical_context.t
    @@ -0,0 +1,77 @@
    +use strict;
    +use warnings;
    +no warnings 'experimental::regex_sets';
    +use Test::More;
    +
    +our (@atom_modes, @class_modes, @extended_modes, @single_mode);
    +our ($comment_calls, $inline_comment_calls, $scoped_comment_calls, $quoted_calls);
    +
    +sub IsInlineAtom {
    +    push @atom_modes, $_[0] ? 1 : 0;
    +    return $_[0] ? "0042\n" : "0041\n";
    +}
    +sub IsInlineClass {
    +    push @class_modes, $_[0] ? 1 : 0;
    +    return $_[0] ? "0042\n" : "0041\n";
    +}
    +sub IsInlineExtended {
    +    push @extended_modes, $_[0] ? 1 : 0;
    +    return $_[0] ? "0042\n" : "0041\n";
    +}
    +sub IsSingleMode {
    +    push @single_mode, $_[0] ? 1 : 0;
    +    return "0042\n";
    +}
    +sub IsCommentSide { ++$comment_calls; "0043\n" }
    +sub IsInlineCommentSide { ++$inline_comment_calls; "0043\n" }
    +sub IsScopedCommentSide { ++$scoped_comment_calls; "0043\n" }
    +sub IsQuotedSide { ++$quoted_calls; "0043\n" }
    +
    +my $atom = eval q{qr/^(?i:\p{IsInlineAtom})(?-i:\p{IsInlineAtom})$/};
    +is($@, '', 'inline-mode atom property compiles');
    +ok('BA' =~ $atom, 'inline-mode atom callback definitions match their scopes');
    +is_deeply([sort @atom_modes], [0, 1],
    +    'atom callback receives both local fold modes exactly once');
    +
    +my $class = eval q{qr/^(?i:[\p{IsInlineClass}])(?-i:[\p{IsInlineClass}])$/};
    +is($@, '', 'inline-mode standard-class property compiles');
    +ok('BA' =~ $class, 'standard-class callbacks match their local scopes');
    +is_deeply([sort @class_modes], [0, 1],
    +    'standard-class callback receives both local fold modes exactly once');
    +
    +my $extended = eval q{qr/^(?i:(?[\p{IsInlineExtended}]))(?-i:(?[\p{IsInlineExtended}]))$/};
    +is($@, '', 'inline-mode extended-class property compiles');
    +ok('BA' =~ $extended, 'extended-class callbacks match their local scopes');
    +is_deeply([sort @extended_modes], [0, 1],
    +    'extended-class callback receives both local fold modes exactly once');
    +
    +my $single = eval q{qr/^(?i:\p{IsSingleMode})$/};
    +is($@, '', 'single inline-mode property compiles');
    +ok('B' =~ $single, 'single inline-mode callback definition matches');
    +is_deeply(\@single_mode, [1],
    +    'preload does not invoke a callback in the enclosing fold mode');
    +
    +my $comment = eval "qr/(?x:# \\p{IsCommentSide}\nA)/";
    +is($@, '', 'property-shaped text in an /x comment compiles');
    +ok('A' =~ $comment, '/x comment does not affect the executable pattern');
    +is($comment_calls || 0, 0, '/x comment does not invoke a user-property callback');
    +
    +my $inline_comment = eval q{qr/(?# \p{IsInlineCommentSide})A/};
    +is($@, '', 'property-shaped text in an inline comment compiles');
    +ok('A' =~ $inline_comment, 'inline comment does not affect the executable pattern');
    +is($inline_comment_calls || 0, 0,
    +    'inline comment does not invoke a user-property callback');
    +
    +my $scoped_comment = eval "qr/(?x:# \\p{IsScopedCommentSide}\nA)/";
    +is($@, '', 'property-shaped text in a scoped /x comment compiles');
    +ok('A' =~ $scoped_comment, 'scoped /x comment is ignored by the matcher');
    +is($scoped_comment_calls || 0, 0,
    +    'scoped /x comment does not invoke a user-property callback');
    +
    +my $quoted = eval q{qr/\Q\p{IsQuotedSide}\E/};
    +is($@, '', 'property-shaped text in a quoted region compiles');
    +ok('\\p{IsQuotedSide}' =~ $quoted,
    +    'quoted property spelling remains literal matcher text');
    +is($quoted_calls || 0, 0, 'quoted region does not invoke a user-property callback');
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/unicode_user_property_precedence.t b/src/test/resources/unit/regex/unicode_user_property_precedence.t
    new file mode 100644
    index 0000000000..6ed1ef987e
    --- /dev/null
    +++ b/src/test/resources/unit/regex/unicode_user_property_precedence.t
    @@ -0,0 +1,47 @@
    +use strict;
    +use warnings;
    +use utf8;
    +use Test::More;
    +
    +our ($deferred, $deferred_class, $deferred_negated_class);
    +BEGIN {
    +    my $property = 'InLatin1';
    +    $deferred = qr/\p{$property}/;
    +    $deferred_class = qr/[\p{$property}]/;
    +    $deferred_negated_class = qr/[^\p{$property}]/;
    +}
    +
    +our @calls;
    +sub InLatin1 {
    +    push @calls, $_[0] ? 'i' : 's';
    +    return $_[0] ? "0200\t0200\n" : "0100\t0100\n";
    +}
    +
    +ok("\x{0100}" =~ $deferred,
    +    'forward user property matches its sensitive definition');
    +ok("\x{00ff}" !~ $deferred,
    +    'forward user property outranks the colliding built-in block');
    +
    +my $fresh = eval q{qr/\p{InLatin1}/};
    +is($@, '', 'fresh colliding user property compiles');
    +ok("\x{0100}" =~ $fresh, 'fresh user property reuses its sensitive definition');
    +ok("\x{00ff}" !~ $fresh, 'fresh user property still outranks the block');
    +
    +my $folded = eval q{qr/\p{InLatin1}/i};
    +is($@, '', 'fresh folded colliding user property compiles');
    +ok("\x{0200}" =~ $folded, 'folded mode uses its distinct user definition');
    +ok("\x{0100}" !~ $folded, 'folded mode does not reuse the sensitive cache');
    +
    +ok("\x{0100}" =~ $deferred_class,
    +    'forward user property wins inside a standard class');
    +ok("\x{00ff}" !~ $deferred_class,
    +    'standard class does not retain the colliding built-in block');
    +ok("\x{0100}" !~ $deferred_negated_class,
    +    'negated standard class excludes the user-defined member');
    +ok("\x{00ff}" =~ $deferred_negated_class,
    +    'negated standard class includes the built-in-only member');
    +
    +is_deeply(\@calls, ['s', 'i'],
    +    'each case mode resolves its user property once');
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/uniprop_wildcard_warning_defaults.t b/src/test/resources/unit/regex/uniprop_wildcard_warning_defaults.t
    new file mode 100644
    index 0000000000..7e384ca98c
    --- /dev/null
    +++ b/src/test/resources/unit/regex/uniprop_wildcard_warning_defaults.t
    @@ -0,0 +1,63 @@
    +use strict;
    +use Test::More;
    +
    +sub evaluate {
    +    my ($source) = @_;
    +    my @warnings;
    +    local $SIG{__WARN__} = sub { push @warnings, @_ };
    +    local $^W;
    +    my $result = eval $source;
    +    return ($result, $@, \@warnings);
    +}
    +
    +sub wildcard_warnings {
    +    return [grep {
    +        /Unicode property wildcards feature/
    +            || index($_, 'single character results returned') >= 0
    +    } @{$_[0]}];
    +}
    +
    +my $pattern = q{$_ = 'x'; m!(?[\p{name=/KATAKANA/}])$!};
    +my $category = 'experimental::uniprop_wildcards';
    +
    +my (undef, $default_error, $default) = evaluate($pattern);
    +is $default_error, '', 'non-strict wildcard pattern compiles by default';
    +is scalar(@$default), 1, 'experimental wildcard warning is default-on';
    +like $default->[0], qr/^The Unicode property wildcards feature is experimental/,
    +    'default warning retains its experimental text';
    +
    +my (undef, $enabled_error, $enabled) = evaluate(
    +    q{use warnings; } . $pattern);
    +is $enabled_error, '', 'wildcard pattern compiles with warnings enabled';
    +is scalar(@$enabled), 2, 'enabling warnings retains both wildcard diagnostics';
    +like $enabled->[1], qr/^Using just the single character results returned by \\p\{\}/,
    +    'enabled warning retains the positioned single-character diagnostic';
    +
    +my (undef, $suppressed_error, $suppressed) = evaluate(
    +    qq{no warnings '$category'; } . $pattern);
    +is $suppressed_error, '', 'suppressed wildcard pattern compiles';
    +is scalar(@$suppressed), 0, 'explicit category suppression wins';
    +
    +my (undef, $strict_error, $strict) = evaluate(
    +    q{no warnings 'experimental::re_strict'; use re 'strict'; } . $pattern);
    +is $strict_error, '', 'strict wildcard pattern compiles';
    +my $strict_wildcards = wildcard_warnings($strict);
    +ok scalar(@$strict_wildcards) >= 1, 'strict mode retains a wildcard warning';
    +like join('', @$strict_wildcards), qr/The Unicode property wildcards feature is experimental/,
    +    'strict mode retains the experimental warning text';
    +
    +my (undef, $strict_suppressed_error, $strict_suppressed) = evaluate(
    +    q{no warnings 'experimental::re_strict'; use re 'strict'; }
    +    . qq{no warnings '$category'; } . $pattern);
    +is $strict_suppressed_error, '', 'strict suppressed wildcard pattern compiles';
    +unlike join('', @$strict_suppressed),
    +    qr/The Unicode property wildcards feature is experimental/,
    +    'explicit experimental warning suppression wins under strict mode';
    +
    +my (undef, $fatal_error, $fatal) = evaluate(
    +    qq{use warnings FATAL => '$category'; } . $pattern);
    +like $fatal_error, qr/^The Unicode property wildcards feature is experimental/,
    +    'fatal category turns the default warning into an exception';
    +is scalar(@$fatal), 0, 'fatal warning is not also delivered to the warning hook';
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/unknown_class_escape_diagnostics.t b/src/test/resources/unit/regex/unknown_class_escape_diagnostics.t
    new file mode 100644
    index 0000000000..0331b53852
    --- /dev/null
    +++ b/src/test/resources/unit/regex/unknown_class_escape_diagnostics.t
    @@ -0,0 +1,26 @@
    +use strict;
    +use warnings;
    +no warnings 'experimental::re_strict';
    +use Test::More tests => 8;
    +
    +for my $case (
    +    [ '[\y]',  '\y' ],
    +    [ '[a\zb]', '\z' ],
    +) {
    +    my ($pattern, $escape) = @$case;
    +    my @warnings;
    +    {
    +        local $SIG{__WARN__} = sub { push @warnings, @_ };
    +        eval "qr/$pattern/";
    +    }
    +    is($@, '', "$pattern compiles without re strict");
    +    is(scalar @warnings, 1, "$pattern emits one warning");
    +    like($warnings[0],
    +        qr/^Unrecognized escape \Q$escape\E in character class passed through in regex; marked by <-- HERE/,
    +        "$pattern warning retains the escape and position");
    +
    +    eval "use re 'strict'; qr/$pattern/";
    +    like($@,
    +        qr/^Unrecognized escape \Q$escape\E in character class in regex; marked by <-- HERE/,
    +        "$pattern is fatal under re strict");
    +}
    diff --git a/src/test/resources/unit/regex/unknown_conditional_diagnostic.t b/src/test/resources/unit/regex/unknown_conditional_diagnostic.t
    new file mode 100644
    index 0000000000..a9f4ae1f73
    --- /dev/null
    +++ b/src/test/resources/unit/regex/unknown_conditional_diagnostic.t
    @@ -0,0 +1,9 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 3;
    +
    +for my $expression (q{qr/(?(x)y|x)/}, q{qr/(?(??{}))/}, q{qr/(?(?[]))/}) {
    +    my $compiled = eval "$expression; 1";
    +    ok(!$compiled && index($@, 'Unknown switch condition (?(...))') >= 0,
    +       'unknown conditional uses the Perl diagnostic');
    +}
    diff --git a/src/test/resources/unit/regex/unknown_escape_diagnostics.t b/src/test/resources/unit/regex/unknown_escape_diagnostics.t
    new file mode 100644
    index 0000000000..7c63e1fd1c
    --- /dev/null
    +++ b/src/test/resources/unit/regex/unknown_escape_diagnostics.t
    @@ -0,0 +1,31 @@
    +use strict;
    +use warnings;
    +no warnings 'experimental::re_strict';
    +use Test::More tests => 10;
    +
    +for my $case (
    +    [ '\y',  '\y' ],
    +    [ 'a\q', '\q' ],
    +) {
    +    my ($pattern, $escape) = @$case;
    +    my @warnings;
    +    {
    +        local $SIG{__WARN__} = sub { push @warnings, @_ };
    +        eval "qr/$pattern/";
    +    }
    +    is($@, '', "$pattern compiles without re strict");
    +    is(scalar @warnings, 1, "$pattern emits one warning");
    +    like($warnings[0],
    +        qr/^Unrecognized escape \Q$escape\E passed through in regex; marked by <-- HERE/,
    +        "$pattern warning retains the escape and position");
    +
    +    @warnings = ();
    +    {
    +        local $SIG{__WARN__} = sub { push @warnings, @_ };
    +        eval "use re 'strict'; qr/$pattern/";
    +    }
    +    is($@, '', "$pattern remains a warning under re strict");
    +    like($warnings[-1],
    +        qr/^Unrecognized escape \Q$escape\E passed through in regex; marked by <-- HERE/,
    +        "$pattern retains its warning under re strict");
    +}
    diff --git a/src/test/resources/unit/regex/unknown_numeric_class_escape.t b/src/test/resources/unit/regex/unknown_numeric_class_escape.t
    new file mode 100644
    index 0000000000..b2657b7b49
    --- /dev/null
    +++ b/src/test/resources/unit/regex/unknown_numeric_class_escape.t
    @@ -0,0 +1,23 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 5;
    +
    +my @warnings;
    +{
    +    local $SIG{__WARN__} = sub { push @warnings, @_ };
    +    eval q{qr/[\8\9]\x{100}/};
    +}
    +is($@, '', 'unknown numeric class escapes remain nonfatal normally');
    +is(scalar @warnings, 2, 'each unknown numeric class escape warns');
    +like($warnings[0], qr/^Unrecognized escape \\8 in character class passed through/,
    +    'first numeric escape retains its spelling');
    +like($warnings[1], qr/^Unrecognized escape \\9 in character class passed through/,
    +    'second numeric escape retains its spelling');
    +
    +{
    +    use re 'strict';
    +    local $SIG{__WARN__} = sub {};
    +    eval q{qr/[\8\9]\x{100}/};
    +}
    +like($@, qr/^Unrecognized escape \\8 in character class in regex/,
    +    're strict promotes the first numeric escape warning');
    diff --git a/src/test/resources/unit/regex/unsupported_group_introducer_diagnostics.t b/src/test/resources/unit/regex/unsupported_group_introducer_diagnostics.t
    new file mode 100644
    index 0000000000..4dddd909d2
    --- /dev/null
    +++ b/src/test/resources/unit/regex/unsupported_group_introducer_diagnostics.t
    @@ -0,0 +1,12 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 2;
    +
    +for my $case (
    +    [ q{qr/(?@)/}, 'Sequence (?@...) not implemented' ],
    +    [ q{qr/(?;x/}, 'Sequence (?;...) not recognized' ],
    +) {
    +    my ($expression, $expected) = @$case;
    +    my $compiled = eval "$expression; 1";
    +    ok(!$compiled && index($@, $expected) >= 0, $expected);
    +}
    diff --git a/src/test/resources/unit/regex/unterminated_comment_group_diagnostics.t b/src/test/resources/unit/regex/unterminated_comment_group_diagnostics.t
    new file mode 100644
    index 0000000000..b0b365d6a6
    --- /dev/null
    +++ b/src/test/resources/unit/regex/unterminated_comment_group_diagnostics.t
    @@ -0,0 +1,10 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 6;
    +
    +for my $pattern ('x(?#', 'x(?#:', '(?#abc') {
    +    my $ok = eval "qr/$pattern/; 1";
    +    ok(!$ok, "$pattern is rejected");
    +    ok(index($@, 'Sequence (?#... not terminated') >= 0,
    +        "$pattern reports an unterminated comment sequence");
    +}
    diff --git a/src/test/resources/unit/regex/unterminated_option_group_diagnostics.t b/src/test/resources/unit/regex/unterminated_option_group_diagnostics.t
    new file mode 100644
    index 0000000000..72ea7917ba
    --- /dev/null
    +++ b/src/test/resources/unit/regex/unterminated_option_group_diagnostics.t
    @@ -0,0 +1,10 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 6;
    +
    +for my $pattern ('(?i', '(?a-x', '(?-') {
    +    my $ok = eval "qr/$pattern/; 1";
    +    ok(!$ok, "$pattern is rejected");
    +    ok(index($@, 'Sequence (?... not terminated') >= 0,
    +        "$pattern reports an unterminated option sequence");
    +}
    diff --git a/src/test/resources/unit/regex/useless_modifier_warning_position.t b/src/test/resources/unit/regex/useless_modifier_warning_position.t
    new file mode 100644
    index 0000000000..dd3ee0c8be
    --- /dev/null
    +++ b/src/test/resources/unit/regex/useless_modifier_warning_position.t
    @@ -0,0 +1,29 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 8;
    +
    +my @warnings;
    +{
    +    local $SIG{__WARN__} = sub { push @warnings, @_ };
    +    my $compiled = eval q{qr/(?ogc)/};
    +    ok($compiled, 'modifier-only group compiles');
    +}
    +
    +is(scalar @warnings, 3, 'one warning is emitted per useless modifier');
    +like($warnings[0], qr/Useless \(\?o\) - use \/o modifier.*\(\?o <-- HERE gc\)/s,
    +     'o warning is marked after o');
    +like($warnings[1], qr/Useless \(\?g\) - use \/g modifier.*\(\?og <-- HERE c\)/s,
    +     'g warning is marked after g');
    +like($warnings[2], qr/Useless \(\?c\) - use \/gc modifier.*\(\?ogc <-- HERE \)/s,
    +     'c warning is marked after c');
    +
    +@warnings = ();
    +{
    +    local $SIG{__WARN__} = sub { push @warnings, @_ };
    +    my $compiled = eval q{qr/(?-cgo)/};
    +    ok($compiled, 'negative modifier group compiles');
    +}
    +is(scalar @warnings, 2, 'c suppresses the redundant g warning but not o');
    +like(join('', @warnings),
    +     qr/Useless \(\?-c\) - don't use \/gc modifier.*Useless \(\?-o\) - don't use \/o modifier/s,
    +     'negative warnings explain which external modifier not to use');
    diff --git a/src/test/resources/unit/regex/user_property_digit_name.t b/src/test/resources/unit/regex/user_property_digit_name.t
    new file mode 100644
    index 0000000000..7959f59e18
    --- /dev/null
    +++ b/src/test/resources/unit/regex/user_property_digit_name.t
    @@ -0,0 +1,21 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 8;
    +
    +sub Is0 { "41\n" }
    +sub In9x { "42\n" }
    +
    +my $is_zero = qr/\p{Is0}/;
    +like('A', $is_zero, 'digit-leading Is suffix is a valid user property name');
    +unlike('B', $is_zero, 'digit-leading Is property preserves its ranges');
    +
    +my $in_nine = qr/\p{In9x}/;
    +like('B', $in_nine, 'digit-leading In suffix is a valid user property name');
    +unlike('A', $in_nine, 'digit-leading In property preserves its ranges');
    +
    +for my $name (qw(Is7 In8)) {
    +    my $ok = eval 'qr/(?[' . "\\P{$name}" . '])/; 1';
    +    ok(!$ok, "$name is rejected inside an extended set");
    +    like($@, qr/^Unknown user-defined property name "\Q$name\E"/,
    +        "$name reports the user-property diagnostic");
    +}
    diff --git a/src/test/resources/unit/regex/user_property_package_provenance.t b/src/test/resources/unit/regex/user_property_package_provenance.t
    new file mode 100644
    index 0000000000..9c98701024
    --- /dev/null
    +++ b/src/test/resources/unit/regex/user_property_package_provenance.t
    @@ -0,0 +1,41 @@
    +use strict;
    +use warnings;
    +use feature 'unicode_strings';
    +use threads;
    +use Test::More tests => 9;
    +
    +my ($some, $other);
    +{
    +    package Some;
    +    sub Is_q { "71\n" }
    +    $some = qr/\p{Is_q}/;
    +}
    +{
    +    package Other;
    +    sub Is_q { "72\n" }
    +    $other = qr/\p{Is_q}/;
    +}
    +
    +like('q', $some, 'bare property resolves in the qr construction package');
    +unlike('r', $some, 'first package excludes the other package member');
    +like('r', $other, 'same bare name resolves independently in another package');
    +unlike('q', $other, 'package-specific property caches do not collide');
    +like("$some", qr/Is_q/, 'stringification preserves the bare property spelling');
    +
    +my $child = threads->create(sub {
    +    return 0 unless 'q' =~ $some && 'r' !~ $some;
    +    return 0 unless 'r' =~ $other && 'q' !~ $other;
    +    return 1;
    +});
    +is($child->join, 1, 'ithread snapshot retains both construction packages');
    +
    +my $embedded;
    +{
    +    package Some;
    +    $embedded = qr/abc$some/;
    +}
    +like('abcq', $embedded, 'compiled qr reuse retains property provenance');
    +unlike('abcr', $embedded, 'compiled qr reuse retains package exclusions');
    +
    +my $qualified = qr/\p{Other::Is_q}/;
    +like('r', $qualified, 'explicitly qualified property remains unchanged');
    diff --git a/src/test/resources/unit/regex/vertical_whitespace_byte_casefold.t b/src/test/resources/unit/regex/vertical_whitespace_byte_casefold.t
    new file mode 100644
    index 0000000000..f456752e2d
    --- /dev/null
    +++ b/src/test/resources/unit/regex/vertical_whitespace_byte_casefold.t
    @@ -0,0 +1,18 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +
    +my $byte_nel = pack 'C', 0x85;
    +utf8::downgrade($byte_nel, 1);
    +
    +my $byte_lf = "\n";
    +utf8::downgrade($byte_lf, 1);
    +
    +like($byte_nel, qr/\A\v\z/i,
    +    'case-insensitive byte pattern matches byte NEL');
    +like($byte_lf, qr/\A\v\z/i,
    +    'case-insensitive byte pattern matches byte LF');
    +is(qr/\b\v$/i, '(?^i:\b\v$)',
    +    'case-insensitive vertical whitespace pattern stringifies');
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex/word_boundary_ignored_sequences.t b/src/test/resources/unit/regex/word_boundary_ignored_sequences.t
    new file mode 100644
    index 0000000000..82a8a2c83c
    --- /dev/null
    +++ b/src/test/resources/unit/regex/word_boundary_ignored_sequences.t
    @@ -0,0 +1,83 @@
    +use strict;
    +use warnings;
    +use utf8;
    +
    +use Test::More tests => 27;
    +
    +ok("  \r" =~ /\A \B{wb} \B{wb}\r\z/,
    +    'horizontal whitespace joins a following vertical whitespace run');
    +ok("  \r" !~ /\A \B{wb} \b{wb}\r\z/,
    +    'positive boundary rejects the interior whitespace transition');
    +
    +ok("  \r\x{0308}" =~ /\A \B{wb} \B{wb}\r\b{wb}\x{0308}\z/,
    +    'vertical whitespace breaks before ignored Extend');
    +ok("  \r\x{00ad}" =~ /\A \B{wb} \B{wb}\r\b{wb}\x{00ad}\z/,
    +    'vertical whitespace breaks before ignored Format');
    +ok("  \r\x{200d}" =~ /\A \B{wb} \B{wb}\r\b{wb}\x{200d}\z/,
    +    'vertical whitespace breaks before ignored ZWJ');
    +
    +ok("   \x{0308}" =~ /\A \B{wb} \b{wb} \B{wb}\x{0308}\z/,
    +    'horizontal whitespace and Extend form a pair separate from its prefix');
    +ok("   \x{00ad}" =~ /\A \B{wb} \b{wb} \B{wb}\x{00ad}\z/,
    +    'horizontal whitespace and Format form a pair separate from its prefix');
    +ok("  \t\x{200d}" =~ /\A \B{wb} \B{wb}\t\B{wb}\x{200d}\z/,
    +    'horizontal tab and ZWJ remain joined to the whitespace prefix');
    +ok("  \t\x{0308}" =~ /\A \B{wb} \b{wb}\t\B{wb}\x{0308}\z/,
    +    'horizontal tab binds to Extend separately from its prefix');
    +ok("   \x{200d}" =~ /\A \B{wb} \B{wb} \B{wb}\x{200d}\z/,
    +    'ZWJ remains joined to the complete WSegSpace run');
    +ok("  \x{00a0}\x{200d}"
    +        =~ /\A \B{wb} \B{wb}\x{00a0}\B{wb}\x{200d}\z/,
    +    'tailored no-break space remains joined before ZWJ');
    +ok("  \x{2007}\x{200d}"
    +        =~ /\A \B{wb} \B{wb}\x{2007}\B{wb}\x{200d}\z/,
    +    'tailored figure space remains joined before ZWJ');
    +ok("  \x{202f}\x{200d}"
    +        =~ /\A \B{wb} \b{wb}\x{202f}\B{wb}\x{200d}\z/,
    +    'ExtendNumLet narrow no-break space retains its non-tailored boundary');
    +ok("  \x{0308}" =~ /\A \b{wb} \B{wb}\x{0308}\z/,
    +    'a WSegSpace before Extend starts a new pair after its prefix');
    +ok("\r \x{0308}" =~ /\A\r\B{wb} \B{wb}\x{0308}\z/,
    +    'newline and WSegSpace remain joined when ignored text follows');
    +ok("  \x{1680}\x{0308}"
    +        =~ /\A \B{wb} \b{wb}\x{1680}\B{wb}\x{0308}\z/,
    +    'non-ASCII WSegSpace follows the same ignored-suffix rule');
    +ok("\x{1680}\r" =~ /\A\x{1680}\B{wb}\r\z/,
    +    'non-ASCII WSegSpace joins a newline property');
    +
    +ok("\x{1f469}\x{0308}\x{200d}\x{1f680}"
    +        =~ /\A\x{1f469}\B{wb}\x{0308}\B{wb}\x{200d}\B{wb}\x{1f680}\z/,
    +    'Extend and ZWJ remain transparent in an emoji ZWJ sequence');
    +ok("\x{1f1e6}\x{0308}\x{1f1e7}"
    +        =~ /\A\x{1f1e6}\B{wb}\x{0308}\B{wb}\x{1f1e7}\z/,
    +    'ignored Extend preserves odd RI parity');
    +ok("\x{1f1e6}\x{1f1e7}\x{0308}\x{1f1e8}"
    +        =~ /\A\x{1f1e6}\B{wb}\x{1f1e7}\B{wb}\x{0308}\b{wb}\x{1f1e8}\z/,
    +    'ignored Extend preserves the break before a third RI');
    +
    +ok("\r\x{0308}\n" =~ /\A\r\b{wb}\x{0308}\b{wb}\n\z/,
    +    'ignored Extend does not bridge two vertical whitespace characters');
    +ok("\x{0308}A" =~ /\A\x{0308}\b{wb}A\z/,
    +    'leading ignored character remains separated at start');
    +ok("A\x{0308}" =~ /\AA\B{wb}\x{0308}\z/,
    +    'trailing ignored character follows WB4 at end');
    +
    +my $spaces = "   \x{0308}A";
    +my @space_boundaries;
    +while ($spaces =~ /\b{wb}/g) {
    +    push @space_boundaries, pos($spaces);
    +}
    +is_deeply(\@space_boundaries, [0, 2, 4, 5],
    +    'repeated scans preserve whitespace-prefix and ignored-pair boundaries');
    +
    +my @space_non_boundaries;
    +while ($spaces =~ /\B{wb}/g) {
    +    push @space_non_boundaries, pos($spaces);
    +}
    +is_deeply(\@space_non_boundaries, [1, 3],
    +    'repeated negated scans find both whitespace non-boundaries');
    +
    +ok("  \rA" =~ /(?:\A \B{wb} X|\A \B{wb} \B{wb}\r\b{wb}A\z)/,
    +    'backtracking from a failed boundary branch restores the successful path');
    +ok("  \rA" !~ /(?:\A \B{wb} \b{wb}\rA|\A \b{wb} \B{wb}\rA)/,
    +    'failed alternatives do not leak boundary state');
    diff --git a/src/test/resources/unit/regex/word_boundary_newline_runs.t b/src/test/resources/unit/regex/word_boundary_newline_runs.t
    new file mode 100644
    index 0000000000..be99d0003c
    --- /dev/null
    +++ b/src/test/resources/unit/regex/word_boundary_newline_runs.t
    @@ -0,0 +1,50 @@
    +use strict;
    +use warnings;
    +use utf8;
    +
    +use Test::More tests => 17;
    +
    +sub no_boundary {
    +    my ($left, $right, $description) = @_;
    +    my $subject = $left . $right;
    +    ok($subject =~ /\A\Q$left\E\B{wb}\Q$right\E\z/, $description);
    +}
    +
    +sub boundary {
    +    my ($left, $right, $description) = @_;
    +    my $subject = $left . $right;
    +    ok($subject =~ /\A\Q$left\E\b{wb}\Q$right\E\z/, $description);
    +}
    +
    +no_boundary("\r", "\r", 'CR x CR is not a word boundary');
    +no_boundary("\r", "\n", 'CR x LF is not a word boundary');
    +no_boundary("\n", "\r", 'LF x CR is not a word boundary');
    +no_boundary("\n", "\n", 'LF x LF is not a word boundary');
    +no_boundary("\r", "\x0b", 'CR x vertical tab is not a word boundary');
    +no_boundary("\x0b", "\r", 'vertical tab x CR is not a word boundary');
    +no_boundary("\x0b", "\x0b", 'vertical tab x vertical tab is not a word boundary');
    +no_boundary("\x{85}", "\x{2028}", 'NEL x line separator is not a word boundary');
    +no_boundary("\x{2028}", "\x{2029}", 'line separator x paragraph separator is not a word boundary');
    +
    +boundary("\r", "A", 'newline x letter is a word boundary');
    +boundary("A", "\r", 'letter x newline is a word boundary');
    +boundary("\x0b", "_", 'control newline x ExtendNumLet is a word boundary');
    +
    +ok("\r" =~ /\A\b{wb}\r\b{wb}\z/, 'start and end remain word boundaries');
    +ok("\r\r" !~ /\A\B{wb}/, 'negated word boundary rejects start of string');
    +ok("\r\r" !~ /\B{wb}\z/, 'negated word boundary rejects end of string');
    +
    +my $subject = "\r\rA";
    +my @boundaries;
    +while ($subject =~ /\b{wb}/g) {
    +    push @boundaries, pos($subject);
    +}
    +is_deeply(\@boundaries, [0, 2, 3],
    +    'repeated boundary scans skip the interior newline-run position');
    +
    +my @non_boundaries;
    +while ($subject =~ /\B{wb}/g) {
    +    push @non_boundaries, pos($subject);
    +}
    +is_deeply(\@non_boundaries, [1],
    +    'repeated negated-boundary scans find only the newline-run interior');
    diff --git a/src/test/resources/unit/regex/word_class_complement.t b/src/test/resources/unit/regex/word_class_complement.t
    new file mode 100644
    index 0000000000..705fefb7a2
    --- /dev/null
    +++ b/src/test/resources/unit/regex/word_class_complement.t
    @@ -0,0 +1,27 @@
    +#!/usr/bin/perl
    +use strict;
    +use warnings;
    +use Test::More;
    +
    +for my $code_point (0x7f, 0x80, 0xaa, 0xff, 0x100, 0x200c) {
    +    my $character = chr $code_point;
    +    utf8::upgrade($character);
    +    my $word = $character =~ /[\w]/ ? 1 : 0;
    +    my $not_word = $character =~ /[\W]/ ? 1 : 0;
    +    is($word + $not_word, 1,
    +       sprintf('U+%04X belongs to exactly one Unicode word class', $code_point));
    +    is($word, $character =~ /\w/ ? 1 : 0,
    +       sprintf('U+%04X has the same plain and class word result', $code_point));
    +}
    +
    +for my $code_point (0x7f, 0x80, 0xaa, 0xff) {
    +    my $byte_character = chr $code_point;
    +    my $word = $byte_character =~ /[\w]/ ? 1 : 0;
    +    my $not_word = $byte_character =~ /[\W]/ ? 1 : 0;
    +    is($word + $not_word, 1,
    +       sprintf('byte U+%04X belongs to exactly one word class', $code_point));
    +    is($word, $byte_character =~ /\w/ ? 1 : 0,
    +       sprintf('byte U+%04X has the same plain and class word result', $code_point));
    +}
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex_joni_native_script_run.t b/src/test/resources/unit/regex_joni_native_script_run.t
    new file mode 100644
    index 0000000000..3573fec55b
    --- /dev/null
    +++ b/src/test/resources/unit/regex_joni_native_script_run.t
    @@ -0,0 +1,34 @@
    +use strict;
    +use utf8;
    +use threads;
    +use Test::More;
    +
    +ok("abc" =~ /\A(*script_run:.*)\z/,
    +   'a single Latin script run matches');
    +ok("אבג" =~ /\A(*sr:.*)\z/,
    +   'short script-run spelling matches Hebrew');
    +ok("a\N{HEBREW LETTER ALEF}" !~ /\A(*script_run:.*)\z/,
    +   'mixed scripts do not match');
    +ok("あ漢" =~ /\A(*script_run:.*)\z/,
    +   'Japanese Han and Hiragana share a permitted run');
    +ok("\x{0378}" =~ /\A(*script_run:.)\z/,
    +   'one Unknown code point is permitted');
    +ok("\x{0378}\x{0379}" !~ /\A(*script_run:..)\z/,
    +   'two Unknown code points are rejected');
    +ok("1\x{0E51}" !~ /\A(*script_run:..)\z/,
    +   'different decimal digit sets are rejected');
    +
    +ok("abc" =~ /\A(*script_run:(?:a|ab))c\z/,
    +   'ordinary script_run can backtrack within its body');
    +ok("abc" !~ /\A(*atomic_script_run:(?:a|ab))c\z/,
    +   'atomic script_run does not backtrack within its body');
    +ok("abc" !~ /\A(*asr:(?:a|ab))c\z/,
    +   'atomic short spelling has the same boundary');
    +
    +my $thread_pattern = threads->create(sub { qr/\A(*sr:.*)\z/ })->join;
    +ok("אבג" =~ $thread_pattern,
    +   'script-run regex retains semantics across thread snapshot join');
    +ok("a\N{HEBREW LETTER ALEF}" !~ $thread_pattern,
    +   'thread snapshot retains mixed-script rejection');
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex_joni_search_optimizer.t b/src/test/resources/unit/regex_joni_search_optimizer.t
    new file mode 100644
    index 0000000000..65e276f29d
    --- /dev/null
    +++ b/src/test/resources/unit/regex_joni_search_optimizer.t
    @@ -0,0 +1,71 @@
    +use strict;
    +use utf8;
    +use Test::More;
    +use threads;
    +
    +my $g_subject = ('a' x 20_000) . 'b';
    +my $g_hits = 0;
    +for my $offset (1 .. 400) {
    +    pos($g_subject) = $offset;
    +    $g_hits++ if $g_subject =~ /\Gb/g;
    +}
    +is($g_hits, 0, '\\G rejection remains anchored at each global start');
    +
    +my $anchored = 'abcdefg' x 30_000;
    +ok($anchored !~ /^XX\d{1,10}cde/,
    +   'absolute anchored required literal rejects a long subject');
    +
    +my $implicit = ('0' x 40_000) . '::: 0c';
    +for my $pattern (
    +        qr/.*:::\s*ab/, qr/.*?:::\s*ab/,
    +        qr/.*:::\s*ab/i, qr/.*?:::\s*ab/i) {
    +    ok($implicit !~ $pattern,
    +       'greedy or lazy implicit anchor rejects missing required literal');
    +}
    +
    +for my $character ("\N{CENT SIGN}", "\N{EURO SIGN}", "\N{GRINNING FACE}") {
    +    my $subject = ('0' x 1_000) . $character . 'x' . $character . 'ok';
    +    ok($subject =~ /.*${character}ok/,
    +       'UTF-8 literal keeps a later matching candidate after an earlier prefix');
    +    ok($subject !~ /.*${character}missing/,
    +       'UTF-8 literal rejects a missing required suffix');
    +}
    +
    +ok("prefix\n:::ab" !~ /\A.*:::ab/,
    +   'non-multiline greedy star does not cross a newline');
    +
    +my $global = ('0' x 1_000) . ('1' x 40_000);
    +my $matches = 0;
    +$matches++ while $global =~ /0/g;
    +is($matches, 1_000, 'long global scan preserves every match');
    +
    +my @threads = map { threads->create(sub {
    +    my $subject = 'ab' x 10_000;
    +    utf8::upgrade($subject);
    +    my $count = 0;
    +    $count++ while $subject =~ /\Ga+ba+b/g && $count < 100;
    +    return $count;
    +}) } 1 .. 2;
    +is_deeply([ map { $_->join } @threads ], [100, 100],
    +          'two threaded global matchers preserve isolated anchored progress');
    +
    +my ($callback_count, $nested_callback_count, $nested_match) = (0, 0, 0);
    +my $nested_callback = qr/x(?{ $nested_callback_count++ })y/;
    +ok('ab' =~ /a(?{
    +        $callback_count++;
    +        $nested_match = 'xy' =~ $nested_callback;
    +    })b/x,
    +   'callback reentry preserves the outer matcher stack');
    +is($callback_count, 1, 'reentrant callback executes exactly once');
    +ok($nested_match, 'nested callback matcher succeeds');
    +is($nested_callback_count, 1, 'nested callback executes exactly once');
    +
    +my $nested_plain = qr/inn/;
    +my $dynamic_result = qr/b/;
    +ok('abc' =~ /a(??{
    +        'inner' =~ $nested_plain;
    +        $dynamic_result;
    +    })c/x,
    +   'dynamic continuation may run a nested matcher');
    +
    +done_testing;
    diff --git a/src/test/resources/unit/regex_upper_lower_property_alias_fold.t b/src/test/resources/unit/regex_upper_lower_property_alias_fold.t
    new file mode 100644
    index 0000000000..5a632d1829
    --- /dev/null
    +++ b/src/test/resources/unit/regex_upper_lower_property_alias_fold.t
    @@ -0,0 +1,22 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +
    +for my $property (qw(Upper Uppercase XPosixUpper)) {
    +    ok('A' =~ qr/\p{$property}/, "$property contains uppercase without /i");
    +    ok('a' !~ qr/\p{$property}/, "$property excludes lowercase without /i");
    +    ok('A' =~ qr/\p{$property}/i, "$property /i contains uppercase");
    +    ok('a' =~ qr/\p{$property}/i, "$property /i folds lowercase");
    +}
    +
    +for my $property (qw(Lower Lowercase XPosixLower)) {
    +    ok('a' =~ qr/\p{$property}/, "$property contains lowercase without /i");
    +    ok('A' !~ qr/\p{$property}/, "$property excludes uppercase without /i");
    +    ok('a' =~ qr/\p{$property}/i, "$property /i contains lowercase");
    +    ok('A' =~ qr/\p{$property}/i, "$property /i folds uppercase");
    +}
    +
    +ok('1' !~ /\p{Upper}/i, 'casing alias /i does not add non-letters');
    +ok('1' !~ /\p{Lower}/i, 'lowercase alias /i does not add non-letters');
    +
    +done_testing();
    diff --git a/src/test/resources/unit/runtime/filetest_perl_executable.t b/src/test/resources/unit/runtime/filetest_perl_executable.t
    new file mode 100644
    index 0000000000..cb93872bd6
    --- /dev/null
    +++ b/src/test/resources/unit/runtime/filetest_perl_executable.t
    @@ -0,0 +1,6 @@
    +use strict;
    +use warnings;
    +use Test::More tests => 2;
    +
    +ok(-B $^X, 'the active Perl executable is binary');
    +ok(!-T $^X, 'the active Perl executable is not text');
    diff --git a/src/test/resources/unit/source_location_index.t b/src/test/resources/unit/source_location_index.t
    new file mode 100644
    index 0000000000..91b067c791
    --- /dev/null
    +++ b/src/test/resources/unit/source_location_index.t
    @@ -0,0 +1,32 @@
    +use strict;
    +use warnings;
    +use utf8;
    +use Test::More tests => 5;
    +
    +sub error_for {
    +    my ($padding, $line, $file, $message) = @_;
    +    my $source = ("\n" x $padding)
    +        . "use utf8;\n"
    +        . qq{#line $line "$file"\n}
    +        . qq{die "$message";\n};
    +    eval $source;
    +    return $@;
    +}
    +
    +my $first = error_for(4_000, 700, 'same-alpha.pl', 'caf\\x{00e9}');
    +is($first, "caf\x{00e9} at same-alpha.pl line 700.\n",
    +    'blank-heavy multibyte source preserves logical location');
    +
    +my $equal = error_for(4_000, 700, 'same-alpha.pl', 'caf\\x{00e9}');
    +is($equal, $first, 'equal source identity repeats the exact diagnostic');
    +
    +my $distinct = error_for(4_000, 701, 'other-beta.pl', 'caf\\x{00e9}');
    +is($distinct, "caf\x{00e9} at other-beta.pl line 701.\n",
    +    'distinct source identity retains its own file and line');
    +
    +like(error_for(8_000, 9, 'deep.pl', 'deep'),
    +    qr/^deep at deep\.pl line 9\.\n\z/,
    +    'larger padding does not alter mapped line');
    +is(error_for(4_000, 700, 'same-alpha.pl', 'again'),
    +    "again at same-alpha.pl line 700.\n",
    +    'repeated lookup keeps logical source identity stable');
    diff --git a/src/test/resources/unit/string_control_punctuation.t b/src/test/resources/unit/string_control_punctuation.t
    new file mode 100644
    index 0000000000..dc825919c0
    --- /dev/null
    +++ b/src/test/resources/unit/string_control_punctuation.t
    @@ -0,0 +1,52 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +
    +my @punctuation = (
    +    [' ',  96], ['!',  97], ['"',  98], ['#',  99], ['$', 100], ['%', 101],
    +    ['&', 102], ["'", 103], ['(', 104], [')', 105], ['*', 106], ['+', 107],
    +    [',', 108], ['-', 109], ['.', 110], ['/', 111], [':', 122], [';', 123],
    +    ['<', 124], ['=', 125], ['>', 126], ['?', 127], ['@',   0], ['[',  27],
    +    ['\\', 28], [']',  29], ['^',  30], ['_',  31], ['`',  32], ['|',  60],
    +    ['}',  61], ['~',  62],
    +);
    +
    +sub control_eval {
    +    my ($operand) = @_;
    +    my $source;
    +    if ($operand eq '\\') {
    +        $source = join '', chr(34), chr(92), 'c', chr(92), chr(92), chr(34);
    +    }
    +    else {
    +        my @pairs = (['(', ')'], ['[', ']'], ['{', '}'], ['<', '>'],
    +                     ['!', '!'], ['~', '~']);
    +        my ($open, $close) = @{(grep {
    +            $operand ne $_->[0] && $operand ne $_->[1]
    +        } @pairs)[0]};
    +        $source = 'qq' . $open . '\\c' . $operand . $close;
    +    }
    +
    +    my @warnings;
    +    local $SIG{__WARN__} = sub { push @warnings, @_ };
    +    my $value = eval $source;
    +    return ($value, $@, \@warnings);
    +}
    +
    +for my $case (@punctuation) {
    +    my ($operand, $expected) = @$case;
    +    my ($value, $error) = control_eval($operand);
    +    is $error, '', sprintf('\\c operand 0x%02X compiles', ord($operand));
    +    is ord($value), $expected,
    +            sprintf('\\c operand 0x%02X maps to %d', ord($operand), $expected);
    +}
    +
    +my (undef, $brace_error) = control_eval('{');
    +like $brace_error, qr/Use ";" instead of "\\c\{"/,
    +        '\\c left brace retains its dedicated diagnostic';
    +
    +{
    +    no warnings qw(syntax regexp experimental::regex_sets);
    +    like "\c#", qr/(?[\c#])/, 'regex_sets.t row 65 subject matches itself';
    +}
    +
    +done_testing;
    diff --git a/src/test/resources/unit/system_command_utf8_byte_output.t b/src/test/resources/unit/system_command_utf8_byte_output.t
    new file mode 100644
    index 0000000000..0de78a39e7
    --- /dev/null
    +++ b/src/test/resources/unit/system_command_utf8_byte_output.t
    @@ -0,0 +1,17 @@
    +use strict;
    +use warnings;
    +use utf8;
    +use Test::More tests => 5;
    +
    +my $command = qq{"$^X" -e "binmode STDOUT; print STDOUT pack q(H*), q(e280a2)"};
    +my $captured = qx{$command};
    +
    +ok(!utf8::is_utf8($captured), 'qx capture is not UTF-8 flagged');
    +is(length($captured), 3, 'qx capture retains three octets');
    +is(unpack('H*', $captured), 'e280a2', 'qx capture retains exact UTF-8 bytes');
    +
    +my $encoded = "\x{2022}";
    +utf8::encode($encoded);
    +is($captured, $encoded, 'qx bytes equal explicitly encoded Unicode output');
    +is(join(',', map { ord } split //, $captured), '226,128,162',
    +    'qx exposes subprocess octets without decoding');
    diff --git a/src/test/resources/unit/threads_dynamic_code_array_state.t b/src/test/resources/unit/threads_dynamic_code_array_state.t
    new file mode 100644
    index 0000000000..151dcbf63f
    --- /dev/null
    +++ b/src/test/resources/unit/threads_dynamic_code_array_state.t
    @@ -0,0 +1,39 @@
    +use strict;
    +use warnings;
    +use threads;
    +use re 'eval';
    +use Test::More tests => 2;
    +
    +sub eval_match {
    +    my ($subject, $regex) = @_;
    +    my $matched;
    +    eval q{$matched = $subject =~ /$regex/ ? 1 : 0};
    +    return $matched || 0;
    +}
    +
    +my $worker = threads->create(sub {
    +    my $trusted = 'Q';
    +    my $runtime = 'R';
    +    my @mixed = ('L', qr/(??{$trusted})/, '(??{$runtime})');
    +    my $first = eval_match('L Q R', qr/^@mixed$/);
    +
    +    $trusted = 'S';
    +    $runtime = 'T';
    +    my $second = eval_match('L S T', qr/^@mixed$/);
    +
    +    my $token = '[a-z]';
    +    my @parts = (qr/(??{$token})/);
    +    my $subject = 'a1b';
    +    pos($subject) = 1;
    +    my $failed = !($subject =~ /\G@parts/gc) && pos($subject) == 1;
    +    $token = '1';
    +    my $resumed = $subject =~ /\G@parts/gc
    +        && $& eq '1' && pos($subject) == 2;
    +
    +    return join('|', $first, $second, $failed, $resumed);
    +});
    +
    +is($worker->join, '1|1|1|1',
    +    'child mixed source retains cells and /gc state across eval reuse');
    +ok(eval_match('parent', qr/^parent$/),
    +    'parent eval regex remains usable after child-first execution');
    diff --git a/src/test/resources/unit/threads_regex_callback_clone_isolation.t b/src/test/resources/unit/threads_regex_callback_clone_isolation.t
    new file mode 100644
    index 0000000000..0cfd012c89
    --- /dev/null
    +++ b/src/test/resources/unit/threads_regex_callback_clone_isolation.t
    @@ -0,0 +1,86 @@
    +use strict;
    +use warnings;
    +use threads;
    +use Test::More;
    +use Scalar::Util qw(refaddr);
    +use re 'eval';
    +
    +my $cell = { genuine => 0, dynamic => 0, nested => 0, trace => [] };
    +my $state = { left => $cell, right => $cell };
    +$state->{self} = $state;
    +
    +my $leaf = qr/(?{
    +    ++$state->{right}{nested};
    +    push @{$state->{left}{trace}}, 'n';
    +})A/;
    +my $pattern = qr/^(?{
    +    ++$state->{left}{genuine};
    +    push @{$state->{right}{trace}}, 'g';
    +})(??{
    +    ++$state->{right}{dynamic};
    +    push @{$state->{left}{trace}}, 'd';
    +    $leaf;
    +})$/;
    +
    +my $ordinary_leaf = { label => 'parent', hits => 0 };
    +my $ordinary = { left => $ordinary_leaf, right => $ordinary_leaf };
    +$ordinary->{self} = $ordinary;
    +my $ordinary_code = sub {
    +    my ($label) = @_;
    +    $ordinary->{right}{label} = $label;
    +    ++$ordinary->{left}{hits};
    +    return join(':', $ordinary->{left}{label}, $ordinary->{right}{hits},
    +        refaddr($ordinary->{left}) == refaddr($ordinary->{right}),
    +        refaddr($ordinary->{self}) == refaddr($ordinary));
    +};
    +my $plain = qr/^A$/;
    +
    +ok('A' =~ $pattern, 'parent warms genuine, dynamic, and nested callback qr');
    +is(join(':', @{$cell}{qw(genuine dynamic nested)}, join('', @{$cell->{trace}})),
    +   '1:1:1:gdn', 'warm match updates the one captured graph');
    +is($ordinary_code->('parent'), 'parent:1:1:1',
    +   'ordinary closure graph is warmed as clone control');
    +ok('A' =~ $plain, 'noncallback qr is warmed as clone control');
    +
    +sub child_result {
    +    my ($label) = @_;
    +    my $before = join(':', @{$cell}{qw(genuine dynamic nested)},
    +        join('', @{$cell->{trace}}));
    +    my $identity = join(':',
    +        refaddr($state->{left}) == refaddr($state->{right}),
    +        refaddr($state->{self}) == refaddr($state));
    +    my $first = 'A' =~ $pattern ? 1 : 0;
    +    my $second = 'A' =~ $pattern ? 1 : 0;
    +    my $after = join(':', @{$cell}{qw(genuine dynamic nested)},
    +        join('', @{$cell->{trace}}));
    +    my $ordinary_result = $ordinary_code->($label);
    +    my $plain_result = join(':', 'A' =~ $plain ? 1 : 0, 'B' !~ $plain ? 1 : 0);
    +    return [$before, $identity, $first, $second, $after,
    +        $ordinary_result, $plain_result];
    +}
    +
    +sub expected_child {
    +    my ($label) = @_;
    +    return ['1:1:1:gdn', '1:1', 1, 1, '3:3:3:gdngdngdn',
    +        "$label:2:1:1", '1:1'];
    +}
    +
    +my $first = threads->create(\&child_result, 'child-one')->join;
    +is_deeply($first, expected_child('child-one'),
    +    'first child gets one coherent cloned callback and closure graph');
    +is(join(':', @{$cell}{qw(genuine dynamic nested)}, join('', @{$cell->{trace}}),
    +        $ordinary_leaf->{label}, $ordinary_leaf->{hits}),
    +   '1:1:1:gdn:parent:1', 'first child cannot mutate parent graphs');
    +
    +my $second = threads->create(\&child_result, 'child-two')->join;
    +is_deeply($second, expected_child('child-two'),
    +    'second child starts from the parent snapshot, not the first child');
    +is(join(':', @{$cell}{qw(genuine dynamic nested)}, join('', @{$cell->{trace}}),
    +        $ordinary_leaf->{label}, $ordinary_leaf->{hits}),
    +   '1:1:1:gdn:parent:1', 'repeated child leaves parent graphs isolated');
    +
    +ok('A' =~ $pattern, 'parent callback qr remains reusable after repeated children');
    +is(join(':', @{$cell}{qw(genuine dynamic nested)}, join('', @{$cell->{trace}})),
    +   '2:2:2:gdngdn', 'parent retains its own callback cells');
    +
    +done_testing;
    diff --git a/src/test/resources/unit/threads_regex_callback_reuse.t b/src/test/resources/unit/threads_regex_callback_reuse.t
    new file mode 100644
    index 0000000000..e20e83d3f9
    --- /dev/null
    +++ b/src/test/resources/unit/threads_regex_callback_reuse.t
    @@ -0,0 +1,22 @@
    +use strict;
    +use warnings;
    +use threads;
    +use Test::More;
    +
    +my $pattern = qr/(?{ 1 })(??{ 'A' })/;
    +
    +ok('A' =~ $pattern, 'parent warms callback and dynamic regex');
    +
    +my $worker = threads->create(sub {
    +    my $first = 'A' =~ $pattern;
    +    my $second = 'A' =~ $pattern;
    +    my $reject = 'B' !~ $pattern;
    +    return $first && $second && $reject;
    +});
    +
    +ok($worker->join,
    +    'child reuses the warmed callback and dynamic regex without recompilation drift');
    +ok('A' =~ $pattern, 'parent regex remains reusable after child completion');
    +ok('B' !~ $pattern, 'parent regex retains its dynamic match program');
    +
    +done_testing;
    diff --git a/src/test/resources/unit/threads_regex_callback_shared_wrapper.t b/src/test/resources/unit/threads_regex_callback_shared_wrapper.t
    new file mode 100644
    index 0000000000..ef571337f5
    --- /dev/null
    +++ b/src/test/resources/unit/threads_regex_callback_shared_wrapper.t
    @@ -0,0 +1,45 @@
    +use strict;
    +use warnings;
    +use threads;
    +use Test::More;
    +
    +my $count = 0;
    +my $events = [];
    +my $shared = qr/(?{
    +    ++$count;
    +    push @$events, $count;
    +})A/;
    +
    +my $left = qr/^$shared$/;
    +my $right = qr/^$shared$/;
    +
    +ok('A' =~ $left, 'parent warms first qr wrapper');
    +is_deeply([$count, $events], [1, [1]], 'parent callback state is warm');
    +
    +my $first_child = threads->create(sub {
    +    my $left_ok = 'A' =~ $left;
    +    my $right_ok = 'A' =~ $right;
    +    return [$left_ok && $right_ok, $count, [@$events]];
    +})->join;
    +
    +is_deeply($first_child, [1, 3, [1, 2, 3]],
    +    'two qr roots share one child-side callback graph');
    +is_deeply([$count, $events], [1, [1]],
    +    'shared child callback graph remains isolated from parent');
    +
    +my $second_child = threads->create(sub {
    +    my $right_ok = 'A' =~ $right;
    +    my $left_ok = 'A' =~ $left;
    +    return [$right_ok && $left_ok, $count, [@$events]];
    +})->join;
    +
    +is_deeply($second_child, [1, 3, [1, 2, 3]],
    +    'repeated child recreates one shared callback graph');
    +is_deeply([$count, $events], [1, [1]],
    +    'repeated shared-wrapper clone leaves parent isolated');
    +
    +ok('A' =~ $right, 'parent second qr wrapper remains reusable');
    +is_deeply([$count, $events], [2, [1, 2]],
    +    'parent qr roots retain their shared callback state');
    +
    +done_testing;
    diff --git a/src/test/resources/unit/warnings_nested_scope_restore.t b/src/test/resources/unit/warnings_nested_scope_restore.t
    new file mode 100644
    index 0000000000..ea82535644
    --- /dev/null
    +++ b/src/test/resources/unit/warnings_nested_scope_restore.t
    @@ -0,0 +1,40 @@
    +use strict;
    +use warnings;
    +use Test::More;
    +
    +{
    +    no warnings 'uninitialized';
    +    my ($value, @warnings);
    +    local $SIG{__WARN__} = sub { push @warnings, @_ };
    +    my $number = $value + 1;
    +    ok($number == 1 && !@warnings,
    +        'nested no warnings suppresses its lexical category');
    +}
    +
    +my ($outer_value, @outer_warnings);
    +{
    +    local $SIG{__WARN__} = sub { push @outer_warnings, @_ };
    +    my $number = $outer_value + 1;
    +    is($number, 1, 'leaving no warnings restores nonfatal execution');
    +}
    +like(join('', @outer_warnings), qr/uninitialized value/i,
    +    'leaving no warnings restores the outer enabled category');
    +
    +{
    +    use warnings FATAL => 'uninitialized';
    +    my $value;
    +    my $ok = eval { my $number = $value + 1; 1 };
    +    ok(!$ok && $@ =~ /uninitialized value/i,
    +        'nested fatal warnings apply inside their lexical block');
    +}
    +
    +my ($after_fatal, @after_warnings);
    +my $after_ok;
    +{
    +    local $SIG{__WARN__} = sub { push @after_warnings, @_ };
    +    $after_ok = eval { my $number = $after_fatal + 1; 1 };
    +}
    +ok($after_ok && $@ eq '' && join('', @after_warnings) =~ /uninitialized value/i,
    +    'leaving fatal warnings restores the outer nonfatal category');
    +
    +done_testing;
    diff --git a/third_party/joni/src/org/joni/Analyser.java b/third_party/joni/src/org/joni/Analyser.java
    index d5ec4bfa50..36ec09ffe9 100644
    --- a/third_party/joni/src/org/joni/Analyser.java
    +++ b/third_party/joni/src/org/joni/Analyser.java
    @@ -34,6 +34,9 @@
     
     import java.util.IllegalFormatConversionException;
     import java.util.ArrayList;
    +import java.util.Collections;
    +import java.util.IdentityHashMap;
    +import java.util.Set;
     
     import org.jcodings.CaseFoldCodeItem;
     import org.jcodings.Encoding;
    @@ -57,6 +60,7 @@
     import org.joni.constants.internal.NodeType;
     import org.joni.constants.internal.StackPopLevel;
     import org.joni.constants.internal.TargetInfo;
    +import org.joni.exception.ValueException;
     
     final class Analyser extends Parser {
     
    @@ -81,6 +85,7 @@ protected final void compile() {
     
             Node root = parseRegexp(); // onig_parse_make_tree
             regex.numMem = env.numMem;
    +        resolveForwardNamedBackrefs(root);
     
             if (Config.USE_NAMED_GROUP) {
                 /* mixed use named group and no-named group */
    @@ -160,7 +165,8 @@ protected final void compile() {
             // unreachable. The ordinary optimizer assumes every concatenated node
             // remains mandatory, so its minimum-length and literal-search filters
             // are not sound for these programs.
    -        if (Config.OPTIMIZE && !env.hasControlVerb && !regex.hasDynamicOptions) {
    +        if (Config.OPTIMIZE && !env.hasControlVerb && !env.hasCallout
    +                && !regex.hasDynamicOptions) {
                 setOptimizedInfoFromTree(root);
             }
     
    @@ -188,6 +194,46 @@ protected final void compile() {
             regex.options &= ~syntax.options;
         }
     
    +    private void resolveForwardNamedBackrefs(Node node) {
    +        switch (node.getType()) {
    +        case NodeType.LIST:
    +        case NodeType.ALT:
    +            ListNode list = (ListNode)node;
    +            do {
    +                resolveForwardNamedBackrefs(list.value);
    +            } while ((list = list.tail) != null);
    +            break;
    +        case NodeType.QTFR:
    +            resolveForwardNamedBackrefs(((QuantifierNode)node).target);
    +            break;
    +        case NodeType.ENCLOSE:
    +            EncloseNode enclose = (EncloseNode)node;
    +            if (enclose.assertionCondition != null) {
    +                resolveForwardNamedBackrefs(enclose.assertionCondition);
    +            }
    +            if (enclose.target != null) resolveForwardNamedBackrefs(enclose.target);
    +            break;
    +        case NodeType.ANCHOR:
    +            AnchorNode anchor = (AnchorNode)node;
    +            if (anchor.target != null) resolveForwardNamedBackrefs(anchor.target);
    +            break;
    +        case NodeType.BREF:
    +            BackRefNode backref = (BackRefNode)node;
    +            if (backref.unresolvedName != null) {
    +                NameEntry entry = regex.nameToGroupNumbers(backref.unresolvedName,
    +                        backref.unresolvedNameP, backref.unresolvedNameEnd);
    +                if (entry == null) {
    +                    throw new ValueException(PERL_REFERENCE_TO_NONEXISTENT_NAMED_GROUP,
    +                            backref.unresolvedNameEnd - getBegin());
    +                }
    +                backref.resolve(entry.getBackRefs(), env);
    +            }
    +            break;
    +        default:
    +            break;
    +        }
    +    }
    +
         private String encStringToString(byte[]bytes, int p, int end) {
             StringBuilder sb = new StringBuilder("\nPATTERN: /");
     
    @@ -449,14 +495,14 @@ private int getMinMatchLength(Node node) {
                 BackRefNode br = (BackRefNode)node;
                 if (br.isRecursion()) break;
     
    -            if (br.back[0] > env.numMem) {
    +            if (invalidBackrefNode(br.back[0])) {
                     if (!syntax.op3OptionECMAScript()) newValueException(INVALID_BACKREF);
                 } else {
                     min = getMinMatchLength(env.memNodes[br.back[0]]);
                 }
     
                 for (int i=1; i env.numMem) {
    +                if (invalidBackrefNode(br.back[i])) {
                         if (!syntax.op3OptionECMAScript()) newValueException(INVALID_BACKREF);
                     } else {
                         int tmin = getMinMatchLength(env.memNodes[br.back[i]]);
    @@ -596,7 +642,7 @@ private int getMaxMatchLength(Node node) {
                 }
     
                 for (int i=0; i env.numMem) {
    +                if (invalidBackrefNode(br.back[i])) {
                         if(!syntax.op3OptionECMAScript()) newValueException(INVALID_BACKREF);
                     } else {
                         int tmax = getMaxMatchLength(env.memNodes[br.back[i]]);
    @@ -674,10 +720,11 @@ private int getMaxMatchLength(Node node) {
         private static final int GET_CHAR_LEN_VARLEN            = -1;
         private static final int GET_CHAR_LEN_TOP_ALT_VARLEN    = -2;
         protected final int getCharLengthTree(Node node) {
    -        return getCharLengthTree(node, 0);
    +        return getCharLengthTree(node, 0,
    +                Collections.newSetFromMap(new IdentityHashMap<>()));
         }
     
    -    private int getCharLengthTree(Node node, int level) {
    +    private int getCharLengthTree(Node node, int level, Set activeCalls) {
             level++;
     
             int len = 0;
    @@ -687,7 +734,7 @@ private int getCharLengthTree(Node node, int level) {
             case NodeType.LIST:
                 ListNode ln = (ListNode)node;
                 do {
    -                int tlen = getCharLengthTree(ln.value, level);
    +                int tlen = getCharLengthTree(ln.value, level, activeCalls);
                     if (returnCode == 0) len = MinMaxLen.distanceAdd(len, tlen);
                 } while (returnCode == 0 && (ln = ln.tail) != null);
                 break;
    @@ -696,9 +743,9 @@ private int getCharLengthTree(Node node, int level) {
                 ListNode an = (ListNode)node;
                 boolean varLen = false;
     
    -            int tlen = getCharLengthTree(an.value, level);
    +            int tlen = getCharLengthTree(an.value, level, activeCalls);
                 while (returnCode == 0 && (an = an.tail) != null) {
    -                int tlen2 = getCharLengthTree(an.value, level);
    +                int tlen2 = getCharLengthTree(an.value, level, activeCalls);
                     if (returnCode == 0) {
                         if (tlen != tlen2) varLen = true;
                     }
    @@ -720,12 +767,15 @@ private int getCharLengthTree(Node node, int level) {
             case NodeType.STR:
                 StringNode sn = (StringNode)node;
                 len = sn.length(enc);
    +            if (sn.isAmbig() && sn.isDontGetOptInfo() && len > 1) {
    +                returnCode = GET_CHAR_LEN_VARLEN;
    +            }
                 break;
     
             case NodeType.QTFR:
                 QuantifierNode qn = (QuantifierNode)node;
                 if (qn.lower == qn.upper) {
    -                tlen = getCharLengthTree(qn.target, level);
    +                tlen = getCharLengthTree(qn.target, level, activeCalls);
                     if (returnCode == 0) len = MinMaxLen.distanceMultiply(tlen, qn.lower);
                 } else {
                     returnCode = GET_CHAR_LEN_VARLEN;
    @@ -735,10 +785,14 @@ private int getCharLengthTree(Node node, int level) {
             case NodeType.CALL:
                 if (Config.USE_SUBEXP_CALL) {
                     CallNode cn = (CallNode)node;
    -                if (!cn.isRecursion()) {
    -                    len = getCharLengthTree(cn.target, level);
    -                } else {
    +                if (!activeCalls.add(cn.target)) {
                         returnCode = GET_CHAR_LEN_VARLEN;
    +                } else {
    +                    try {
    +                        len = getCharLengthTree(cn.target, level, activeCalls);
    +                    } finally {
    +                        activeCalls.remove(cn.target);
    +                    }
                     }
                 } // USE_SUBEXP_CALL
                 break;
    @@ -757,7 +811,7 @@ private int getCharLengthTree(Node node, int level) {
                         if (en.isCLenFixed()) {
                             len = en.charLength;
                         } else {
    -                        len = getCharLengthTree(en.target, level);
    +                        len = getCharLengthTree(en.target, level, activeCalls);
                             if (returnCode == 0) {
                                 en.charLength = len;
                                 en.setCLenFixed();
    @@ -769,7 +823,7 @@ private int getCharLengthTree(Node node, int level) {
                 case EncloseType.OPTION:
                 case EncloseType.STOP_BACKTRACK:
                 case EncloseNode.CONDITION:
    -                len = getCharLengthTree(en.target, level);
    +                len = getCharLengthTree(en.target, level, activeCalls);
                     break;
     
                 case EncloseType.ABSENT:
    @@ -1329,9 +1383,10 @@ private void setCallAttr(CallNode cn) {
                 }
                 newValueException(UNDEFINED_NAME_REFERENCE, cn.nameP, cn.nameEnd);
             }
    -        // Perl subroutine calls do not replace captures already visible in the
    -        // caller. Reused branch-reset numbers and DEFINE-only groups need the
    -        // existing call-frame snapshot path.
    +        // PerlOnJava subroutine calls do not replace captures already visible
    +        // in the caller.  Generic Joni Perl-like syntaxes retain Joni's
    +        // established capture-publication behavior.
    +        cn.preserveCallerCaptures = "PERLONJAVA".equals(syntax.name);
             if ((cn.lexicalTarget == null && env.isMultiplexMemNode(cn.groupNum))
                     || (isInsideDefine(en) && !isInsideDefine(cn))) {
                 cn.setRecursion();
    @@ -1414,6 +1469,10 @@ protected final void setupSubExpCall(Node node) {
                                 newValueException(MULTIPLEX_DEFINITION_NAME_CALL, cn.nameP, cn.nameEnd);
                             } else {
                                 cn.groupNum = ne.backRef1; // ne.backNum == 1 ? ne.backRef1 : ne.backRefs[0]; // ??? need to check ?
    +                            if (ne.backNum == 1) {
    +                                cn.lexicalTarget = env.physicalNamedMemNode(
    +                                        ne.getPhysicalBackRefs()[0]);
    +                            }
                                 if (ne.backNum > 1) cn.setRecursion();
                                 setCallAttr(cn);
                             }
    @@ -1489,6 +1548,7 @@ private Node setupLookBehind(AnchorNode node) {
                     node.variableLookBehindMin = min;
                     node.variableLookBehindMax = max;
                     node.variableLookBehindTargetLength = -1;
    +                warnVariableLookBehindCapture(node, min, max);
                     returnCode = 0;
                     return node;
                 }
    @@ -1514,6 +1574,10 @@ private Node setupLookBehind(AnchorNode node) {
                 break;
             case GET_CHAR_LEN_TOP_ALT_VARLEN:
                 if (syntax.differentLengthAltLookBehind()) {
    +                CharLengthRange range = getCharLengthRange(node.target);
    +                if (range != null) {
    +                    warnVariableLookBehindCapture(node, range.min, range.max);
    +                }
                     return divideLookBehindAlternatives(node);
                 } else {
                     newSyntaxException(INVALID_LOOK_BEHIND_PATTERN);
    @@ -1545,10 +1609,50 @@ private boolean setupBoundedQuantifierLookBehind(AnchorNode node) {
             node.variableLookBehindMin = range.min;
             node.variableLookBehindMax = range.max;
             node.variableLookBehindTargetLength = -1;
    +        warnVariableLookBehindCapture(node, range.min, range.max);
             returnCode = 0;
             return true;
         }
     
    +    private void warnVariableLookBehindCapture(AnchorNode node, int min, int max) {
    +        if (node.variableLookBehindCaptureWarned || min == max || !containsCapture(node.target,
    +                Collections.newSetFromMap(new IdentityHashMap<>()))) {
    +            return;
    +        }
    +        node.variableLookBehindCaptureWarned = true;
    +        String message = node.type == AnchorType.LOOK_BEHIND_NOT
    +                ? PERL_NEGATIVE_VARIABLE_LOOKBEHIND_CAPTURE
    +                : PERL_POSITIVE_VARIABLE_LOOKBEHIND_CAPTURE;
    +        env.warnings.warn(message, getEnd() - getBegin());
    +    }
    +
    +    private boolean containsCapture(Node node, Set active) {
    +        if (node == null || !active.add(node)) return false;
    +        try {
    +            return switch (node.getType()) {
    +            case NodeType.LIST, NodeType.ALT -> {
    +                ListNode list = (ListNode)node;
    +                boolean found = false;
    +                do {
    +                    found |= containsCapture(list.value, active);
    +                } while (!found && (list = list.tail) != null);
    +                yield found;
    +            }
    +            case NodeType.QTFR -> containsCapture(((QuantifierNode)node).target, active);
    +            case NodeType.ANCHOR -> containsCapture(((AnchorNode)node).target, active);
    +            case NodeType.ENCLOSE -> {
    +                EncloseNode enclose = (EncloseNode)node;
    +                yield enclose.type == EncloseType.MEMORY
    +                        || containsCapture(enclose.target, active);
    +            }
    +            case NodeType.CALL -> containsCapture(((CallNode)node).target, active);
    +            default -> false;
    +            };
    +        } finally {
    +            active.remove(node);
    +        }
    +    }
    +
         private static final class CharLengthRange {
             final int min;
             final int max;
    @@ -1590,6 +1694,11 @@ void addAccept(int min, int max) {
         }
     
         private AcceptLengthInfo getAcceptLengthInfo(Node node) {
    +        return getAcceptLengthInfo(node,
    +                Collections.newSetFromMap(new IdentityHashMap<>()));
    +    }
    +
    +    private AcceptLengthInfo getAcceptLengthInfo(Node node, Set activeCalls) {
             if (node instanceof ControlVerbNode control) {
                 AcceptLengthInfo info = new AcceptLengthInfo();
                 if (control.kind == ControlVerbNode.Kind.ACCEPT) info.addAccept(0, 0);
    @@ -1604,7 +1713,7 @@ private AcceptLengthInfo getAcceptLengthInfo(Node node) {
                 result.addNormal(0, 0);
                 ListNode list = (ListNode)node;
                 do {
    -                AcceptLengthInfo item = getAcceptLengthInfo(list.value);
    +                AcceptLengthInfo item = getAcceptLengthInfo(list.value, activeCalls);
                     if (item == null) return null;
                     AcceptLengthInfo next = new AcceptLengthInfo();
                     if (result.hasAccept()) {
    @@ -1628,7 +1737,7 @@ private AcceptLengthInfo getAcceptLengthInfo(Node node) {
                 AcceptLengthInfo result = new AcceptLengthInfo();
                 ListNode alt = (ListNode)node;
                 do {
    -                AcceptLengthInfo branch = getAcceptLengthInfo(alt.value);
    +                AcceptLengthInfo branch = getAcceptLengthInfo(alt.value, activeCalls);
                     if (branch == null) return null;
                     if (branch.hasNormal()) result.addNormal(branch.normalMin, branch.normalMax);
                     if (branch.hasAccept()) result.addAccept(branch.acceptMin, branch.acceptMax);
    @@ -1636,9 +1745,11 @@ private AcceptLengthInfo getAcceptLengthInfo(Node node) {
                 return result;
             }
             case NodeType.STR: {
    -            int length = ((StringNode)node).length(enc);
    +            StringNode string = (StringNode)node;
    +            int length = string.length(enc);
                 AcceptLengthInfo info = new AcceptLengthInfo();
    -            info.addNormal(length, length);
    +            info.addNormal(string.isAmbig() && string.isDontGetOptInfo() && length > 1 ? 1 : length,
    +                    length);
                 return info;
             }
             case NodeType.CTYPE:
    @@ -1651,7 +1762,7 @@ private AcceptLengthInfo getAcceptLengthInfo(Node node) {
             case NodeType.QTFR: {
                 QuantifierNode quantifier = (QuantifierNode)node;
                 if (isRepeatInfinite(quantifier.upper)) return null;
    -            AcceptLengthInfo target = getAcceptLengthInfo(quantifier.target);
    +            AcceptLengthInfo target = getAcceptLengthInfo(quantifier.target, activeCalls);
                 if (target == null) return null;
                 AcceptLengthInfo info = new AcceptLengthInfo();
                 if (target.hasNormal()) {
    @@ -1678,7 +1789,7 @@ private AcceptLengthInfo getAcceptLengthInfo(Node node) {
                     info.addNormal(0, 0);
                     return info;
                 }
    -            return getAcceptLengthInfo(enclose.target);
    +            return getAcceptLengthInfo(enclose.target, activeCalls);
             }
             case NodeType.ANCHOR: {
                 // Nested assertions are their own ACCEPT boundary.
    @@ -1686,23 +1797,46 @@ private AcceptLengthInfo getAcceptLengthInfo(Node node) {
                 info.addNormal(0, 0);
                 return info;
             }
    -        case NodeType.CALL:
    -            // Subexpression calls are their own ACCEPT boundary; their
    -            // effective consumed width needs call-specific analysis.
    -            return null;
    +        case NodeType.CALL: {
    +            CallNode call = (CallNode)node;
    +            if (!activeCalls.add(call.target)) return null;
    +            try {
    +                AcceptLengthInfo target = getAcceptLengthInfo(call.target, activeCalls);
    +                if (target == null) return null;
    +
    +                // ACCEPT terminates the called subexpression rather than the
    +                // containing lookbehind, so both target exit kinds are normal
    +                // completions at the call site.
    +                AcceptLengthInfo info = new AcceptLengthInfo();
    +                if (target.hasNormal()) {
    +                    info.addNormal(target.normalMin, target.normalMax);
    +                }
    +                if (target.hasAccept()) {
    +                    info.addNormal(target.acceptMin, target.acceptMax);
    +                }
    +                return info;
    +            } finally {
    +                activeCalls.remove(call.target);
    +            }
    +        }
             default:
                 return null;
             }
         }
     
         private CharLengthRange getCharLengthRange(Node node) {
    +        return getCharLengthRange(node,
    +                Collections.newSetFromMap(new IdentityHashMap<>()));
    +    }
    +
    +    private CharLengthRange getCharLengthRange(Node node, Set activeCalls) {
             switch (node.getType()) {
             case NodeType.LIST: {
                 int min = 0;
                 int max = 0;
                 ListNode list = (ListNode)node;
                 do {
    -                CharLengthRange item = getCharLengthRange(list.value);
    +                CharLengthRange item = getCharLengthRange(list.value, activeCalls);
                     if (item == null) return null;
                     min = MinMaxLen.distanceAdd(min, item.min);
                     max = MinMaxLen.distanceAdd(max, item.max);
    @@ -1714,7 +1848,7 @@ private CharLengthRange getCharLengthRange(Node node) {
                 int max = 0;
                 ListNode alt = (ListNode)node;
                 do {
    -                CharLengthRange branch = getCharLengthRange(alt.value);
    +                CharLengthRange branch = getCharLengthRange(alt.value, activeCalls);
                     if (branch == null) return null;
                     min = Math.min(min, branch.min);
                     max = Math.max(max, branch.max);
    @@ -1722,8 +1856,11 @@ private CharLengthRange getCharLengthRange(Node node) {
                 return new CharLengthRange(min, max);
             }
             case NodeType.STR: {
    -            int length = ((StringNode)node).length(enc);
    -            return new CharLengthRange(length, length);
    +            StringNode string = (StringNode)node;
    +            int length = string.length(enc);
    +            return new CharLengthRange(
    +                    string.isAmbig() && string.isDontGetOptInfo() && length > 1 ? 1 : length,
    +                    length);
             }
             case NodeType.CTYPE:
             case NodeType.CCLASS:
    @@ -1732,7 +1869,7 @@ private CharLengthRange getCharLengthRange(Node node) {
             case NodeType.QTFR: {
                 QuantifierNode quantifier = (QuantifierNode)node;
                 if (isRepeatInfinite(quantifier.upper)) return null;
    -            CharLengthRange target = getCharLengthRange(quantifier.target);
    +            CharLengthRange target = getCharLengthRange(quantifier.target, activeCalls);
                 if (target == null) return null;
                 return new CharLengthRange(
                         MinMaxLen.distanceMultiply(target.min, quantifier.lower),
    @@ -1742,13 +1879,18 @@ private CharLengthRange getCharLengthRange(Node node) {
                 EncloseNode enclose = (EncloseNode)node;
                 if (enclose.type == EncloseType.ABSENT) return null;
                 if (enclose.type == EncloseType.DEFINE) return new CharLengthRange(0, 0);
    -            return getCharLengthRange(enclose.target);
    +            return getCharLengthRange(enclose.target, activeCalls);
             }
             case NodeType.ANCHOR:
                 return new CharLengthRange(0, 0);
             case NodeType.CALL: {
                 CallNode call = (CallNode)node;
    -            return call.isRecursion() ? null : getCharLengthRange(call.target);
    +            if (!activeCalls.add(call.target)) return null;
    +            try {
    +                return getCharLengthRange(call.target, activeCalls);
    +            } finally {
    +                activeCalls.remove(call.target);
    +            }
             }
             default:
                 return null;
    @@ -2141,11 +2283,119 @@ private Node expandCaseFoldString(Node node) {
             /* ending */
             Node xnode = topRoot != null ? topRoot : prevNode.p;
             xnode = addPerlReverseFoldPartitions(sn, xnode);
    +        xnode = addPerlSimpleFoldClassPartitions(sn, xnode);
     
             node.replaceWith(xnode);
             return xnode;
         }
     
    +    private Node addPerlSimpleFoldClassPartitions(StringNode source, Node expanded) {
    +        if (!syntax.op2OptionPerl() || Option.isPerlAsciiStrict(regex.options)
    +                || Option.isPerlBytePattern(regex.options)) {
    +            return expanded;
    +        }
    +
    +        ListNode root = null;
    +        ListNode tail = null;
    +        int literalStart = source.p;
    +        boolean hasPerlOnlySibling = false;
    +
    +        for (int p = source.p; p < source.end;) {
    +            int next = p + enc.length(source.bytes, p, source.end);
    +            int codePoint = enc.mbcToCode(source.bytes, p, source.end);
    +            int foldLength = PerlCaseFold.simpleFoldClassLength(codePoint);
    +            // JCodings already supplies ordinary two-member case pairs.  Only
    +            // materialize a class when Perl's pinned relation contributes an
    +            // extra sibling such as Kelvin or Angstrom; otherwise this would
    +            // needlessly discard an exact-literal optimizer candidate.
    +            if (foldLength <= 2 && !perlSimpleFoldNeedsPartition(codePoint)
    +                    && perlSimpleFoldClassIsNative(source.bytes, p, next,
    +                    codePoint, foldLength)) {
    +                p = next;
    +                continue;
    +            }
    +
    +            boolean hasSibling = false;
    +            for (int index = 0; index < foldLength; index++) {
    +                int folded = PerlCaseFold.simpleFoldClassCodePoint(codePoint, index);
    +                if (folded != codePoint && !PerlCaseFold.isTurkicSourceExcluded(folded)) {
    +                    hasSibling = true;
    +                    break;
    +                }
    +            }
    +            if (!hasSibling || PerlCaseFold.isTurkicSourceExcluded(codePoint)) {
    +                p = next;
    +                continue;
    +            }
    +
    +            if (literalStart < p) {
    +                ListNode literal = ListNode.newList(
    +                        new StringNode(source.bytes, literalStart, p), null);
    +                if (root == null) root = literal;
    +                else tail.setTail(literal);
    +                tail = literal;
    +            }
    +
    +            CClassNode closure = new CClassNode();
    +            for (int index = 0; index < foldLength; index++) {
    +                int folded = PerlCaseFold.simpleFoldClassCodePoint(codePoint, index);
    +                if (!PerlCaseFold.isTurkicSourceExcluded(folded)) {
    +                    closure.addCodeRange(env, folded, folded, false);
    +                }
    +            }
    +            ListNode closureNode = ListNode.newList(closure, null);
    +            if (root == null) root = closureNode;
    +            else tail.setTail(closureNode);
    +            tail = closureNode;
    +
    +            literalStart = next;
    +            p = next;
    +            hasPerlOnlySibling = true;
    +        }
    +
    +        if (!hasPerlOnlySibling) return expanded;
    +        if (literalStart < source.end) {
    +            ListNode literal = ListNode.newList(
    +                    new StringNode(source.bytes, literalStart, source.end), null);
    +            tail.setTail(literal);
    +        }
    +        ListNode alternatives = newAlt(expanded, null);
    +        alternatives.setTail(newAlt(root, null));
    +        return alternatives;
    +    }
    +
    +    private boolean perlSimpleFoldNeedsPartition(int codePoint) {
    +        // JCodings exposes the case-fold query for these pinned pairs but does
    +        // not make its literal matcher accept the reverse source.  Keep this
    +        // exceptional relation explicit rather than broadening every ordinary
    +        // two-member literal and losing the exact-literal optimizer.
    +        return codePoint == 0x023a || codePoint == 0x023e
    +                || codePoint == 0x2c65 || codePoint == 0x2c66;
    +    }
    +
    +    private boolean perlSimpleFoldClassIsNative(byte[] bytes, int p, int next,
    +                                                int codePoint, int foldLength) {
    +        if (foldLength <= 1) return true;
    +
    +        CaseFoldCodeItem[] items = enc.caseFoldCodesByString(
    +                regex.caseFoldFlagFor(regex.options), bytes, p, next);
    +        for (int index = 0; index < foldLength; index++) {
    +            int sibling = PerlCaseFold.simpleFoldClassCodePoint(codePoint, index);
    +            if (sibling == codePoint) continue;
    +
    +            boolean found = false;
    +            for (CaseFoldCodeItem item : items) {
    +                if (item.byteLen == next - p && item.code.length == 1
    +                        && item.code[0] == sibling) {
    +                    found = true;
    +                    break;
    +                }
    +            }
    +            if (!found) return false;
    +        }
    +        return true;
    +    }
    +
         private Node addPerlReverseFoldPartitions(StringNode source, Node expanded) {
             if (!syntax.op2OptionPerl() || Option.isPerlAsciiStrict(regex.options)
                     || Option.isPerlBytePattern(regex.options)) {
    @@ -2500,7 +2750,7 @@ protected final Node setupTree(Node node, int state) {
             case NodeType.BREF:
                 BackRefNode br = (BackRefNode)node;
                 for (int i=0; i env.numMem) {
    +                if (invalidBackrefNode(br.back[i])) {
                         if (!syntax.op3OptionECMAScript()) newValueException(INVALID_BACKREF);
                     } else {
                         env.backrefedMem = bsOnAt(env.backrefedMem, br.back[i]);
    @@ -2520,8 +2770,7 @@ protected final Node setupTree(Node node, int state) {
                 Node target = qn.target;
     
                 int perlTargetMin = -1;
    -            if (syntax.op2OptionPerl() && qn.isByNumber()
    -                    && target.getType() == NodeType.CALL) {
    +            if (syntax.op2OptionPerl() && qn.isByNumber()) {
                     perlTargetMin = getMinMatchLength(target);
                     if (perlTargetMin == 0) {
                         perlSyntaxWarn(PERL_QUANTIFIER_ON_ZERO_LENGTH);
    @@ -2636,7 +2885,8 @@ protected final Node setupTree(Node node, int state) {
                         }
                     }
                     if (en.assertionCondition == null && en.calloutConditionId < 0
    -                        && en.recursionConditionGroup < 0 && en.regNum > env.numMem) {
    +                        && en.recursionConditionGroup < 0 && en.regNum > env.numMem
    +                        && !syntax.op2OptionPerl()) {
                         newValueException(INVALID_BACKREF);
                     }
                     if (en.recursionConditionGroup > env.numMem) newValueException(INVALID_BACKREF);
    @@ -2756,10 +3006,16 @@ private void optimizeNodeLeft(Node node, NodeOptInfo opt, OptEnvironment oenv) {
     
                     opt.length.set(slen, slen);
                 } else {
    +                int min = slen;
                     int max;
                     if (sn.isDontGetOptInfo()) {
                         int n = sn.length(enc);
                         max = enc.maxLength() * n;
    +                    // A multi-character canonical fold can match one encoded
    +                    // source character (for example U+1F80 can match U+1F88).
    +                    // Its canonical byte length is therefore not a sound
    +                    // lower bound for a following optimizer candidate.
    +                    min = enc.minLength();
                     } else {
                         opt.exb.concatStr(sn.bytes, sn.p, sn.end, sn.isRaw(), enc);
                         opt.exb.ignoreCase = 1;
    @@ -2770,7 +3026,7 @@ private void optimizeNodeLeft(Node node, NodeOptInfo opt, OptEnvironment oenv) {
     
                         max = slen;
                     }
    -                opt.length.set(slen, max);
    +                opt.length.set(min, max);
                 }
     
                 if (opt.exb.length == slen) {
    @@ -2921,7 +3177,7 @@ private void optimizeNodeLeft(Node node, NodeOptInfo opt, OptEnvironment oenv) {
                 QuantifierNode qn = (QuantifierNode)node;
                 optimizeNodeLeft(qn.target, nopt, oenv);
                 if (/*qn.lower == 0 &&*/ isRepeatInfinite(qn.upper)) {
    -                if (oenv.mmd.max == 0 && qn.target.getType() == NodeType.CANY && qn.greedy) {
    +                if (oenv.mmd.max == 0 && qn.target.getType() == NodeType.CANY) {
                         if (isMultiline(oenv.options)) {
                             opt.anchor.add(AnchorType.ANYCHAR_STAR_ML);
                         } else {
    @@ -3025,6 +3281,7 @@ protected final void setOptimizedInfoFromTree(Node node) {
             oenv.mmd.clear(); // ??
     
             optimizeNodeLeft(node, opt, oenv);
    +        regex.minimumLength = opt.length.min;
     
             regex.anchor = opt.anchor.leftAnchor & (AnchorType.BEGIN_BUF |
                                                     AnchorType.BEGIN_POSITION |
    @@ -3066,4 +3323,9 @@ protected final void setOptimizedInfoFromTree(Node node) {
                 Config.log.println(regex.optimizeInfoToString());
             }
         }
    +
    +    private boolean invalidBackrefNode(int number) {
    +        return number <= 0 || number > env.numMem || env.memNodes == null
    +                || number >= env.memNodes.length || env.memNodes[number] == null;
    +    }
     }
    diff --git a/third_party/joni/src/org/joni/ApplyCaseFold.java b/third_party/joni/src/org/joni/ApplyCaseFold.java
    index e5a250664e..7e46ee4baa 100644
    --- a/third_party/joni/src/org/joni/ApplyCaseFold.java
    +++ b/third_party/joni/src/org/joni/ApplyCaseFold.java
    @@ -39,13 +39,44 @@ public void apply(int from, int[]to, int length, Object o) {
             CClassNode foldCc = arg.foldCc;
             BitSet bs = cc.bs;
             boolean addFlag;
    +        boolean bytePropertySource = false;
     
             if (!arg.preservePropertyAsciiCrossings && Option.isPerlAsciiStrict(env.option)
                     && perlAsciiStrictRelationCrossesAscii(from, to, length)) {
                 return;
             }
     
    -        if (!isEligible(foldCc, enc, from) || ascCc == null) {
    +        if (Option.isPerlBytePattern(env.option) && !Encoding.isAscii(from)) {
    +            boolean fromMember = cc.isCodeInCC(enc, from);
    +            if (length == 1) {
    +                boolean fromProperty = isEligible(
    +                        arg.propertyFoldCc, enc, from);
    +                boolean toProperty = isEligible(
    +                        arg.propertyFoldCc, enc, to[0]);
    +                bytePropertySource = fromProperty || toProperty;
    +                if (!bytePropertySource) return;
    +
    +                boolean toMember = cc.isCodeInCC(enc, to[0]);
    +                boolean propertyMember = (fromProperty && fromMember)
    +                        || (toProperty && toMember);
    +                if (fromMember != propertyMember) {
    +                    if (propertyMember) cc.includeCode(env, from);
    +                    else cc.excludeCode(env, from);
    +                }
    +                if (toMember != propertyMember) {
    +                    if (propertyMember) cc.includeCode(env, to[0]);
    +                    else cc.excludeCode(env, to[0]);
    +                }
    +                return;
    +            }
    +            bytePropertySource = isEligible(arg.propertyFoldCc, enc, from);
    +            if (!bytePropertySource) return;
    +            if (!fromMember) return;
    +        }
    +
    +        if (bytePropertySource) {
    +            addFlag = true;
    +        } else if (!isEligible(foldCc, enc, from) || ascCc == null) {
                 addFlag = false;
             } else if (Encoding.isAscii(from) == Encoding.isAscii(to[0])) {
                 addFlag = true;
    diff --git a/third_party/joni/src/org/joni/ApplyCaseFoldArg.java b/third_party/joni/src/org/joni/ApplyCaseFoldArg.java
    index 54ad870ef5..ef474c5a55 100644
    --- a/third_party/joni/src/org/joni/ApplyCaseFoldArg.java
    +++ b/third_party/joni/src/org/joni/ApplyCaseFoldArg.java
    @@ -24,22 +24,29 @@
     
     final class ApplyCaseFoldArg {
         final ScanEnvironment env;
    -    final CClassNode cc, ascCc, foldCc;
    +    final CClassNode cc, ascCc, foldCc, propertyFoldCc;
         final boolean preservePropertyAsciiCrossings;
         ListNode altRoot;
         ListNode tail;
     
         ApplyCaseFoldArg(ScanEnvironment env, CClassNode cc, CClassNode ascCc,
                          CClassNode foldCc) {
    -        this(env, cc, ascCc, foldCc, false);
    +        this(env, cc, ascCc, foldCc, null, false);
         }
     
         ApplyCaseFoldArg(ScanEnvironment env, CClassNode cc, CClassNode ascCc,
                          CClassNode foldCc, boolean preservePropertyAsciiCrossings) {
    +        this(env, cc, ascCc, foldCc, null, preservePropertyAsciiCrossings);
    +    }
    +
    +    ApplyCaseFoldArg(ScanEnvironment env, CClassNode cc, CClassNode ascCc,
    +                     CClassNode foldCc, CClassNode propertyFoldCc,
    +                     boolean preservePropertyAsciiCrossings) {
             this.env = env;
             this.cc = cc;
             this.ascCc = ascCc;
             this.foldCc = foldCc;
    +        this.propertyFoldCc = propertyFoldCc;
             this.preservePropertyAsciiCrossings = preservePropertyAsciiCrossings;
         }
     }
    diff --git a/third_party/joni/src/org/joni/ArrayCompiler.java b/third_party/joni/src/org/joni/ArrayCompiler.java
    index 5c5c6f541d..91e4c9712e 100644
    --- a/third_party/joni/src/org/joni/ArrayCompiler.java
    +++ b/third_party/joni/src/org/joni/ArrayCompiler.java
    @@ -28,7 +28,10 @@
     import java.util.LinkedHashMap;
     import java.util.Map;
     import java.util.ArrayList;
    +import java.util.Collections;
    +import java.util.IdentityHashMap;
     import java.util.List;
    +import java.util.Set;
     
     import org.jcodings.constants.CharacterType;
     import org.joni.ast.AnchorNode;
    @@ -59,16 +62,24 @@ final class ArrayCompiler extends Compiler {
         private int templateNum;
         private final Map controlVerbLabelIds = new LinkedHashMap<>();
         private final List wideScalarClasses = new ArrayList<>();
    +    private final Set previousRepeatBackrefs =
    +            Collections.newSetFromMap(new IdentityHashMap<>());
    +    private final Set recursiveFrameBackrefs =
    +            Collections.newSetFromMap(new IdentityHashMap<>());
    +    private final Set calledFrameStopBacktracks =
    +            Collections.newSetFromMap(new IdentityHashMap<>());
     
         ArrayCompiler(Analyser analyser) {
             super(analyser);
         }
     
         @Override
    -    protected final void prepare() {
    +    protected final void prepare(Node root) {
             int codeSize = Config.USE_STRING_TEMPLATES ? 8 : ((analyser.getEnd() - analyser.getBegin()) * 2 + 2);
             code = new int[codeSize];
             codeLength = 0;
    +        collectPreviousRepeatBackrefs(root, 0, 0, new boolean[regex.numMem + 1]);
    +        collectRecursiveFrameBackrefs(root, false);
         }
     
         @Override
    @@ -438,14 +449,22 @@ protected void compileCallNode(CallNode node) {
             addOpcode(OPCode.CALL);
             node.unsetAddrList.add(codeLength, node.target);
             addAbsAddr(0); /*dummy addr.*/
    -        // Preserve analyser recursion knowledge for the matcher without adding
    -        // an opcode operand. -1 remains reserved for compiler-internal calls.
    -        addMemNum(node.isRecursion() ? -(node.groupNum + 1) : node.groupNum);
    +        // Keep recursion and Perl capture-publication policy separate from the
    +        // group number. Ordinary Perl subroutine calls preserve the caller's
    +        // captures but must not be treated as recursive by the analyser.
    +        int callFlags = (node.isRecursion() ? 0x40000000 : 0)
    +                | (node.preserveCallerCaptures ? 0x80000000 : 0);
    +        addMemNum((node.groupNum & 0x3fffffff) | callFlags);
         }
     
         @Override
         protected void compileBackrefNode(BackRefNode node) {
             BackRefNode br = node;
    +        if (usesPreviousRepeatCapture(br) || usesPreviousRecursiveFrameCapture(br)) {
    +            addOpcode(isIgnoreCase(regex.options) ? OPCode.BACKREFN_PREV_IC : OPCode.BACKREFN_PREV);
    +            addMemNum(br.back[0]);
    +            return;
    +        }
             if (Config.USE_BACKREF_WITH_LEVEL && br.isNestLevel()) {
                 addOpcode(OPCode.BACKREF_WITH_LEVEL);
                 addOption(regex.options & Option.IGNORECASE);
    @@ -486,7 +505,217 @@ protected void compileBackrefNode(BackRefNode node) {
             }
         }
     
    +    private boolean usesPreviousRepeatCapture(BackRefNode backref) {
    +        return previousRepeatBackrefs.contains(backref);
    +    }
    +
    +    private boolean usesPreviousRecursiveFrameCapture(BackRefNode backref) {
    +        return recursiveFrameBackrefs.contains(backref);
    +    }
    +
    +    private void collectRecursiveFrameBackrefs(Node node, boolean recursiveFrame) {
    +        if (node == null) return;
    +        switch (node.getType()) {
    +        case NodeType.LIST:
    +        case NodeType.ALT:
    +            for (ListNode item = (ListNode)node; item != null; item = item.tail) {
    +                collectRecursiveFrameBackrefs(item.value, recursiveFrame);
    +            }
    +            break;
    +        case NodeType.QTFR:
    +            collectRecursiveFrameBackrefs(((QuantifierNode)node).target, recursiveFrame);
    +            break;
    +        case NodeType.ENCLOSE:
    +            EncloseNode enclosure = (EncloseNode)node;
    +            if (recursiveFrame && enclosure.isStopBtSimpleRepeat()) {
    +                calledFrameStopBacktracks.add(enclosure);
    +            }
    +            collectRecursiveFrameBackrefs(enclosure.target,
    +                    recursiveFrame || (enclosure.isMemory() && enclosure.isCalled()));
    +            break;
    +        case NodeType.ANCHOR:
    +            collectRecursiveFrameBackrefs(((AnchorNode)node).target, recursiveFrame);
    +            break;
    +        case NodeType.CALL:
    +            CallNode call = (CallNode)node;
    +            // A recursive target is normally compiled from its CALL node,
    +            // rather than from the enclosing occurrence in the main tree.
    +            // Visit that body once to classify its forward backreferences;
    +            // do not follow nested calls again, as their targets form cycles.
    +            if (!recursiveFrame && call.isRecursion()) {
    +                collectRecursiveFrameBackrefs(call.target.target, true);
    +            }
    +            break;
    +        case NodeType.BREF:
    +            BackRefNode backref = (BackRefNode)node;
    +            if (recursiveFrame && backref.isRecursion()) {
    +                recursiveFrameBackrefs.add(backref);
    +            }
    +            break;
    +        default:
    +            break;
    +        }
    +    }
    +
    +    private boolean preservesCalledFrameBacktracking(EncloseNode enclosure) {
    +        return calledFrameStopBacktracks.contains(enclosure);
    +    }
    +
    +    private void collectPreviousRepeatBackrefs(Node node, int repeatDepth, int alternativeDepth,
    +                                                boolean[] activeRepeatedCaptures) {
    +        if (node == null) return;
    +        switch (node.getType()) {
    +        case NodeType.LIST:
    +            for (ListNode item = (ListNode)node; item != null; item = item.tail) {
    +                collectPreviousRepeatBackrefs(item.value, repeatDepth, alternativeDepth,
    +                        activeRepeatedCaptures);
    +            }
    +            break;
    +        case NodeType.ALT:
    +            for (ListNode item = (ListNode)node; item != null; item = item.tail) {
    +                collectPreviousRepeatBackrefs(item.value, repeatDepth, alternativeDepth + 1,
    +                        activeRepeatedCaptures);
    +            }
    +            break;
    +        case NodeType.QTFR:
    +            QuantifierNode quantifier = (QuantifierNode)node;
    +            int nestedRepeatDepth = quantifier.upper == QuantifierNode.REPEAT_INFINITE
    +                    || quantifier.upper > 1 ? repeatDepth + 1 : repeatDepth;
    +            collectPreviousRepeatBackrefs(quantifier.target, nestedRepeatDepth, alternativeDepth,
    +                    activeRepeatedCaptures);
    +            break;
    +        case NodeType.ENCLOSE:
    +            EncloseNode enclosure = (EncloseNode)node;
    +            if (enclosure.isCondition() && enclosure.target instanceof ListNode
    +                    && enclosure.target.getType() == NodeType.ALT) {
    +                for (ListNode item = (ListNode)enclosure.target; item != null; item = item.tail) {
    +                    collectPreviousRepeatBackrefs(item.value, repeatDepth, alternativeDepth,
    +                            activeRepeatedCaptures);
    +                }
    +                break;
    +            }
    +            boolean wasActive = false;
    +            if (enclosure.isMemory() && enclosure.regNum > 0 && repeatDepth > 0) {
    +                wasActive = activeRepeatedCaptures[enclosure.regNum];
    +                activeRepeatedCaptures[enclosure.regNum] = true;
    +            }
    +            collectPreviousRepeatBackrefs(enclosure.target, repeatDepth, alternativeDepth,
    +                    activeRepeatedCaptures);
    +            if (enclosure.isMemory() && enclosure.regNum > 0 && repeatDepth > 0) {
    +                activeRepeatedCaptures[enclosure.regNum] = wasActive;
    +            }
    +            break;
    +        case NodeType.ANCHOR:
    +            collectPreviousRepeatBackrefs(((AnchorNode)node).target, repeatDepth, alternativeDepth,
    +                    activeRepeatedCaptures);
    +            break;
    +        case NodeType.BREF:
    +            BackRefNode backref = (BackRefNode)node;
    +            if (backref.backNum == 1 && !backref.isNestLevel() && alternativeDepth == 0
    +                    && backref.back[0] < activeRepeatedCaptures.length
    +                    && activeRepeatedCaptures[backref.back[0]]) {
    +                previousRepeatBackrefs.add(backref);
    +            }
    +            break;
    +        default:
    +            break;
    +        }
    +    }
    +
         private static final int REPEAT_RANGE_ALLOC = 8;
    +
    +    private static void collectCaptureGroups(Node node, boolean[] groups) {
    +        if (node == null) return;
    +        switch (node.getType()) {
    +        case NodeType.LIST:
    +        case NodeType.ALT:
    +            for (ListNode item = (ListNode)node; item != null; item = item.tail) {
    +                collectCaptureGroups(item.value, groups);
    +            }
    +            break;
    +        case NodeType.QTFR:
    +            collectCaptureGroups(((QuantifierNode)node).target, groups);
    +            break;
    +        case NodeType.ENCLOSE:
    +            EncloseNode enclose = (EncloseNode)node;
    +            if (enclose.isMemory() && enclose.regNum > 0 && enclose.regNum < groups.length) {
    +                groups[enclose.regNum] = true;
    +            }
    +            collectCaptureGroups(enclose.target, groups);
    +            break;
    +        case NodeType.ANCHOR:
    +            collectCaptureGroups(((AnchorNode)node).target, groups);
    +            break;
    +        default:
    +            break;
    +        }
    +    }
    +
    +    private int[] captureGroups(Node target) {
    +        boolean[] found = new boolean[regex.numMem + 1];
    +        collectCaptureGroups(target, found);
    +        int count = 0;
    +        for (int group = 1; group < found.length; group++) {
    +            if (found[group]) count++;
    +        }
    +        if (count == 0) return null;
    +
    +        int[] groups = new int[count];
    +        int index = 0;
    +        for (int group = 1; group < found.length; group++) {
    +            if (found[group]) groups[index++] = group;
    +        }
    +        return groups;
    +    }
    +
    +    private int entryRepeatCaptureClear(Node target) {
    +        int[] groups = captureGroups(target);
    +        if (groups == null) return -1;
    +        int id = regex.numRepeatCaptureClearGroups++;
    +        if (regex.repeatCaptureClearGroups == null) {
    +            regex.repeatCaptureClearGroups = new int[REPEAT_RANGE_ALLOC][];
    +        } else if (id >= regex.repeatCaptureClearGroups.length) {
    +            int[][] expanded = new int[regex.repeatCaptureClearGroups.length + REPEAT_RANGE_ALLOC][];
    +            System.arraycopy(regex.repeatCaptureClearGroups, 0, expanded, 0,
    +                    regex.repeatCaptureClearGroups.length);
    +            regex.repeatCaptureClearGroups = expanded;
    +        }
    +        regex.repeatCaptureClearGroups[id] = groups;
    +        return id;
    +    }
    +
    +    private int repeatCaptureClearLength(Node target) {
    +        return captureGroups(target) == null ? 0
    +                : OPSize.REPEAT_CAPTURE_CLEAR + OPSize.REPEAT_CAPTURE_CLEAR_END;
    +    }
    +
    +    private void compileRepeatCaptureClear(int clearId) {
    +        if (clearId < 0) return;
    +        addOpcode(OPCode.REPEAT_CAPTURE_CLEAR);
    +        addMemNum(clearId);
    +    }
    +
    +    private void compileRepeatTree(Node target, int clearId) {
    +        compileRepeatCaptureClear(clearId);
    +        compileTree(target);
    +        if (clearId >= 0) {
    +            addOpcode(OPCode.REPEAT_CAPTURE_CLEAR_END);
    +            addMemNum(clearId);
    +        }
    +    }
    +
    +    private void compileRepeatTreeNTimes(Node target, int count, int clearId) {
    +        for (int i = 0; i < count; i++) compileRepeatTree(target, clearId);
    +    }
    +
    +    private void compileRepeatTreeEmptyCheck(Node target, int emptyInfo, int clearId) {
    +        if (emptyInfo == 0) {
    +            compileRepeatTree(target, clearId);
    +        } else {
    +            compileTreeEmptyCheck(target, emptyInfo);
    +        }
    +    }
    +
         private void entryRepeatRange(int id, int lower, int upper) {
             if (regex.repeatRangeLo == null) {
                 regex.repeatRangeLo = new int[REPEAT_RANGE_ALLOC];
    @@ -504,7 +733,8 @@ private void entryRepeatRange(int id, int lower, int upper) {
             regex.repeatRangeHi[id] = isRepeatInfinite(upper) ? 0x7fffffff : upper;
         }
     
    -    private void compileRangeRepeatNode(QuantifierNode qn, int targetLen, int emptyInfo) {
    +    private void compileRangeRepeatNode(QuantifierNode qn, int targetLen, int emptyInfo,
    +                                        int clearId) {
             regex.requireStack = true;
             int numRepeat = regex.numRepeat;
             addOpcode(qn.greedy ? OPCode.REPEAT : OPCode.REPEAT_NG);
    @@ -514,7 +744,7 @@ private void compileRangeRepeatNode(QuantifierNode qn, int targetLen, int emptyI
     
             entryRepeatRange(numRepeat, qn.lower, qn.upper);
     
    -        compileTreeEmptyCheck(qn.target, emptyInfo);
    +        compileRepeatTreeEmptyCheck(qn.target, emptyInfo, clearId);
     
             if ((Config.USE_SUBEXP_CALL && regex.numCall > 0) || qn.isInRepeat()) {
                 addOpcode(qn.greedy ? OPCode.REPEAT_INC_SG : OPCode.REPEAT_INC_NG_SG);
    @@ -536,6 +766,10 @@ private int compileCECLengthQuantifierNode(QuantifierNode qn) {
             int emptyInfo = qn.targetEmptyInfo;
     
             int tlen = compileLengthTree(qn.target);
    +        // Empty and recursive-empty repeats use capture state in Joni's null
    +        // loop detector. Their reset needs a separate null-check-aware design.
    +        int repeatClearLen = emptyInfo == 0 ? repeatCaptureClearLength(qn.target) : 0;
    +        int bodyLen = tlen + repeatClearLen;
             int ckn = regex.numCombExpCheck > 0 ? qn.combExpCheckNum : 0;
             int cklen = cknOn(ckn) ? OPSize.STATE_CHECK_NUM : 0;
     
    @@ -552,9 +786,9 @@ private int compileCECLengthQuantifierNode(QuantifierNode qn) {
     
             int modTLen;
             if (emptyInfo != 0) {
    -            modTLen = tlen + (OPSize.NULL_CHECK_START + OPSize.NULL_CHECK_END);
    +            modTLen = bodyLen + (OPSize.NULL_CHECK_START + OPSize.NULL_CHECK_END);
             } else {
    -            modTLen = tlen;
    +            modTLen = bodyLen;
             }
     
             int len;
    @@ -583,15 +817,15 @@ private int compileCECLengthQuantifierNode(QuantifierNode qn) {
             } else if (qn.upper == 1 && qn.greedy) {
                 if (qn.lower == 0) {
                     if (cknOn(ckn)) {
    -                    len = OPSize.STATE_CHECK_PUSH + tlen;
    +                    len = OPSize.STATE_CHECK_PUSH + bodyLen;
                     } else {
    -                    len = OPSize.PUSH + tlen;
    +                    len = OPSize.PUSH + bodyLen;
                     }
                 } else {
    -                len = tlen;
    +                len = bodyLen;
                 }
             } else if (!qn.greedy && qn.upper == 1 && qn.lower == 0) { /* '??' */
    -            len = OPSize.PUSH + cklen + OPSize.JUMP + tlen;
    +            len = OPSize.PUSH + cklen + OPSize.JUMP + bodyLen;
             } else {
                 len = OPSize.REPEAT_INC + modTLen + OPSize.OPCODE + OPSize.RELADDR + OPSize.MEMNUM;
     
    @@ -609,6 +843,9 @@ protected void compileCECQuantifierNode(QuantifierNode qn) {
             int emptyInfo = qn.targetEmptyInfo;
     
             int tlen = compileLengthTree(qn.target);
    +        int clearId = emptyInfo == 0 ? entryRepeatCaptureClear(qn.target) : -1;
    +        int bodyLen = tlen + (clearId < 0 ? 0
    +                : OPSize.REPEAT_CAPTURE_CLEAR + OPSize.REPEAT_CAPTURE_CLEAR_END);
     
             int ckn = regex.numCombExpCheck > 0 ? qn.combExpCheckNum : 0;
     
    @@ -649,9 +886,9 @@ protected void compileCECQuantifierNode(QuantifierNode qn) {
     
             int modTLen;
             if (emptyInfo != 0) {
    -            modTLen = tlen + (OPSize.NULL_CHECK_START + OPSize.NULL_CHECK_END);
    +            modTLen = bodyLen + (OPSize.NULL_CHECK_START + OPSize.NULL_CHECK_END);
             } else {
    -            modTLen = tlen;
    +            modTLen = bodyLen;
             }
             if (infinite && qn.lower <= 1) {
                 if (qn.greedy) {
    @@ -666,7 +903,7 @@ protected void compileCECQuantifierNode(QuantifierNode qn) {
                     } else {
                         addOpcodeRelAddr(OPCode.PUSH, modTLen + OPSize.JUMP);
                     }
    -                compileTreeEmptyCheck(qn.target, emptyInfo);
    +                compileRepeatTreeEmptyCheck(qn.target, emptyInfo, clearId);
                     addOpcodeRelAddr(OPCode.JUMP, -(modTLen + OPSize.JUMP + (cknOn(ckn) ?
                                                                                    OPSize.STATE_CHECK_PUSH :
                                                                                    OPSize.PUSH)));
    @@ -674,7 +911,7 @@ protected void compileCECQuantifierNode(QuantifierNode qn) {
                     if (qn.lower == 0) {
                         addOpcodeRelAddr(OPCode.JUMP, modTLen);
                     }
    -                compileTreeEmptyCheck(qn.target, emptyInfo);
    +                compileRepeatTreeEmptyCheck(qn.target, emptyInfo, clearId);
                     if (cknOn(ckn)) {
                         addOpcode(OPCode.STATE_CHECK_PUSH_OR_JUMP);
                         addStateCheckNum(ckn);
    @@ -693,12 +930,12 @@ protected void compileCECQuantifierNode(QuantifierNode qn) {
                     if (cknOn(ckn)) {
                         addOpcode(OPCode.STATE_CHECK_PUSH);
                         addStateCheckNum(ckn);
    -                    addRelAddr(tlen);
    +                    addRelAddr(bodyLen);
                     } else {
    -                    addOpcodeRelAddr(OPCode.PUSH, tlen);
    +                    addOpcodeRelAddr(OPCode.PUSH, bodyLen);
                     }
                 }
    -            compileTree(qn.target);
    +            compileRepeatTree(qn.target, clearId);
             } else if (!qn.greedy && qn.upper == 1 && qn.lower == 0){ /* '??' */
                 if (cknOn(ckn)) {
                     addOpcode(OPCode.STATE_CHECK_PUSH);
    @@ -708,10 +945,10 @@ protected void compileCECQuantifierNode(QuantifierNode qn) {
                     addOpcodeRelAddr(OPCode.PUSH, OPSize.JUMP);
                 }
     
    -            addOpcodeRelAddr(OPCode.JUMP, tlen);
    -            compileTree(qn.target);
    +            addOpcodeRelAddr(OPCode.JUMP, bodyLen);
    +            compileRepeatTree(qn.target, clearId);
             } else {
    -            compileRangeRepeatNode(qn, modTLen, emptyInfo);
    +            compileRangeRepeatNode(qn, modTLen, emptyInfo, clearId);
                 if (cknOn(ckn)) {
                     addOpcode(OPCode.STATE_CHECK);
                     addStateCheckNum(ckn);
    @@ -724,6 +961,8 @@ private int compileNonCECLengthQuantifierNode(QuantifierNode qn) {
             int emptyInfo = qn.targetEmptyInfo;
     
             int tlen = compileLengthTree(qn.target);
    +        int repeatClearLen = emptyInfo == 0 ? repeatCaptureClearLength(qn.target) : 0;
    +        int bodyLen = tlen + repeatClearLen;
     
             /* anychar repeat */
             if (qn.target.getType() == NodeType.CANY) {
    @@ -738,23 +977,23 @@ private int compileNonCECLengthQuantifierNode(QuantifierNode qn) {
     
             int modTLen;
             if (emptyInfo != 0) {
    -            modTLen = tlen + (OPSize.NULL_CHECK_START + OPSize.NULL_CHECK_END);
    +            modTLen = bodyLen + (OPSize.NULL_CHECK_START + OPSize.NULL_CHECK_END);
             } else {
    -            modTLen = tlen;
    +            modTLen = bodyLen;
             }
     
             int len;
    -        if (infinite && (qn.lower <= 1 || tlen * qn.lower <= QUANTIFIER_EXPAND_LIMIT_SIZE)) {
    -            if (qn.lower == 1 && tlen > QUANTIFIER_EXPAND_LIMIT_SIZE) {
    +        if (infinite && (qn.lower <= 1 || bodyLen * qn.lower <= QUANTIFIER_EXPAND_LIMIT_SIZE)) {
    +            if (qn.lower == 1 && bodyLen > QUANTIFIER_EXPAND_LIMIT_SIZE) {
                     len = OPSize.JUMP;
                 } else {
    -                len = tlen * qn.lower;
    +                len = bodyLen * qn.lower;
                 }
     
                 if (qn.greedy) {
                     if (qn.headExact != null) {
                         len += OPSize.PUSH_OR_JUMP_EXACT1 + modTLen + OPSize.JUMP;
    -                } else if (qn.nextHeadExact != null) {
    +                } else if (qn.nextHeadExact != null && qn.target.getType() != NodeType.CALL) {
                         len += OPSize.PUSH_IF_PEEK_NEXT + modTLen + OPSize.JUMP;
                     } else {
                         len += OPSize.PUSH + modTLen + OPSize.JUMP;
    @@ -766,11 +1005,11 @@ private int compileNonCECLengthQuantifierNode(QuantifierNode qn) {
             } else if (qn.upper == 0 && qn.isRefered) { /* /(?..){0}/ */
                 len = OPSize.JUMP + tlen;
             } else if (!infinite && qn.greedy &&
    -                  (qn.upper == 1 || (tlen + OPSize.PUSH) * qn.upper <= QUANTIFIER_EXPAND_LIMIT_SIZE )) {
    -            len = tlen * qn.lower;
    -            len += (OPSize.PUSH + tlen) * (qn.upper - qn.lower);
    +                  (qn.upper == 1 || (bodyLen + OPSize.PUSH) * qn.upper <= QUANTIFIER_EXPAND_LIMIT_SIZE )) {
    +            len = bodyLen * qn.lower;
    +            len += (OPSize.PUSH + bodyLen) * (qn.upper - qn.lower);
             } else if (!qn.greedy && qn.upper == 1 && qn.lower == 0) { /* '??' */
    -            len = OPSize.PUSH + OPSize.JUMP + tlen;
    +            len = OPSize.PUSH + OPSize.JUMP + bodyLen;
             } else {
                 len = OPSize.REPEAT_INC + modTLen + OPSize.OPCODE + OPSize.RELADDR + OPSize.MEMNUM;
             }
    @@ -784,6 +1023,9 @@ protected void compileNonCECQuantifierNode(QuantifierNode qn) {
             int emptyInfo = qn.targetEmptyInfo;
     
             int tlen = compileLengthTree(qn.target);
    +        int clearId = emptyInfo == 0 ? entryRepeatCaptureClear(qn.target) : -1;
    +        int bodyLen = tlen + (clearId < 0 ? 0
    +                : OPSize.REPEAT_CAPTURE_CLEAR + OPSize.REPEAT_CAPTURE_CLEAR_END);
     
             if (qn.isAnyCharStar()) {
                 compileTreeNTimes(qn.target, qn.lower);
    @@ -808,12 +1050,12 @@ protected void compileNonCECQuantifierNode(QuantifierNode qn) {
     
             int modTLen;
             if (emptyInfo != 0) {
    -            modTLen = tlen + (OPSize.NULL_CHECK_START + OPSize.NULL_CHECK_END);
    +            modTLen = bodyLen + (OPSize.NULL_CHECK_START + OPSize.NULL_CHECK_END);
             } else {
    -            modTLen = tlen;
    +            modTLen = bodyLen;
             }
    -        if (infinite && (qn.lower <= 1 || tlen * qn.lower <= QUANTIFIER_EXPAND_LIMIT_SIZE)) {
    -            if (qn.lower == 1 && tlen > QUANTIFIER_EXPAND_LIMIT_SIZE) {
    +        if (infinite && (qn.lower <= 1 || bodyLen * qn.lower <= QUANTIFIER_EXPAND_LIMIT_SIZE)) {
    +            if (qn.lower == 1 && bodyLen > QUANTIFIER_EXPAND_LIMIT_SIZE) {
                     if (qn.greedy) {
                         if (qn.headExact != null) {
                             addOpcodeRelAddr(OPCode.JUMP, OPSize.PUSH_OR_JUMP_EXACT1);
    @@ -826,7 +1068,7 @@ protected void compileNonCECQuantifierNode(QuantifierNode qn) {
                         addOpcodeRelAddr(OPCode.JUMP, OPSize.JUMP);
                     }
                 } else {
    -                compileTreeNTimes(qn.target, qn.lower);
    +                compileRepeatTreeNTimes(qn.target, qn.lower, clearId);
                 }
     
                 if (qn.greedy) {
    @@ -834,42 +1076,42 @@ protected void compileNonCECQuantifierNode(QuantifierNode qn) {
                         addOpcodeRelAddr(OPCode.PUSH_OR_JUMP_EXACT1, modTLen + OPSize.JUMP);
                         StringNode sn = (StringNode)qn.headExact;
                         addBytes(sn.bytes, sn.p, 1);
    -                    compileTreeEmptyCheck(qn.target, emptyInfo);
    +                    compileRepeatTreeEmptyCheck(qn.target, emptyInfo, clearId);
                         addOpcodeRelAddr(OPCode.JUMP, -(modTLen + OPSize.JUMP + OPSize.PUSH_OR_JUMP_EXACT1));
    -                } else if (qn.nextHeadExact != null) {
    +                } else if (qn.nextHeadExact != null && qn.target.getType() != NodeType.CALL) {
                         addOpcodeRelAddr(OPCode.PUSH_IF_PEEK_NEXT, modTLen + OPSize.JUMP);
                         StringNode sn = (StringNode)qn.nextHeadExact;
                         addBytes(sn.bytes, sn.p, 1);
    -                    compileTreeEmptyCheck(qn.target, emptyInfo);
    +                    compileRepeatTreeEmptyCheck(qn.target, emptyInfo, clearId);
                         addOpcodeRelAddr(OPCode.JUMP, -(modTLen + OPSize.JUMP + OPSize.PUSH_IF_PEEK_NEXT));
                     } else {
                         addOpcodeRelAddr(OPCode.PUSH, modTLen + OPSize.JUMP);
    -                    compileTreeEmptyCheck(qn.target, emptyInfo);
    +                    compileRepeatTreeEmptyCheck(qn.target, emptyInfo, clearId);
                         addOpcodeRelAddr(OPCode.JUMP, -(modTLen + OPSize.JUMP + OPSize.PUSH));
                     }
                 } else {
                     addOpcodeRelAddr(OPCode.JUMP, modTLen);
    -                compileTreeEmptyCheck(qn.target, emptyInfo);
    +                compileRepeatTreeEmptyCheck(qn.target, emptyInfo, clearId);
                     addOpcodeRelAddr(OPCode.PUSH, -(modTLen + OPSize.PUSH));
                 }
             } else if (qn.upper == 0 && qn.isRefered) { /* /(?..){0}/ */
                 addOpcodeRelAddr(OPCode.JUMP, tlen);
                 compileTree(qn.target);
             } else if (!infinite && qn.greedy &&
    -                  (qn.upper == 1 || (tlen + OPSize.PUSH) * qn.upper <= QUANTIFIER_EXPAND_LIMIT_SIZE)) {
    +                  (qn.upper == 1 || (bodyLen + OPSize.PUSH) * qn.upper <= QUANTIFIER_EXPAND_LIMIT_SIZE)) {
                 int n = qn.upper - qn.lower;
    -            compileTreeNTimes(qn.target, qn.lower);
    +            compileRepeatTreeNTimes(qn.target, qn.lower, clearId);
     
                 for (int i=0; i= 0 ? node.calloutConditionId
                                 : node.recursionConditionGroup >= 0 ? node.recursionConditionGroup
    +                            : node.physicalNamedCondition > 0 ? -node.physicalNamedCondition
                                 : node.regNum);
                         addRelAddr(len + OPSize.JUMP);
                     }
    @@ -1423,7 +1683,9 @@ private int compileLengthTree(Node node) {
             case NodeType.BREF:
                 BackRefNode br = (BackRefNode)node;
     
    -            if (Config.USE_BACKREF_WITH_LEVEL && br.isNestLevel()) {
    +            if (usesPreviousRepeatCapture(br) || usesPreviousRecursiveFrameCapture(br)) {
    +                len = OPSize.OPCODE + OPSize.MEMNUM;
    +            } else if (Config.USE_BACKREF_WITH_LEVEL && br.isNestLevel()) {
                     len = OPSize.OPCODE + OPSize.OPTION + OPSize.LENGTH +
                           OPSize.LENGTH + (OPSize.MEMNUM * br.backNum);
                 } else { // USE_BACKREF_AT_LEVEL
    diff --git a/third_party/joni/src/org/joni/ByteCodeMachine.java b/third_party/joni/src/org/joni/ByteCodeMachine.java
    index 8219c88f54..d5771aba39 100644
    --- a/third_party/joni/src/org/joni/ByteCodeMachine.java
    +++ b/third_party/joni/src/org/joni/ByteCodeMachine.java
    @@ -35,6 +35,7 @@
     import org.jcodings.unicode.UnicodeCodeRange;
     import org.joni.constants.internal.OPCode;
     import org.joni.constants.internal.OPSize;
    +import org.joni.constants.internal.StackType;
     import org.joni.exception.ErrorMessages;
     import org.joni.exception.InternalException;
     import org.joni.exception.ValueException;
    @@ -60,6 +61,8 @@ class ByteCodeMachine extends StackMachine implements MatchView {
         private int pkeep;
         private int currentRegexOptions;
         private int pendingControlAction;
    +    private boolean preserveCalloutMutations;
    +    private boolean exportedDestructiveControl;
     
         private final int[]code;        // byte code
         private int ip;                 // instruction pointer
    @@ -120,7 +123,7 @@ private void checkCaptureHistory(Region region) {
     
             // was clear ???
             node.group = 0;
    -        node.beg = ((pkeep > s) ? s : pkeep) - str;
    +        node.beg = visibleMatchStart() - str;
             node.end = s      - str;
     
             stkp = 0;
    @@ -166,7 +169,8 @@ private boolean stringCmpIC(int caseFlodFlag, int s1, IntHolder ps2, int mbLen,
             return true;
         }
     
    -    private boolean stringCmpICPerlAsciiStrict(int s1, IntHolder ps2, int mbLen) {
    +    private boolean stringCmpICPerl(int caseFoldFlag, int s1, IntHolder ps2,
    +                                    int mbLen, boolean asciiStrict) {
             byte[]buf1 = cfbuf();
             byte[]buf2 = cfbuf2();
     
    @@ -184,7 +188,7 @@ private boolean stringCmpICPerlAsciiStrict(int s1, IntHolder ps2, int mbLen) {
                     if (s1 >= end1) break;
                     ascii1 = Encoding.isAscii(enc.mbcToCode(bytes, s1, end1));
                     value = s1;
    -                len1 = enc.mbcCaseFold(regex.caseFoldFlag, bytes, this, end1, buf1);
    +                len1 = enc.mbcCaseFold(caseFoldFlag, bytes, this, end1, buf1);
                     s1 = value;
                     p1 = 0;
                 }
    @@ -193,12 +197,13 @@ private boolean stringCmpICPerlAsciiStrict(int s1, IntHolder ps2, int mbLen) {
                     if (s2 >= range) return false;
                     ascii2 = Encoding.isAscii(enc.mbcToCode(bytes, s2, range));
                     value = s2;
    -                len2 = enc.mbcCaseFold(regex.caseFoldFlag, bytes, this, range, buf2);
    +                len2 = enc.mbcCaseFold(caseFoldFlag, bytes, this, range, buf2);
                     s2 = value;
                     p2 = 0;
                 }
     
    -            if (buf1[p1++] != buf2[p2++] || ascii1 != ascii2) return false;
    +            if (buf1[p1++] != buf2[p2++]
    +                    || (asciiStrict && ascii1 != ascii2)) return false;
             }
     
             if (p2 < len2) return false;
    @@ -206,11 +211,78 @@ private boolean stringCmpICPerlAsciiStrict(int s1, IntHolder ps2, int mbLen) {
             return true;
         }
     
    +    private boolean stringCmpICPerlBytePattern(int s1, IntHolder ps2, int mbLen) {
    +        int end1 = s1 + mbLen;
    +        int s2 = ps2.value;
    +
    +        while (s1 < end1) {
    +            if (s2 >= range) return false;
    +            int left = enc.mbcToCode(bytes, s1, end1);
    +            int right = enc.mbcToCode(bytes, s2, range);
    +            s1 += enc.length(bytes, s1, end1);
    +            s2 += enc.length(bytes, s2, range);
    +            if (left == right) continue;
    +            if (!Encoding.isAscii(left) || !Encoding.isAscii(right)) return false;
    +
    +            int foldLength = PerlCaseFold.simpleFoldClassLength(left);
    +            boolean matched = false;
    +            for (int index = 0; index < foldLength; index++) {
    +                matched |= PerlCaseFold.simpleFoldClassCodePoint(left, index) == right;
    +            }
    +            if (!matched) return false;
    +        }
    +        ps2.value = s2;
    +        return true;
    +    }
    +
         private boolean backrefStringCmpIC(int caseFoldFlag, int s1, IntHolder ps2,
                                            int mbLen, int textEnd) {
    -        return Option.isPerlAsciiStrict(currentRegexOptions)
    -                ? stringCmpICPerlAsciiStrict(s1, ps2, mbLen)
    -                : stringCmpIC(caseFoldFlag, s1, ps2, mbLen, textEnd);
    +        if (Option.isPerlBytePattern(currentRegexOptions)) {
    +            return stringCmpICPerlBytePattern(s1, ps2, mbLen);
    +        }
    +        if (regex.perlSyntax) {
    +            if (Option.isPerlAsciiStrict(currentRegexOptions)) {
    +                return stringCmpICPerl(caseFoldFlag, s1, ps2, mbLen, true);
    +            }
    +            int targetStart = ps2.value;
    +            if (targetStart + mbLen <= range
    +                    && stringCmpIC(caseFoldFlag, s1, ps2, mbLen, textEnd)) {
    +                return true;
    +            }
    +            ps2.value = targetStart;
    +            return stringCmpICPerl(caseFoldFlag, s1, ps2, mbLen, false);
    +        }
    +        return stringCmpIC(caseFoldFlag, s1, ps2, mbLen, textEnd);
    +    }
    +
    +    private boolean usesPerlVariableLengthBackref() {
    +        return regex.perlSyntax && !Option.isPerlBytePattern(currentRegexOptions);
    +    }
    +
    +    private boolean backrefPerlSimpleClassCmp(int s1, IntHolder ps2, int mbLen) {
    +        int end1 = s1 + mbLen;
    +        int s2 = ps2.value;
    +        boolean asciiStrict = Option.isPerlAsciiStrict(currentRegexOptions);
    +
    +        while (s1 < end1) {
    +            if (s2 >= range) return false;
    +            int left = enc.mbcToCode(bytes, s1, end1);
    +            int right = enc.mbcToCode(bytes, s2, range);
    +            s1 += enc.length(bytes, s1, end1);
    +            s2 += enc.length(bytes, s2, range);
    +            if (left == right) continue;
    +            if (asciiStrict && Encoding.isAscii(left) != Encoding.isAscii(right)) {
    +                return false;
    +            }
    +            int foldLength = PerlCaseFold.simpleFoldClassLength(left);
    +            boolean matched = false;
    +            for (int index = 0; index < foldLength; index++) {
    +                matched |= PerlCaseFold.simpleFoldClassCodePoint(left, index) == right;
    +            }
    +            if (!matched) return false;
    +        }
    +        ps2.value = s2;
    +        return true;
         }
     
         @Override
    @@ -222,26 +294,32 @@ protected final int matchAt(int _range, int _sstart, int _sprev, boolean interru
             ip = 0;
             currentRegexOptions = regex.options;
             controlMark = null;
    +        preserveCalloutMutations = false;
    +        exportedDestructiveControl = false;
     
             if (Config.DEBUG_MATCH) debugMatchBegin();
    -        stackInit();
    -
    -        bestLen = -1;
    -        s = _sstart;
    -        pkeep = _sstart;
    +        enterMatcherExecution();
             int result = -1;
             try {
    +            stackInit();
    +            bestLen = -1;
    +            s = _sstart;
    +            pkeep = _sstart;
                 result = enc.isSingleByte() || (msaOptions & Option.CR_7_BIT) != 0
                         ? executeSb(interrupt) : execute(interrupt);
                 return result;
             } finally {
    -            if (result >= 0) {
    -                controlError = null;
    -                completeActiveCallouts();
    -            } else {
    -                if (controlMark != null) controlError = controlMark;
    -                controlMark = null;
    -                unwindActiveCallouts();
    +            try {
    +                if (result >= 0) {
    +                    controlError = null;
    +                    completeActiveCallouts();
    +                } else {
    +                    if (controlMark != null) controlError = controlMark;
    +                    controlMark = null;
    +                    unwindActiveCallouts();
    +                }
    +            } finally {
    +                leaveMatcherExecution();
                 }
             }
         }
    @@ -341,6 +419,8 @@ private final int execute(final boolean checkThreadInterrupt) throws Interrupted
                     case OPCode.BACKREF_MULTI:              opBackRefMulti();          continue;
                     case OPCode.BACKREF_MULTI_IC:           opBackRefMultiIC();        continue;
                     case OPCode.BACKREF_WITH_LEVEL:         opBackRefAtLevel();        continue;
    +                case OPCode.BACKREFN_PREV:              opBackRefPrevious();       continue;
    +                case OPCode.BACKREFN_PREV_IC:           opBackRefPreviousIC();     continue;
     
                     case OPCode.SET_OPTION_PUSH:            opSetOptionPush();         continue;
                     case OPCode.SET_OPTION:                 opSetOption();             continue;
    @@ -364,6 +444,9 @@ private final int execute(final boolean checkThreadInterrupt) throws Interrupted
                     case OPCode.REPEAT_INC_SG:              opRepeatIncSG();           continue;
                     case OPCode.REPEAT_INC_NG:              opRepeatIncNG();           continue;
                     case OPCode.REPEAT_INC_NG_SG:           opRepeatIncNGSG();         continue;
    +                case OPCode.REPEAT_CAPTURE_CLEAR:       opRepeatCaptureClear();    continue;
    +                case OPCode.REPEAT_CAPTURE_CLEAR_END:   opRepeatCaptureClearEnd(); continue;
    +                case OPCode.SCRIPT_RUN:                 opScriptRun();             continue;
     
                     case OPCode.PUSH_POS:                   opPushPos();               continue;
                     case OPCode.POP_POS:                    opPopPos();                continue;
    @@ -512,6 +595,8 @@ private final int executeSb(final boolean checkThreadInterrupt) throws Interrupt
                     case OPCode.BACKREF_MULTI:              opBackRefMulti();          continue;
                     case OPCode.BACKREF_MULTI_IC:           opBackRefMultiIC();        continue;
                     case OPCode.BACKREF_WITH_LEVEL:         opBackRefAtLevel();        continue;
    +                case OPCode.BACKREFN_PREV:              opBackRefPrevious();       continue;
    +                case OPCode.BACKREFN_PREV_IC:           opBackRefPreviousIC();     continue;
     
                     case OPCode.SET_OPTION_PUSH:            opSetOptionPush();         continue;
                     case OPCode.SET_OPTION:                 opSetOption();             continue;
    @@ -535,6 +620,9 @@ private final int executeSb(final boolean checkThreadInterrupt) throws Interrupt
                     case OPCode.REPEAT_INC_SG:              opRepeatIncSG();           continue;
                     case OPCode.REPEAT_INC_NG:              opRepeatIncNG();           continue;
                     case OPCode.REPEAT_INC_NG_SG:           opRepeatIncNGSG();         continue;
    +                case OPCode.REPEAT_CAPTURE_CLEAR:       opRepeatCaptureClear();    continue;
    +                case OPCode.REPEAT_CAPTURE_CLEAR_END:   opRepeatCaptureClearEnd(); continue;
    +                case OPCode.SCRIPT_RUN:                 opScriptRun();             continue;
     
                     case OPCode.PUSH_POS:                   opPushPos();               continue;
                     case OPCode.POP_POS:                    opPopPos();                continue;
    @@ -628,7 +716,7 @@ private boolean opEnd() {
                 final Region region = msaRegion;
                 if (region != null) {
                     // USE_POSIX_REGION_OPTION ... else ...
    -                region.setBeg(0, msaBegin = ((pkeep > s) ? s : pkeep) - str);
    +                region.setBeg(0, msaBegin = visibleMatchStart() - str);
                     region.setEnd(0, msaEnd   = s      - str);
                     CompletedRecursiveCall completed = completedRecursiveCall();
                     int[] callerCaptures = completed == null
    @@ -659,7 +747,7 @@ private boolean opEnd() {
     
                     if (Config.USE_CAPTURE_HISTORY && regex.captureHistory != 0) checkCaptureHistory(region);
                 } else {
    -                msaBegin = ((pkeep > s) ? s : pkeep) - str;
    +                msaBegin = visibleMatchStart() - str;
                     msaEnd   = s      - str;
                 }
             } else {
    @@ -675,6 +763,13 @@ private boolean opEnd() {
             return endBestLength();
         }
     
    +    private int visibleMatchStart() {
    +        // Perl permits a KEEP reached through a called group inside an
    +        // assertion to publish a start beyond the zero-width assertion end.
    +        // Other Joni syntaxes retain the historical non-inverted region.
    +        return regex.perlSyntax ? pkeep : Math.min(pkeep, s);
    +    }
    +
         private boolean endBestLength() {
             int effectiveOptions = regex.options | msaOptions;
             if (isFindCondition(effectiveOptions)) {
    @@ -942,7 +1037,17 @@ private void opExactNICSb() {
         private void opCondition() {
             int mem = code[ip++];
             int addr = code[ip++];
    -        if (mem > regex.numMem || repeatStk[memEndStk + mem] == INVALID_INDEX || repeatStk[memStartStk + mem] == INVALID_INDEX) {
    +        if (mem < 0) {
    +            int physical = -mem;
    +            if (physicalNamedCaptureBeg == null
    +                    || physical >= physicalNamedCaptureBeg.length
    +                    || physicalNamedCaptureBeg[physical] == INVALID_INDEX
    +                    || physicalNamedCaptureEnd[physical] == INVALID_INDEX) {
    +                ip += addr;
    +            }
    +            return;
    +        }
    +        if (mem > regex.numMem || captureIsUnset(mem)) {
                 ip += addr;
             }
         }
    @@ -1191,8 +1296,16 @@ private void opAnyCharMLSb() {
     
         private void opAnyCharStar() {
             final byte[]bytes = this.bytes;
    +        final int nextExactByte = nextExactByte();
             while (s < range) {
    -            pushAlt(ip, s, sprev, pkeep);
    +            // The compiler normally emits ANYCHAR_STAR_PEEK_NEXT when it knows
    +            // the next literal.  Some valid AST shapes do not preserve that
    +            // metadata, but the bytecode still makes a following exact literal
    +            // mandatory.  Retrying at every other position only repeats a
    +            // guaranteed failed exact match (notably /.*literal/ on a miss).
    +            if (nextExactByte < 0 || (bytes[s] & 0xff) == nextExactByte) {
    +                pushAlt(ip, s, sprev, pkeep);
    +            }
                 int n = enc.length(bytes, s, end);
                 if (s + n > range) {opFail(); return;}
                 if (enc.isNewLine(bytes, s, end)) {opFail(); return;}
    @@ -1203,14 +1316,48 @@ private void opAnyCharStar() {
     
         private void opAnyCharStarSb() {
             final byte[]bytes = this.bytes;
    +        final int nextExactByte = nextExactByte();
             while (s < range) {
    -            pushAlt(ip, s, sprev, pkeep);
    +            if (nextExactByte < 0 || (bytes[s] & 0xff) == nextExactByte) {
    +                pushAlt(ip, s, sprev, pkeep);
    +            }
                 if (bytes[s] == Encoding.NEW_LINE) {opFail(); return;}
                 sprev = s;
                 s++;
             }
         }
     
    +    /**
    +     * Return the first byte of the exact opcode immediately following an
    +     * ANYCHAR_STAR, or -1 when the following instruction cannot prove a byte.
    +     *
    +     * This deliberately recognizes only bytecode layouts whose first byte is
    +     * explicit in {@code code}; case-insensitive and template-backed strings
    +     * retain the existing fully general retry behaviour.
    +     */
    +    private int nextExactByte() {
    +        if (ip + 1 >= code.length) return -1;
    +
    +        switch (code[ip]) {
    +            case OPCode.EXACT1:
    +            case OPCode.EXACT2:
    +            case OPCode.EXACT3:
    +            case OPCode.EXACT4:
    +            case OPCode.EXACT5:
    +            case OPCode.EXACTMB2N1:
    +            case OPCode.EXACTMB2N2:
    +            case OPCode.EXACTMB2N3:
    +                return code[ip + 1] & 0xff;
    +            case OPCode.EXACTN:
    +                if (!Config.USE_STRING_TEMPLATES && ip + 2 < code.length && code[ip + 1] > 0) {
    +                    return code[ip + 2] & 0xff;
    +                }
    +                return -1;
    +            default:
    +                return -1;
    +        }
    +    }
    +
         private void opAnyCharMLStar() {
             final byte[]bytes = this.bytes;
             while (s < range) {
    @@ -1408,7 +1555,20 @@ private boolean isWordBreakBoundary() {
             byte immediateLeft = wordPropertyAt(leftPosition);
             byte right = wordPropertyAt(s);
     
    -        if (immediateLeft == WordBreakData.CR && right == WordBreakData.LF) return false; // WB3
    +        // Perl keeps every adjacent pair of word-break whitespace properties
    +        // in one span, including complete newline runs. A WSegSpace immediately
    +        // followed by Extend or Format instead binds to that character and
    +        // starts a new span from preceding WSegSpace characters. ZWJ retains
    +        // the ordinary WB4 behavior for the complete WSegSpace run.
    +        boolean leftHSpace = isPerlTailoredHSpace(leftPosition);
    +        boolean rightHSpace = isPerlTailoredHSpace(s);
    +        if ((leftHSpace || isWordNewline(immediateLeft))
    +                && (rightHSpace || isWordNewline(right))) {
    +            if (leftHSpace && rightHSpace
    +                    && isWordExtendOrFormat(immediateWordPropertyAfter(s))) return true;
    +            return false;
    +        }
    +
             if (isWordNewline(immediateLeft) || isWordNewline(right)) return true; // WB3a, WB3b
             if (isWordIgnored(right)) return false; // WB4
     
    @@ -1482,6 +1642,11 @@ private byte nextWordPropertyAfter(int position) {
             return WordBreakData.OTHER;
         }
     
    +    private byte immediateWordPropertyAfter(int position) {
    +        position += enc.length(bytes, position, end);
    +        return position < end ? wordPropertyAt(position) : WordBreakData.OTHER;
    +    }
    +
         private boolean hasOddWordRegionalIndicatorRun(int leftPosition) {
             int count = 0;
             int[] position = {leftPosition};
    @@ -1495,12 +1660,27 @@ private boolean isWordIgnored(byte property) {
                     || property == WordBreakData.ZWJ;
         }
     
    +    private boolean isWordExtendOrFormat(byte property) {
    +        return property == WordBreakData.EXTEND || property == WordBreakData.FORMAT;
    +    }
    +
         private boolean isWordNewline(byte property) {
             return property == WordBreakData.NEWLINE
                     || property == WordBreakData.CR
                     || property == WordBreakData.LF;
         }
     
    +    private boolean isPerlTailoredHSpace(int position) {
    +        int codePoint = enc.mbcToCode(bytes, position, end);
    +        return codePoint == 0x0009
    +                || codePoint == 0x0020
    +                || codePoint == 0x00a0
    +                || codePoint == 0x1680
    +                || (codePoint >= 0x2000 && codePoint <= 0x200a)
    +                || codePoint == 0x205f
    +                || codePoint == 0x3000;
    +    }
    +
         private boolean isWordAHLetter(byte property) {
             return property == WordBreakData.ALETTER
                     || property == WordBreakData.HEBREW_LETTER;
    @@ -2027,6 +2207,14 @@ private boolean isGcbControl(int codePoint) {
         }
     
         private boolean isGcb(int codePoint, UnicodeCodeRange range) {
    +        if (!enc.isUnicode()) {
    +            if (range == UnicodeCodeRange.GRAPHEMECLUSTERBREAK_CR) return codePoint == '\r';
    +            if (range == UnicodeCodeRange.GRAPHEMECLUSTERBREAK_LF) return codePoint == '\n';
    +            if (range == UnicodeCodeRange.GRAPHEMECLUSTERBREAK_CONTROL) {
    +                return codePoint < 0x20 || codePoint >= 0x7f && codePoint <= 0x9f;
    +            }
    +            return false;
    +        }
             return enc.isCodeCType(codePoint, range.getCType());
         }
     
    @@ -2324,10 +2512,36 @@ private int backrefEnd(int mem) {
             return bsAt(regex.btMemEnd, mem) ? stack[me].getMemPStr() : me;
         }
     
    +    private boolean captureIsUnset(int mem) {
    +        int start = repeatStk[memStartStk + mem];
    +        int captureEnd = repeatStk[memEndStk + mem];
    +        if (start != INVALID_INDEX && captureEnd != INVALID_INDEX) {
    +            return false;
    +        }
    +        // Only an actively open capture may consult the preceding iteration.
    +        // A fully cleared capture must stay unset after the repeat completes.
    +        if (start == INVALID_INDEX) return true;
    +        StackEntry snapshot = repeatCaptureSnapshot(mem);
    +        return snapshot == null || snapshot.getMemStart() == INVALID_INDEX
    +                || snapshot.getMemEnd() == INVALID_INDEX;
    +    }
    +
         private void backref(int mem) {
    -        if (mem > regex.numMem || backrefInvalid(mem)) {opFail(); return;}
    -        int pstart = backrefStart(mem);
    -        int pend = backrefEnd(mem);
    +        if (mem > regex.numMem) {opFail(); return;}
    +        int pstart;
    +        int pend;
    +        if (backrefInvalid(mem)) {
    +            int[] callerSnapshot = activeRecursiveCallerSnapshot(mem);
    +            if (callerSnapshot == null) {opFail(); return;}
    +            int start = callerSnapshot[mem];
    +            int end = callerSnapshot[regex.numMem + 1 + mem];
    +            if (start == INVALID_INDEX || end == INVALID_INDEX) {opFail(); return;}
    +            pstart = bsAt(regex.btMemStart, mem) ? stack[start].getMemPStr() : start;
    +            pend = bsAt(regex.btMemEnd, mem) ? stack[end].getMemPStr() : end;
    +        } else {
    +            pstart = backrefStart(mem);
    +            pend = backrefEnd(mem);
    +        }
             int n = pend - pstart;
             if (s + n > range) {opFail(); return;}
             sprev = s;
    @@ -2340,6 +2554,28 @@ private void backref(int mem) {
             }
         }
     
    +    private int[] activeRecursiveCallerSnapshot(int mem) {
    +        int returned = 0;
    +        for (int i = stk - 1; i >= 0; i--) {
    +            StackEntry entry = stack[i];
    +            if (entry.type == RETURN) {
    +                returned++;
    +            } else if (entry.type == CALL_FRAME) {
    +                if (returned > 0) {
    +                    returned--;
    +                    continue;
    +                }
    +                if (!entry.getCallFrameRecursiveVisibility()) continue;
    +                int[] snapshot = entry.getCallFrameCaptureSnapshot();
    +                if (snapshot != null && snapshot[mem] != INVALID_INDEX
    +                        && snapshot[regex.numMem + 1 + mem] != INVALID_INDEX) {
    +                    return snapshot;
    +                }
    +            }
    +        }
    +        return null;
    +    }
    +
         private void opBackRef1() {
             backref(1);
         }
    @@ -2358,11 +2594,16 @@ private void opBackRefNIC() {
             int pstart = backrefStart(mem);
             int pend = backrefEnd(mem);
             int n = pend - pstart;
    -        if (!Option.isPerlAsciiStrict(currentRegexOptions) && s + n > range) {opFail(); return;}
    +        if (!Option.isPerlAsciiStrict(currentRegexOptions)
    +                && !usesPerlVariableLengthBackref() && s + n > range) {opFail(); return;}
             sprev = s;
     
             value = s;
    -        if (!backrefStringCmpIC(currentCaseFoldFlag(), pstart, this, n, end)) {opFail(); return;}
    +        if (!backrefStringCmpIC(currentCaseFoldFlag(), pstart, this, n, end)) {
    +            value = s;
    +            if (!usesPerlVariableLengthBackref()
    +                    || !backrefPerlSimpleClassCmp(pstart, this, n)) {opFail(); return;}
    +        }
             s = value;
     
             if (sprev < range) {
    @@ -2371,6 +2612,85 @@ private void opBackRefNIC() {
             }
         }
     
    +    private StackEntry previousBackref(int mem) {
    +        if (repeatStk[memStartStk + mem] == INVALID_INDEX
    +                || repeatStk[memEndStk + mem] != INVALID_INDEX) {
    +            return null;
    +        }
    +        StackEntry snapshot = repeatCaptureSnapshot(mem);
    +        if (snapshot != null && snapshot.getMemStart() != INVALID_INDEX
    +                && snapshot.getMemEnd() != INVALID_INDEX) {
    +            return snapshot;
    +        }
    +
    +        // A recursive call opens the same capture slot again.  Its MEM_START
    +        // entry retains the closed value from the caller frame, which is the
    +        // value a self-backreference must consume while this invocation is
    +        // still open.
    +        int currentStart = repeatStk[memStartStk + mem];
    +        if (bsAt(regex.btMemStart, mem) && currentStart >= 0 && currentStart < stk) {
    +            StackEntry current = stack[currentStart];
    +            if (current.type == MEM_START && current.getMemStart() != INVALID_INDEX
    +                    && current.getMemEnd() != INVALID_INDEX) {
    +                return current;
    +            }
    +        }
    +        return null;
    +    }
    +
    +    private int previousBackrefStart(StackEntry snapshot, int mem) {
    +        int start = snapshot.getMemStart();
    +        return bsAt(regex.btMemStart, mem) ? stack[start].getMemPStr() : start;
    +    }
    +
    +    private int previousBackrefEnd(StackEntry snapshot, int mem) {
    +        int captureEnd = snapshot.getMemEnd();
    +        return bsAt(regex.btMemEnd, mem) ? stack[captureEnd].getMemPStr() : captureEnd;
    +    }
    +
    +    private void opBackRefPrevious() {
    +        int mem = code[ip++];
    +        if (mem > regex.numMem) {opFail(); return;}
    +        if (!backrefInvalid(mem)) {
    +            backref(mem);
    +            return;
    +        }
    +        StackEntry snapshot = previousBackref(mem);
    +        if (snapshot == null) {opFail(); return;}
    +        int pstart = previousBackrefStart(snapshot, mem);
    +        int n = previousBackrefEnd(snapshot, mem) - pstart;
    +        if (s + n > range) {opFail(); return;}
    +        sprev = s;
    +        while (n-- > 0) if (bytes[pstart++] != bytes[s++]) {opFail(); return;}
    +        if (sprev < range) {
    +            int len;
    +            while (sprev + (len = enc.length(bytes, sprev, end)) < s) sprev += len;
    +        }
    +    }
    +
    +    private void opBackRefPreviousIC() {
    +        int mem = code[ip++];
    +        if (mem > regex.numMem) {opFail(); return;}
    +        if (!backrefInvalid(mem)) {
    +            ip--;
    +            opBackRefNIC();
    +            return;
    +        }
    +        StackEntry snapshot = previousBackref(mem);
    +        if (snapshot == null) {opFail(); return;}
    +        int pstart = previousBackrefStart(snapshot, mem);
    +        int n = previousBackrefEnd(snapshot, mem) - pstart;
    +        if (!Option.isPerlAsciiStrict(currentRegexOptions) && s + n > range) {opFail(); return;}
    +        sprev = s;
    +        value = s;
    +        if (!backrefStringCmpIC(currentCaseFoldFlag(), pstart, this, n, end)) {opFail(); return;}
    +        s = value;
    +        if (sprev < range) {
    +            int len;
    +            while (sprev + (len = enc.length(bytes, sprev, end)) < s) sprev += len;
    +        }
    +    }
    +
         private void opBackRefMulti() {
             int tlen = code[ip++];
     
    @@ -2663,6 +2983,15 @@ private void opPushOrJumpExact1() {
     
         private void opPushIfPeekNext() {
             int addr = code[ip++];
    +        // The next-head optimization is derived from the lexical successor of
    +        // a subexpression body.  A shared body entered through a subexpression
    +        // call instead has its effective continuation at the caller, so retain
    +        // the ordinary repeat alternative for that frame.
    +        if (isInsideSubexpCall(0)) {
    +            ip++;
    +            pushAlt(ip + addr, s, sprev, pkeep);
    +            return;
    +        }
             // beyond string check
             if (s < range && code[ip] == bytes[s]) {
                 ip++;
    @@ -2758,6 +3087,24 @@ private void opRepeatIncNGSG() {
             repeatIncNG(mem, si);
         }
     
    +    private void opRepeatCaptureClear() {
    +        int id = code[ip++];
    +        beginRepeatCaptureIteration(id, regex.repeatCaptureClearGroups[id]);
    +    }
    +
    +    private void opRepeatCaptureClearEnd() {
    +        endRepeatCaptureIteration(code[ip++]);
    +    }
    +
    +    private void opScriptRun() {
    +        int start = savedPosition(StackType.POS);
    +        if (start < 0 || regex.characterPropertyResolver == null
    +                || !regex.characterPropertyResolver.isScriptRun(
    +                        bytes, start, s, enc, regex.wideScalarCodec)) {
    +            opFail();
    +        }
    +    }
    +
         private void opPushPos() {
             int addr = code[ip++];
             pushPos(ip + addr, s, sprev, pkeep);
    @@ -2878,10 +3225,19 @@ private void opCall() {
             }
             int addr = code[ip++];
             int encodedGroupNum = code[ip++];
    -        boolean recursive = encodedGroupNum <= -2;
    -        int groupNum = recursive ? -encodedGroupNum - 1 : encodedGroupNum;
    +        // -1 is emitted for the compiler's ordinary group-entry CALL.  It is
    +        // not a user-visible subpattern call and predates the flag encoding.
    +        if (encodedGroupNum == -1) {
    +            pushCallFrame(ip, -1, false, false, false);
    +            ip = addr;
    +            return;
    +        }
    +        boolean recursive = (encodedGroupNum & 0x40000000) != 0;
    +        boolean preserveCallerCaptures = (encodedGroupNum & 0x80000000) != 0;
    +        int groupNum = encodedGroupNum & 0x3fffffff;
             recursive |= isInsideSubexpCall(groupNum);
    -        pushCallFrame(ip, groupNum, recursive);
    +        pushCallFrame(ip, groupNum, recursive || preserveCallerCaptures,
    +                preserveCallerCaptures, recursive);
             ip = addr; // absolute address
         }
     
    @@ -2996,6 +3352,7 @@ private boolean opAccept() {
     
         private void opControlFail() {
             controlVerbEncountered = true;
    +        markDestructiveControl();
             String name = controlVerbName(code[ip++]);
             // An unnamed FAIL terminates the current path without replacing a
             // more specific PRUNE/SKIP/THEN/COMMIT error already encountered on
    @@ -3008,6 +3365,7 @@ private void opControlFail() {
     
         private void opPrune() {
             controlVerbEncountered = true;
    +        markDestructiveControl();
             String name = controlVerbName(code[ip++]);
             controlError = name == null ? "1" : name;
             cutAlternatives(false);
    @@ -3016,6 +3374,7 @@ private void opPrune() {
     
         private void opSkip() {
             controlVerbEncountered = true;
    +        markDestructiveControl();
             String name = controlVerbName(code[ip++]);
             controlError = name == null ? "1" : name;
             if (name != null) {
    @@ -3033,6 +3392,7 @@ private void opSkip() {
     
         private void opThen() {
             controlVerbEncountered = true;
    +        markDestructiveControl();
             String name = controlVerbName(code[ip++]);
             controlError = name == null ? "1" : name;
             cutAlternatives(true, s, sprev, pkeep);
    @@ -3041,6 +3401,7 @@ private void opThen() {
     
         private void opCommit() {
             controlVerbEncountered = true;
    +        markDestructiveControl();
             String name = controlVerbName(code[ip++]);
             controlError = name == null ? "1" : name;
             cutAlternatives(false);
    @@ -3055,6 +3416,16 @@ private void opMark() {
             controlMark = next;
         }
     
    +    private void markDestructiveControl() {
    +        preserveCalloutMutations = true;
    +        exportedDestructiveControl = true;
    +    }
    +
    +    @Override
    +    protected boolean completeCalloutsOnUnwind() {
    +        return preserveCalloutMutations;
    +    }
    +
         @Override
         protected void restoreControlMark(String name) {
             if (controlMark != null) controlError = controlMark;
    @@ -3271,7 +3642,8 @@ private CompletedRecursiveCall completedRecursiveCall() {
                 } else if (entry.type == CALL_FRAME) {
                     if (returns.isEmpty()) break;
                     int returnIndex = returns.pop();
    -                if (entry.getCallFrameCaptureSnapshot() != null
    +                if (entry.getCallFrameRecursiveVisibility()
    +                        && entry.getCallFrameCaptureSnapshot() != null
                             && (visible == null || returnIndex > visible.returnIndex)) {
                         visible = new CompletedRecursiveCall(entry, returnIndex);
                     }
    @@ -3303,6 +3675,7 @@ private void checkCapture(int capture) {
     
         private void opReturn() {
             StackEntry frame = returnFrame();
    +        restoreCallFrameCaptureSnapshot(frame);
             ip = frame.getCallFrameRetAddr();
             pushReturn();
         }
    @@ -3373,6 +3746,11 @@ int first() {
                 machine.sstart = start;
                 machine.sprev = machine.enc.prevCharHead(machine.bytes,
                         machine.str, start, machine.end);
    +            // Dynamic continuations enter execute() directly instead of going
    +            // through matchAt(), so initialize the option scope that matchAt()
    +            // normally installs.  In particular, Perl /aa case folding is a
    +            // match-time option and must remain active in the nested program.
    +            machine.currentRegexOptions = machine.regex.options;
                 machine.stk = 0;
                 machine.ip = 0;
                 machine.stackInit();
    @@ -3406,6 +3784,10 @@ void propagateControlTo(ByteCodeMachine outer) {
                 int action = machine.pendingControlAction;
                 machine.pendingControlAction = CONTROL_NONE;
                 if (machine.controlVerbEncountered) outer.controlVerbEncountered = true;
    +            if (machine.exportedDestructiveControl) {
    +                outer.markDestructiveControl();
    +                machine.exportedDestructiveControl = false;
    +            }
                 if (machine.controlError != null) outer.controlError = machine.controlError;
                 switch (action) {
                 case CONTROL_PRUNE:
    diff --git a/third_party/joni/src/org/joni/CharacterPropertyResolver.java b/third_party/joni/src/org/joni/CharacterPropertyResolver.java
    index e42ef5b6f9..ecd3a3b4b7 100644
    --- a/third_party/joni/src/org/joni/CharacterPropertyResolver.java
    +++ b/third_party/joni/src/org/joni/CharacterPropertyResolver.java
    @@ -49,10 +49,25 @@ public Result(int[] ranges, long[] wideRanges, boolean caseFold) {
     
         /**
          * Returns resolved ranges and their ignore-case policy, or {@code null} to
    -     * use the encoding's built-in property lookup. The context flag allows a
    -     * resolver to defer properties whose class-composition semantics require
    -     * frontend handling.
    +     * use the encoding's built-in property lookup. The class context allows a
    +     * resolver to defer properties whose composition semantics require host
    +     * handling. The overload below additionally exposes lexical options.
          */
         Result resolve(byte[] bytes, int p, int end, Encoding encoding,
                        boolean inCharacterClass);
    +
    +    /**
    +     * Resolves a property with the lexical option state active at its token.
    +     * Existing resolvers remain source-compatible and may ignore that state.
    +     */
    +    default Result resolve(byte[] bytes, int p, int end, Encoding encoding,
    +                           boolean inCharacterClass, int option) {
    +        return resolve(bytes, p, end, encoding, inCharacterClass);
    +    }
    +
    +    /** Validates a Perl script-run span; ordinary resolvers remain neutral. */
    +    default boolean isScriptRun(byte[] bytes, int p, int end, Encoding encoding,
    +                                WideScalarCodec wideScalarCodec) {
    +        return true;
    +    }
     }
    diff --git a/third_party/joni/src/org/joni/Compiler.java b/third_party/joni/src/org/joni/Compiler.java
    index 5e4ba18ada..f910ed87e3 100644
    --- a/third_party/joni/src/org/joni/Compiler.java
    +++ b/third_party/joni/src/org/joni/Compiler.java
    @@ -50,12 +50,12 @@ protected Compiler(Analyser analyser) {
         }
     
         final void compile(Node root) {
    -        prepare();
    +        prepare(root);
             compileTree(root);
             finish();
         }
     
    -    protected abstract void prepare();
    +    protected abstract void prepare(Node root);
         protected abstract void finish();
     
         protected abstract void compileAltNode(ListNode node);
    diff --git a/third_party/joni/src/org/joni/Lexer.java b/third_party/joni/src/org/joni/Lexer.java
    index 033a38a62b..beab1e18b2 100644
    --- a/third_party/joni/src/org/joni/Lexer.java
    +++ b/third_party/joni/src/org/joni/Lexer.java
    @@ -52,6 +52,7 @@ class Lexer extends ScannerSupport {
         private boolean perlVerticalWhitespaceNegated;
         private int perlNonNewlineTokenIndex = -1;
         private int perlCharacterPropertyEscape;
    +    private boolean perlCommentSeparatedGroupToken;
     
         protected Lexer(Regex regex, Syntax syntax, byte[]bytes, int p, int end, WarnCallback warnings) {
             super(regex.enc, bytes, p, end);
    @@ -140,7 +141,12 @@ private int fetchRangeQuantifier() {
             if (c != '}') return invalidRangeQuantifier(synAllow);
     
             if (!isRepeatInfinite(up) && low > up) {
    -            newValueException(UPPER_SMALLER_THAN_LOWER_IN_REPEAT_RANGE);
    +            if (syntax.op2OptionPerl()) {
    +                syntaxWarn("Quantifier {n,m} with n > m can't match",
    +                        p - getBegin());
    +            } else {
    +                newValueException(UPPER_SMALLER_THAN_LOWER_IN_REPEAT_RANGE);
    +            }
             }
     
             token.type = TokenType.INTERVAL;
    @@ -214,6 +220,7 @@ private void fetchEscapedValue() {
             case 'c':
                 if (syntax.opEscCControl()) {
                     fetchEscapedValueControl();
    +                if (syntax.op2OptionPerl()) break;
                 }
                 /* fall through */
     
    @@ -235,6 +242,7 @@ private void fetchEscapedValueControl() {
                 }
             }
             fetch();
    +        int argument = c;
             if (c == '?') {
                 c = 0177;
             } else {
    @@ -244,8 +252,31 @@ private void fetchEscapedValueControl() {
                 if (c == syntax.metaCharTable.esc && !syntax.op2OptionPerl()) {
                     fetchEscapedValue();
                 }
    -            c &= 0x9f;
    +            if (syntax.op2OptionPerl()) {
    +                if (argument < 0x20 || argument > 0x7e) {
    +                    newSyntaxException(PERL_CONTROL_ARGUMENT_MUST_BE_PRINTABLE_ASCII,
    +                            p - getBegin());
    +                }
    +                if (c >= 'a' && c <= 'z') c -= 'a' - 'A';
    +                c ^= 0x40;
    +                warnObscurePerlControlEscape(argument, c);
    +            } else {
    +                c &= 0x9f;
    +            }
    +        }
    +    }
    +
    +    private void warnObscurePerlControlEscape(int argument, int resolved) {
    +        if (argument >= 'A' && argument <= 'Z'
    +                || argument >= 'a' && argument <= 'z'
    +                || argument >= '@' && argument <= '_') {
    +            return;
             }
    +        String replacement = resolved == ' ' ? "\\ "
    +                : Character.toString((char)resolved);
    +        syntaxWarn("\"\\c" + (char)argument
    +                + "\" is more clearly written simply as \""
    +                + replacement + "\"", p - getBegin());
         }
     
         private int nameEndCodePoint(int start) {
    @@ -263,6 +294,11 @@ private int nameEndCodePoint(int start) {
             }
         }
     
    +    protected final boolean isPerlGroupNameStart(int code) {
    +        return code == '_' || Character.isLetter(code)
    +                || Character.getType(code) == Character.LETTER_NUMBER;
    +    }
    +
         // USE_NAMED_GROUP && USE_BACKREF_AT_LEVEL
         /*
             \k, \k
    @@ -397,6 +433,8 @@ private int fetchNameForNamedGroup(int startCode, boolean ref) {
                         err = INVALID_GROUP_NAME;
                         // isNum = 0;
                     }
    +            } else if (!ref && syntax.op2OptionPerl() && !isPerlGroupNameStart(c)) {
    +                err = INVALID_GROUP_NAME;
                 }
             }
     
    @@ -679,6 +717,16 @@ private TokenType fetchPerlVerticalWhitespaceToken() {
                 index--;
             }
     
    +        // The dedicated byte-pattern variant can only consume byte subjects.
    +        // Keep LF..CR and NEL, but do not feed LS/PS to the single-byte
    +        // encoding (notably while ignore-case builds its parallel class).
    +        if (Option.isPerlBytePattern(env.option) && index >= 4) {
    +            token.type = TokenType.CC_CLOSE;
    +            token.setC(']');
    +            perlVerticalWhitespaceTokenIndex = -1;
    +            return token.type;
    +        }
    +
             switch (index) {
             case 0:
                 token.type = TokenType.CODE_POINT;
    @@ -724,7 +772,11 @@ private boolean usesPerlNonNewlineEscape() {
         private boolean isPerlNonNewlineIntervalAhead() {
             if (!left() || !peekIs('{')) return false;
     
    -        int cursor = nextChar(p, stop);
    +        return isPerlNonNewlineIntervalAt(p);
    +    }
    +
    +    private boolean isPerlNonNewlineIntervalAt(int brace) {
    +        int cursor = nextChar(brace, stop);
             boolean sawLow = false;
             boolean sawComma = false;
             boolean sawHigh = false;
    @@ -733,7 +785,10 @@ private boolean isPerlNonNewlineIntervalAhead() {
                 if (code == '}') {
                     return sawComma ? sawLow || sawHigh : sawLow;
                 }
    -            if (code >= '0' && code <= '9') {
    +            if (Character.isWhitespace(code)) {
    +                cursor = nextChar(cursor, stop);
    +                continue;
    +            } else if (code >= '0' && code <= '9') {
                     if (sawComma) sawHigh = true;
                     else sawLow = true;
                 } else if (code == ',' && !sawComma) {
    @@ -781,6 +836,7 @@ private void fetchTokenInCCFor_p() {
                 token.setPropNot(c == 'P');
     
                 if (left() && syntax.op2EscPBraceCircumflexNot()) {
    +                skipPerlPropertyWhitespaceBeforeCaret();
                     c2 = fetchTo();
                     if (c2 == '^') {
                         token.setPropNot(!token.getPropNot());
    @@ -798,7 +854,12 @@ private void fetchTokenInCCFor_p() {
         }
     
         private void fetchTokenInCCFor_x() {
    -        if (!left()) return;
    +        if (!left()) {
    +            if (perlNumericEscapesAreFatal()) {
    +                newSyntaxException(PERL_EMPTY_UNBRACED_HEX_ESCAPE);
    +            }
    +            return;
    +        }
             int last = p;
     
             if (peekIs('{') && syntax.opEscXBraceHex8()) {
    @@ -812,7 +873,11 @@ private void fetchTokenInCCFor_x() {
             } else if (syntax.opEscXHex2()) {
                 int num = scanUnsignedHexadecimalNumber(0, 2);
                 if (num < 0) newValueException(TOO_BIG_NUMBER);
    +            checkPerlUnbracedHexSuffix(last, num);
                 if (p == last) { /* can't read nothing. */
    +                if (perlNumericEscapesAreFatal()) {
    +                    newSyntaxException(PERL_EMPTY_UNBRACED_HEX_ESCAPE);
    +                }
                     num = 0; /* but, it's not error */
                 }
                 if (syntax.op2OptionPerl()) {
    @@ -843,7 +908,13 @@ private void fetchTokenFor_oBrace() {
     
         private boolean fetchTokenFor_namedCharacter(boolean inCharacterClass) {
             NamedCharacterResolver resolver = syntax.namedCharacterResolver;
    -        if (resolver == null || !syntax.op2OptionPerl() || !left() || !peekIs('{')) {
    +        if (resolver == null || !syntax.op2OptionPerl() || !left()) {
    +            return false;
    +        }
    +        if (!peekIs('{')) {
    +            if (!inCharacterClass && hasSeparatedNamedCharacterBrace()) {
    +                newSyntaxException(PERL_MISSING_BRACES_ON_NAMED_CHARACTER_ESCAPE);
    +            }
                 return false;
             }
             if (usesPerlNonNewlineEscape() && isPerlNonNewlineIntervalAhead()) {
    @@ -875,6 +946,7 @@ private boolean fetchTokenFor_namedCharacter(boolean inCharacterClass) {
                 } else if (sequence.length == 1) {
                     token.type = TokenType.CODE_POINT;
                     token.setCode(sequence[0]);
    +                token.namedCharacter = true;
                 } else {
                     token.type = TokenType.NAMED_STRING;
                     token.setNamedCharacterSequence(sequence);
    @@ -886,6 +958,41 @@ private boolean fetchTokenFor_namedCharacter(boolean inCharacterClass) {
             return true; // not reached
         }
     
    +    private boolean hasSeparatedNamedCharacterBrace() {
    +        int cursor = p;
    +        boolean skipped = false;
    +        while (cursor < stop) {
    +            int next = bytes[cursor] & 0xff;
    +            if (isExtend(env.option) && (next == ' ' || next == '\t'
    +                    || next == '\n' || next == '\r' || next == '\f')) {
    +                cursor++;
    +                skipped = true;
    +                continue;
    +            }
    +            if (cursor + 2 < stop && next == '('
    +                    && bytes[cursor + 1] == '?' && bytes[cursor + 2] == '#') {
    +                int comment = cursor + 3;
    +                boolean closed = false;
    +                while (comment < stop) {
    +                    int value = bytes[comment++] & 0xff;
    +                    if (value == '\\' && comment < stop) {
    +                        comment++;
    +                    } else if (value == ')') {
    +                        closed = true;
    +                        break;
    +                    }
    +                }
    +                if (!closed) return false;
    +                cursor = comment;
    +                skipped = true;
    +                continue;
    +            }
    +            break;
    +        }
    +        return skipped && cursor < stop && bytes[cursor] == '{'
    +                && !isPerlNonNewlineIntervalAt(cursor);
    +    }
    +
         private void scanOriginalBracedHexCodePoint(int last) {
             inc();
             int num = scanUnsignedHexadecimalNumber(0, 8);
    @@ -916,6 +1023,7 @@ private long scanPerlBracedCodePoint(int radix, char escape) {
             int significantDigitCount = 0;
             boolean sawDigit = false;
             int invalid = -1;
    +        int invalidPosition = -1;
             while (cursor < close) {
                 int code = codeAt(cursor, close);
                 int digit = perlEscapeDigit(code, radix);
    @@ -944,6 +1052,7 @@ private long scanPerlBracedCodePoint(int radix, char escape) {
                     break;
                 }
                 invalid = code;
    +            invalidPosition = cursor;
                 break;
             }
     
    @@ -952,13 +1061,25 @@ private long scanPerlBracedCodePoint(int radix, char escape) {
                     newSyntaxException(PERL_EMPTY_OCTAL_ESCAPE,
                             close + enc.length(bytes, close, stop) - getBegin());
                 }
    +            if (perlNumericEscapesAreFatal()) {
    +                newSyntaxException(PERL_EMPTY_HEX_ESCAPE,
    +                        close + enc.length(bytes, close, stop) - getBegin());
    +            }
                 value = 0;
             } else if (invalid >= 0) {
                 String kind = escape == 'o' ? "octal" : "hex";
    +            if (perlNumericEscapesAreFatal()) {
    +                newSyntaxException(escape == 'o'
    +                                ? PERL_NON_OCTAL_CHARACTER : PERL_NON_HEX_CHARACTER,
    +                        nextChar(invalidPosition, close) - getBegin());
    +            }
                 String warning = "Non-" + kind + " character '" + (char)invalid
                         + "' terminates \\" + escape + " early.";
    +            String resolvedDigits = formatPerlResolvedEscape(value, radix);
    +            String sourceDigits = perlEscapeSourceDigits(numberStart, invalidPosition, radix);
    +            resolvedDigits = preservePerlEscapeDigitCase(resolvedDigits, sourceDigits);
                 String resolution = " Resolved as \"\\" + escape + "{"
    -                    + formatPerlResolvedEscape(value, radix) + "}\"";
    +                    + resolvedDigits + "}\"";
                 if (syntax.op2OptionPerl() && env.warnings.supportsPositions()) {
                     syntaxWarn(warning + " " + resolution,
                             close + enc.length(bytes, close, stop) - getBegin());
    @@ -994,11 +1115,27 @@ private int findPerlBracedEscapeClose(char escape) {
             int cursor = p;
             while (cursor < stop) {
                 if (codeAt(cursor, stop) == '}') return cursor;
    +            if (codeAt(cursor, stop) == ']') break;
                 cursor = nextChar(cursor, stop);
             }
    +        while (cursor > p) {
    +            int previous = enc.prevCharHead(bytes, p, cursor, stop);
    +            if (!isPerlEscapeWhitespace(codeAt(previous, stop))) break;
    +            cursor = previous;
    +        }
    +        int firstContent = p;
    +        while (firstContent < cursor
    +                && isPerlEscapeWhitespace(codeAt(firstContent, stop))) {
    +            firstContent = nextChar(firstContent, stop);
    +        }
    +        int diagnosticPosition = firstContent < cursor
    +                && perlEscapeDigit(codeAt(firstContent, stop),
    +                        escape == 'o' ? 8 : 16) >= 0
    +                ? cursor : p;
             newSyntaxException(escape == 'o'
                     ? PERL_MISSING_RIGHT_BRACE_ON_OCTAL_ESCAPE
    -                : PERL_MISSING_RIGHT_BRACE_ON_HEX_ESCAPE);
    +                : PERL_MISSING_RIGHT_BRACE_ON_HEX_ESCAPE,
    +                diagnosticPosition - getBegin());
             return stop;
         }
     
    @@ -1029,6 +1166,83 @@ private static String formatPerlResolvedEscape(long value, int radix) {
             return "0".repeat(Math.max(0, minimumWidth - digits.length())) + digits;
         }
     
    +    private static String preservePerlEscapeDigitCase(String resolved, String source) {
    +        int suffix = resolved.length() - source.length();
    +        if (suffix >= 0 && resolved.regionMatches(true, suffix, source, 0, source.length())) {
    +            return resolved.substring(0, suffix) + source;
    +        }
    +        return resolved;
    +    }
    +
    +    private boolean perlNumericEscapesAreFatal() {
    +        return Option.isPerlReStrict(env.option) || env.inPerlExtendedClass;
    +    }
    +
    +    private String perlEscapeSourceDigits(int start, int end, int radix) {
    +        StringBuilder digits = new StringBuilder();
    +        int cursor = start;
    +        while (cursor >= 0 && cursor < end) {
    +            int code = codeAt(cursor, end);
    +            if (perlEscapeDigit(code, radix) >= 0) digits.append((char)code);
    +            cursor = nextChar(cursor, end);
    +        }
    +        return digits.toString();
    +    }
    +
    +    private int asciiCharacterCount(int start, int end) {
    +        int count = 0;
    +        for (int cursor = start; cursor < end; cursor = nextChar(cursor, end)) count++;
    +        return count;
    +    }
    +
    +    private void checkPerlUnbracedHexSuffix(int digitsStart, int value) {
    +        if (!syntax.op2OptionPerl()) return;
    +        int digitCount = asciiCharacterCount(digitsStart, p);
    +        if (digitCount == 2 && left() && enc.isXDigit(peek())) {
    +            if (perlNumericEscapesAreFatal()) {
    +                newSyntaxException(PERL_HEX_ESCAPE_MORE_THAN_TWO_DIGITS,
    +                        nextChar(p, stop) - getBegin());
    +            }
    +            return;
    +        }
    +        if (digitCount != 1 || !left()) return;
    +        int invalid = peek();
    +        if (!Character.isLetterOrDigit(invalid) || enc.isXDigit(invalid)) return;
    +        if (perlNumericEscapesAreFatal()) {
    +            newSyntaxException(PERL_NON_HEX_CHARACTER,
    +                    nextChar(p, stop) - getBegin());
    +        }
    +        String digits = perlEscapeSourceDigits(digitsStart, p, 16);
    +        String resolved = formatPerlResolvedEscape(value, 16);
    +        resolved = preservePerlEscapeDigitCase(resolved, digits);
    +        syntaxWarn("Non-hex character '" + (char)invalid
    +                + "' terminates \\x early.  Resolved as \"\\x"
    +                + resolved + (char)invalid + "\"", p - getBegin());
    +    }
    +
    +    private void warnPerlShortOctalTermination(int value) {
    +        if (!left()) return;
    +        int invalid = peek();
    +        if (invalid != '8' && invalid != '9') return;
    +        syntaxWarn("Non-octal character '" + (char)invalid
    +                + "' terminates \\0 early.  Resolved as \"\\"
    +                + formatPerlResolvedEscape(value, 8) + (char)invalid + "\"",
    +                nextChar(p, stop) - getBegin());
    +    }
    +
    +    private int perlCharacterClassDiagnosticEnd(int cursor) {
    +        boolean escaped = false;
    +        while (cursor < stop) {
    +            int code = codeAt(cursor, stop);
    +            int next = nextChar(cursor, stop);
    +            if (!escaped && code == ']') return next - getBegin();
    +            if (!escaped && code == syntax.metaCharTable.esc) escaped = true;
    +            else escaped = false;
    +            cursor = next;
    +        }
    +        return cursor - getBegin();
    +    }
    +
         private boolean onlyPerlEscapeWhitespaceAfter(int cursor, int close) {
             while (cursor < close) {
                 if (!isPerlEscapeWhitespace(codeAt(cursor, close))) return false;
    @@ -1068,10 +1282,24 @@ private void fetchTokenInCCFor_u() {
     
         private void fetchTokenInCCFor_digit() {
             if (syntax.opEscOctal3()) {
    +            int firstDigit = c;
                 unfetch();
                 int last = p;
                 int num = scanUnsignedOctalNumber(3);
                 if (num < 0) newValueException(TOO_BIG_NUMBER);
    +            int digitCount = asciiCharacterCount(last, p);
    +            if (syntax.op2OptionPerl() && firstDigit == '0') {
    +                int next = left() ? peek() : -1;
    +                boolean tooLong = next >= '0' && next <= '7';
    +                if (perlNumericEscapesAreFatal()
    +                        && (digitCount != 3 || tooLong)) {
    +                    int position = digitCount < 3 && (next == '8' || next == '9')
    +                            ? nextChar(p, stop) - getBegin()
    +                            : perlCharacterClassDiagnosticEnd(p);
    +                    newSyntaxException(PERL_EXTENDED_CLASS_OCTAL_WIDTH, position);
    +                }
    +                warnPerlShortOctalTermination(num);
    +            }
                 if (p == last) {  /* can't read nothing. */
                     num = 0; /* but, it's not error */
                 }
    @@ -1087,25 +1315,83 @@ private void fetchTokenInCCFor_digit() {
             }
         }
     
    +    /**
    +     * Returns the byte immediately after an unescaped {@code delimiter]} pair,
    +     * or -1 when this is not a POSIX equivalence/collating construct.  Perl
    +     * reserves these constructs only when they occur as a nested class form
    +     * such as {@code [[=name=]]}; a single outer class {@code [=name=]} stays
    +     * ordinary class text.
    +     */
    +    private int reservedPosixSyntaxEnd(int delimiter) {
    +        int scan = p;
    +        while (scan < stop) {
    +            int code = enc.mbcToCode(bytes, scan, stop);
    +            int next = scan + enc.length(bytes, scan, stop);
    +            if (code == syntax.metaCharTable.esc) {
    +                // Perl falls back to ordinary class parsing as soon as this
    +                // candidate contains an escape, even if a later delimiter]
    +                // pair would otherwise make it look reserved.
    +                return -1;
    +            } else if (code == ']') {
    +                return -1;
    +            } else if (code == delimiter && next < stop
    +                    && enc.mbcToCode(bytes, next, stop) == ']') {
    +                return next + enc.length(bytes, next, stop);
    +            }
    +            scan = next;
    +        }
    +        return -1;
    +    }
    +
         private void fetchTokenInCCFor_posixBracket() {
    +        boolean perlPosixCandidate = false;
    +        if (syntax.op3PerlLiteralOpenInCC()
    +                && (peekIs(':') || peekIs('.') || peekIs('='))) {
    +            int afterDelimiter = p + enc.length(bytes, p, stop);
    +            perlPosixCandidate = afterDelimiter >= stop
    +                    || enc.mbcToCode(bytes, afterDelimiter, stop) != ']';
    +        }
    +        if (syntax.op2OptionPerl() && (peekIs('=') || peekIs('.'))) {
    +            int delimiter = peek();
    +            token.backP = p;
    +            inc();
    +            if (left() && !peekIs(']')) {
    +                int syntaxEnd = reservedPosixSyntaxEnd(delimiter);
    +                if (syntaxEnd >= 0) {
    +                    newSyntaxException(delimiter == '='
    +                                    ? PERL_POSIX_EQUIVALENCE_CLASS_RESERVED
    +                                    : PERL_POSIX_COLLATING_ELEMENT_RESERVED,
    +                            syntaxEnd - getBegin());
    +                }
    +            }
    +            unfetch();
    +        }
             if (syntax.opPosixBracket() && peekIs(':')) {
                 token.backP = p; /* point at '[' is readed */
                 inc();
    -            if (strExistCheckWithEsc(send, send.length, ']')) {
    +            // Perl treats an empty [:] opener as ordinary class text rather
    +            // than an empty POSIX class.  Do not enter the POSIX parser unless
    +            // there is at least one name character before the closing :].
    +            if (left() && !peekIs(']')
    +                    && (strExistCheckWithEsc(send, send.length, ']')
    +                            || env.usesPerlDiagnostics() && perlPosixCandidate)) {
                     token.type = TokenType.POSIX_BRACKET_OPEN;
                 } else {
                     unfetch();
                     // remove duplication, goto cc_in_cc;
    -                if (syntax.op2CClassSetOp()) {
    +                boolean perlLiteralOpen = syntax.op3PerlLiteralOpenInCC();
    +                if (syntax.op2CClassSetOp() && !perlLiteralOpen) {
                         token.type = TokenType.CC_CC_OPEN;
    -                } else {
    +                } else if (!perlLiteralOpen) {
                         env.ccEscWarn("[");
                     }
                 }
             } else { // cc_in_cc:
    -            if (syntax.op2CClassSetOp()) {
    +            boolean perlLiteralOpen = syntax.op3PerlLiteralOpenInCC()
    +                    && !perlPosixCandidate;
    +            if (syntax.op2CClassSetOp() && !perlLiteralOpen) {
                     token.type = TokenType.CC_CC_OPEN;
    -            } else {
    +            } else if (!perlLiteralOpen) {
                     env.ccEscWarn("[");
                 }
             }
    @@ -1119,6 +1405,7 @@ private void fetchTokenInCCFor_and() {
         }
     
         protected final TokenType fetchTokenInCC() {
    +        token.namedCharacter = false;
             if (perlNonNewlineTokenIndex >= 0) {
                 return fetchPerlNonNewlineToken();
             }
    @@ -1139,6 +1426,25 @@ protected final TokenType fetchTokenInCC() {
                     break;
                 }
             }
    +        boolean literalVerticalSpace = c == '\n' || c == '\r'
    +                || c == '\f' || c == 0x0b;
    +        if (syntax.op2OptionPerl() && Option.isPerlReStrict(env.option)
    +                && !Option.isPerlExtendMore(env.option)
    +                && literalVerticalSpace) {
    +            newSyntaxException(
    +                    "Literal vertical space in [] is illegal except under /x",
    +                    p - getBegin());
    +        }
    +        if (syntax.op2OptionPerl() && Option.isPerlExtendMore(env.option)) {
    +            if (c == '#') {
    +                syntaxWarn("Use of unescaped '#' in [] is deprecated under /xx",
    +                        p - getBegin());
    +            } else if (literalVerticalSpace) {
    +                syntaxWarn("Use of literal vertical space in [] is deprecated under /xx",
    +                        p - getBegin());
    +            }
    +        }
    +        token.backP = getLastFetched();
             token.type = TokenType.CHAR;
             token.base = 0;
             token.setC(c);
    @@ -1234,6 +1540,14 @@ protected final TokenType fetchTokenInCC() {
                 case '7':
                     fetchTokenInCCFor_digit();
                     break;
    +            case '8':
    +            case '9':
    +                if (syntax.op2OptionPerl()) {
    +                    syntaxWarn("Unrecognized escape \\" + (char)c
    +                            + " in character class passed through",
    +                            p - getBegin());
    +                }
    +                break;
     
                 case 'v':
                 case 'V':
    @@ -1244,6 +1558,13 @@ protected final TokenType fetchTokenInCC() {
                     // fall through
     
                 default:
    +                if (syntax.op2OptionPerl() && isAsciiLetter(c)
    +                        && "ntrfabevcCMV".indexOf(c) < 0) {
    +                    syntaxWarn("Unrecognized escape \\" + (char)c
    +                            + " in character class passed through",
    +                            p - getBegin());
    +                    break;
    +                }
                     unfetch();
                     fetchEscapedValue();
                     if (token.getC() != c) {
    @@ -1294,7 +1615,12 @@ private void fetchTokenFor_anchor(int subType) {
         }
     
         private void fetchTokenFor_xBrace() {
    -        if (!left()) return;
    +        if (!left()) {
    +            if (perlNumericEscapesAreFatal()) {
    +                newSyntaxException(PERL_EMPTY_UNBRACED_HEX_ESCAPE);
    +            }
    +            return;
    +        }
     
             int last = p;
             if (peekIs('{') && syntax.opEscXBraceHex8()) {
    @@ -1307,7 +1633,11 @@ private void fetchTokenFor_xBrace() {
             } else if (syntax.opEscXHex2()) {
                 int num = scanUnsignedHexadecimalNumber(0, 2);
                 if (num < 0) newValueException(TOO_BIG_NUMBER);
    +            checkPerlUnbracedHexSuffix(last, num);
                 if (p == last) { /* can't read nothing. */
    +                if (perlNumericEscapesAreFatal()) {
    +                    newSyntaxException(PERL_EMPTY_UNBRACED_HEX_ESCAPE);
    +                }
                     num = 0; /* but, it's not error */
                 }
                 if (syntax.op2OptionPerl()) {
    @@ -1356,6 +1686,7 @@ private void fetchTokenFor_digit() {
             }
     
             if (c == '8' || c == '9') { /* normal char */ // skip_backref:
    +            if (syntax.op2OptionPerl()) newValueException(INVALID_BACKREF);
                 p = last;
                 inc();
                 return;
    @@ -1370,6 +1701,9 @@ private void fetchTokenFor_zero() {
                 int last = p;
                 int num = scanUnsignedOctalNumber(c == '0' ? 2 : 3);
                 if (num < 0) newValueException(TOO_BIG_NUMBER);
    +            if (syntax.op2OptionPerl() && c == '0') {
    +                warnPerlShortOctalTermination(num);
    +            }
                 if (p == last) { /* can't read nothing. */
                     num = 0; /* but, it's not error */
                 }
    @@ -1412,6 +1746,20 @@ private void fetchTokenFor_NamedBackref() {
                                 newSyntaxException(PERL_GROUP_NAME_MUST_START_WITH_WORD,
                                         p - getBegin());
                             }
    +                        int nameStart = p;
    +                        if (c == '{') {
    +                            while (nameStart < stop
    +                                    && Character.isWhitespace(codeAt(nameStart, stop))) {
    +                                nameStart = nextChar(nameStart, stop);
    +                            }
    +                        }
    +                        if (nameStart < stop) {
    +                            int initial = codeAt(nameStart, stop);
    +                            if (!isPerlGroupNameStart(initial)) {
    +                                newSyntaxException(PERL_GROUP_NAME_MUST_START_WITH_WORD,
    +                                        nameStart - getBegin());
    +                            }
    +                        }
                         }
                         fetchNamedBackrefToken();
                     } else {
    @@ -1431,7 +1779,8 @@ private void fetchTokenFor_subexpCall() {
             rejectMalformedPerlBackref();
             if (syntax.op2OptionPerl() && left() && peek() >= '0' && peek() <= '9') {
                 int backref = scanUnsignedNumber();
    -            if (backref <= 0 || backref > env.numMem) newValueException(INVALID_BACKREF);
    +            if (backref == 0) newValueException(PERL_REFERENCE_TO_INVALID_GROUP_ZERO);
    +            if (backref < 0 || backref > env.numMem) newValueException(INVALID_BACKREF);
                 token.type = TokenType.BACKREF;
                 token.setBackrefByName(false);
                 token.setBackrefNum(1);
    @@ -1440,10 +1789,11 @@ private void fetchTokenFor_subexpCall() {
                 return;
             }
             if (Config.USE_NAMED_GROUP) {
    -            if (syntax.op2EscGBraceBackref() && left()) {
    +            if ((syntax.op2EscGBraceBackref() || syntax.op2OptionPerl()) && left()) {
                     fetch();
                     if (c == '{') {
    -                    fetchNamedBackrefToken();
    +                    if (!fetchPerlNumericBackrefToken()) fetchNamedBackrefToken();
    +                    return;
                     } else {
                         unfetch();
                     }
    @@ -1482,8 +1832,11 @@ private void fetchTokenFor_subexpCall() {
                             && enc.isDigit(peek())) {
                         int nameP = enc.prevCharHead(bytes, getBegin(), p, stop);
                         int gNum = scanUnsignedNumber();
    -                    if (gNum <= 0) newValueException(gNum < 0
    -                            ? TOO_BIG_NUMBER : INVALID_BACKREF);
    +                    if (gNum == 0) newValueException(PERL_REFERENCE_TO_INVALID_GROUP_ZERO);
    +                    if (gNum < 0) newValueException(TOO_BIG_NUMBER);
    +                    if (gNum > env.numMem) {
    +                        newValueException(PERL_REFERENCE_TO_NONEXISTENT_OR_UNCLOSED_GROUP);
    +                    }
                         token.type = TokenType.CALL;
                         token.setCallNameP(nameP);
                         token.setCallNameEnd(p);
    @@ -1497,6 +1850,48 @@ private void fetchTokenFor_subexpCall() {
             }
         }
     
    +    private boolean fetchPerlNumericBackrefToken() {
    +        if (!syntax.op2OptionPerl()) return false;
    +
    +        int cursor = p;
    +        while (cursor < stop && Character.isWhitespace(codeAt(cursor, stop))) {
    +            cursor = nextChar(cursor, stop);
    +        }
    +        boolean negative = cursor < stop && codeAt(cursor, stop) == '-';
    +        if (negative) cursor = nextChar(cursor, stop);
    +        int digitsStart = cursor;
    +        long number = 0;
    +        boolean overflow = false;
    +        while (cursor < stop && enc.isDigit(codeAt(cursor, stop))) {
    +            int digit = Encoding.digitVal(codeAt(cursor, stop));
    +            if (number > (Integer.MAX_VALUE - digit) / 10L) overflow = true;
    +            else if (!overflow) number = number * 10 + digit;
    +            cursor = nextChar(cursor, stop);
    +        }
    +        if (cursor == digitsStart) return false;
    +        while (cursor < stop && Character.isWhitespace(codeAt(cursor, stop))) {
    +            cursor = nextChar(cursor, stop);
    +        }
    +        if (cursor >= stop || codeAt(cursor, stop) != '}') return false;
    +        p = nextChar(cursor, stop);
    +
    +        if (overflow) newValueException(INVALID_BACKREF);
    +        if (number == 0) newValueException(PERL_REFERENCE_TO_INVALID_GROUP_ZERO);
    +        long absolute = negative ? (long)env.numMem + 1 - number : number;
    +        if (absolute <= 0 || absolute > env.numMem || env.memNodes == null
    +                || absolute >= env.memNodes.length
    +                || env.memNodes[(int)absolute] == null) {
    +            newValueException(negative
    +                    ? PERL_REFERENCE_TO_NONEXISTENT_OR_UNCLOSED_GROUP : INVALID_BACKREF);
    +        }
    +        token.type = TokenType.BACKREF;
    +        token.setBackrefByName(false);
    +        token.setBackrefNum(1);
    +        token.setBackrefRef1((int)absolute);
    +        if (Config.USE_BACKREF_WITH_LEVEL) token.setBackrefExistLevel(false);
    +        return true;
    +    }
    +
         private void rejectMalformedPerlBackref() {
             if (!syntax.op2OptionPerl()) return;
             if (!left()) {
    @@ -1561,6 +1956,7 @@ private void rejectMalformedPerlBackref() {
         }
     
         protected void fetchNamedBackrefToken() {
    +        int delimiter = c;
             int last = p;
             int backNum;
             if (Config.USE_BACKREF_WITH_LEVEL) {
    @@ -1574,13 +1970,25 @@ protected void fetchNamedBackrefToken() {
             } // USE_BACKREF_AT_LEVEL
             int nameEnd = value; // set by fetchNameWithLevel/fetchName
     
    +        if (syntax.op2OptionPerl() && delimiter == '{') {
    +            while (last < nameEnd && Character.isWhitespace(codeAt(last, nameEnd))) {
    +                last = nextChar(last, nameEnd);
    +            }
    +            while (last < nameEnd) {
    +                int previous = enc.prevCharHead(bytes, last, nameEnd, stop);
    +                if (!Character.isWhitespace(codeAt(previous, nameEnd))) break;
    +                nameEnd = previous;
    +            }
    +        }
    +
             if (backNum != 0) {
                 if (backNum < 0) {
                     backNum = backrefRelToAbs(backNum);
                     if (backNum <= 0) newValueException(INVALID_BACKREF);
                 }
     
    -            if (syntax.strictCheckBackref() && (backNum > env.numMem || env.memNodes == null)) {
    +            if (syntax.strictCheckBackref() && (backNum > env.numMem || env.memNodes == null
    +                    || backNum >= env.memNodes.length || env.memNodes[backNum] == null)) {
                     newValueException(INVALID_BACKREF);
                 }
                 token.type = TokenType.BACKREF;
    @@ -1589,7 +1997,16 @@ protected void fetchNamedBackrefToken() {
                 token.setBackrefRef1(backNum);
             } else {
                 NameEntry e = regex.nameToGroupNumbers(bytes, last, nameEnd);
    -            if (e == null) newValueException(UNDEFINED_NAME_REFERENCE, last, nameEnd);
    +            if (e == null) {
    +                if (syntax.op2OptionPerl()) {
    +                    token.type = TokenType.BACKREF;
    +                    token.setBackrefByName(true);
    +                    token.setBackrefNum(0);
    +                    token.setBackrefName(last, nameEnd);
    +                    return;
    +                }
    +                newValueException(UNDEFINED_NAME_REFERENCE, last, nameEnd);
    +            }
     
                 if (syntax.strictCheckBackref()) {
                     if (e.backNum == 1) {
    @@ -1626,6 +2043,7 @@ private void fetchTokenFor_charProperty() {
                 token.setPropNot(c == 'P');
     
                 if (left() && syntax.op2EscPBraceCircumflexNot()) {
    +                skipPerlPropertyWhitespaceBeforeCaret();
                     fetch();
                     if (c == '^') {
                         token.setPropNot(!token.getPropNot());
    @@ -1649,6 +2067,17 @@ private void fetchTokenFor_charProperty() {
             }
         }
     
    +    private void skipPerlPropertyWhitespaceBeforeCaret() {
    +        if (!syntax.op2OptionPerl()) return;
    +        int cursor = p;
    +        while (cursor < stop && Character.isWhitespace(enc.mbcToCode(bytes, cursor, stop))) {
    +            cursor += enc.length(bytes, cursor, stop);
    +        }
    +        if (cursor > p && cursor < stop && enc.mbcToCode(bytes, cursor, stop) == '^') {
    +            p = cursor;
    +        }
    +    }
    +
         private static boolean isAsciiLetter(int codePoint) {
             return codePoint >= 'A' && codePoint <= 'Z' || codePoint >= 'a' && codePoint <= 'z';
         }
    @@ -1681,6 +2110,7 @@ protected final void fetchToken() {
                 token.type = TokenType.STRING;
                 token.base = 0;
                 token.backP = p;
    +            token.setBackrefName(-1, -1);
     
                 fetch();
     
    @@ -1864,6 +2294,31 @@ protected final void fetchToken() {
                     case 'K':
                         if (syntax.op2EscCapitalKKeep()) token.type = TokenType.KEEP;
                         break;
    +                case 'c':
    +                    if (syntax.opEscCControl()) {
    +                        // A control escape can resolve to the literal 'c'
    +                        // itself (notably \c#). Do not infer whether the
    +                        // escape changed from token.getC(); its token identity
    +                        // is unconditionally a code point.
    +                        unfetch();
    +                        fetchEscapedValue();
    +                        token.type = TokenType.CODE_POINT;
    +                        token.setCode(c);
    +                        break;
    +                    }
    +                    unfetch();
    +                    fetchEscapedValue();
    +                    if (token.getC() != c) {
    +                        token.type = TokenType.CODE_POINT;
    +                        token.setCode(c);
    +                    } else {
    +                        int encLength = enc.length(bytes, token.backP, stop);
    +                        if (encLength == Encoding.CHAR_INVALID) {
    +                            throw new IllegalArgumentException("Invalid character found.");
    +                        }
    +                        p = token.backP + encLength;
    +                    }
    +                    break;
                     case 'v':
                     case 'V':
                         if (usesPerlVerticalWhitespaceEscape()) {
    @@ -1872,6 +2327,12 @@ protected final void fetchToken() {
                         }
                         // fall through
                     default:
    +                    if (syntax.op2OptionPerl() && isAsciiLetter(c)
    +                            && "ntrfabevcCMV".indexOf(c) < 0) {
    +                        syntaxWarn("Unrecognized escape \\" + (char)c
    +                                + " passed through", p - getBegin());
    +                        break;
    +                    }
                         unfetch();
                         fetchEscapedValue();
                         if (token.getC() != c) { /* set_raw: */
    @@ -1891,6 +2352,18 @@ protected final void fetchToken() {
                     token.setC(c);
                     token.escaped = false;
     
    +                if (perlCommentSeparatedGroupToken) {
    +                    perlCommentSeparatedGroupToken = false;
    +                    if (syntax.op2OptionPerl() && c == '?') {
    +                        newSyntaxException(PERL_GROUP_INTRODUCER_NOT_ADJACENT);
    +                    }
    +                    if (syntax.op2OptionPerl() && c == '*') {
    +                        newSyntaxException(left() && Character.isUpperCase(peek())
    +                                ? PERL_VERB_INTRODUCER_NOT_ADJACENT
    +                                : PERL_STAR_GROUP_INTRODUCER_NOT_ADJACENT);
    +                    }
    +                }
    +
                     if (Config.USE_VARIABLE_META_CHARS && (c != MetaChar.INEFFECTIVE_META_CHAR && syntax.opVariableMetaCharacters())) {
                         fetchTokenFor_metaChars();
                         break;
    @@ -1920,6 +2393,10 @@ protected final void fetchToken() {
                         case '(':
                             if (peekIs('?') && syntax.op2QMarkGroupEffect()) {
                                 inc();
    +                            if (Option.isPerlReStrict(env.option) && peekIs(')')) {
    +                                syntaxWarn("Empty (?) without any modifiers",
    +                                        p + enc.length(bytes, p, stop) - getBegin());
    +                            }
                                 if (syntax.op2OptionPerl() && peekIs('[')) {
                                     inc();
                                     token.type = TokenType.EXTENDED_CC_OPEN;
    @@ -1928,7 +2405,11 @@ protected final void fetchToken() {
                                 if (peekIs('#')) {
                                     fetch();
                                     while (true) {
    -                                    if (!left()) newSyntaxException(END_PATTERN_IN_GROUP);
    +                                    if (!left()) {
    +                                        newSyntaxException(syntax.op2OptionPerl()
    +                                                ? PERL_COMMENT_GROUP_NOT_TERMINATED
    +                                                : END_PATTERN_IN_GROUP);
    +                                    }
                                         fetch();
                                         if (c == syntax.metaCharTable.esc) {
                                             if (left()) fetch();
    @@ -1936,6 +2417,7 @@ protected final void fetchToken() {
                                             if (c == ')') break;
                                         }
                                     }
    +                                perlCommentSeparatedGroupToken = true;
                                     continue start; // goto start
                                 }
                                 unfetch();
    @@ -1957,7 +2439,17 @@ protected final void fetchToken() {
                             break;
                         case ']':
                             if (src > getBegin()) { /* /].../ is allowed. */
    -                            env.closeBracketWithoutEscapeWarn("]");
    +                            if (Option.isPerlReStrict(env.option)
    +                                    && (p < getBegin() + 2 || bytes[p - 2] != ']')) {
    +                                syntaxWarn("Unescaped literal ']'", p - getBegin());
    +                            } else {
    +                                env.closeBracketWithoutEscapeWarn("]");
    +                            }
    +                        }
    +                        break;
    +                    case '}':
    +                        if (Option.isPerlReStrict(env.option)) {
    +                            syntaxWarn("Unescaped literal '}'", p - getBegin());
                             }
                             break;
                         case '#':
    @@ -2000,7 +2492,13 @@ private boolean fetchTokenForPerlBoundary(boolean negated) {
                 fetch();
                 if (c == '}') {
                     String boundaryName = name.toString().trim();
    -                if (boundaryName.equals("gcb")) {
    +                if (boundaryName.equals("g") || boundaryName.equals("gcb")) {
    +                    if (Option.isPerlExplicitAscii(env.option)) {
    +                        String boundary = negated ? "B" : "b";
    +                        syntaxWarn("Using /u for '\\" + boundary + "{"
    +                                + boundaryName + "}' instead of /a",
    +                                p - getBegin());
    +                    }
                         fetchTokenFor_anchor(negated
                                 ? AnchorType.NOT_GRAPHEME_BOUNDARY
                                 : AnchorType.GRAPHEME_BOUNDARY);
    @@ -2046,6 +2544,11 @@ private void greedyCheck() {
     
                 token.setRepeatGreedy(false);
                 token.setRepeatPossessive(false);
    +            if (syntax.op2OptionPerl() && token.type == TokenType.INTERVAL
    +                    && token.getRepeatLower() == token.getRepeatUpper()) {
    +                syntaxWarn("Useless use of greediness modifier '?'",
    +                        p - getBegin());
    +            }
                 rejectPerlNestedQuantifierModifier();
             } else {
                 possessiveCheck();
    @@ -2124,7 +2627,8 @@ protected final CharProperty fetchCharProperty(boolean inCharacterClass) {
                     if (syntax.characterPropertyResolver != null) {
                         CharacterPropertyResolver.Result resolved =
                                 syntax.characterPropertyResolver.resolve(
    -                                    bytes, _p, last, enc, inCharacterClass);
    +                                    bytes, _p, last, enc, inCharacterClass,
    +                                    env.option);
                         if (resolved != null) {
                             validateCharacterPropertyRanges(resolved.ranges,
                                     resolved.wideRanges);
    @@ -2141,6 +2645,11 @@ protected final CharProperty fetchCharProperty(boolean inCharacterClass) {
                     throw new CharacterPropertyException(EncodingError.ERR_INVALID_CHAR_PROPERTY_NAME, bytes, _p, last);
                 }
             }
    +        if (syntax.op2OptionPerl()) {
    +            newSyntaxException(PERL_MISSING_RIGHT_BRACE_ON_CHARACTER_PROPERTY.replace(
    +                    "%n", Character.toString(perlCharacterPropertyEscape)),
    +                    _p - getBegin());
    +        }
             newValueException(PROPERTY_NAME_NEVER_TERMINATED, _p, stop);
             return null; // not reached
         }
    diff --git a/third_party/joni/src/org/joni/Matcher.java b/third_party/joni/src/org/joni/Matcher.java
    index 8130404498..a500b90741 100644
    --- a/third_party/joni/src/org/joni/Matcher.java
    +++ b/third_party/joni/src/org/joni/Matcher.java
    @@ -490,15 +490,10 @@ private final int searchCommon(int gpos, int start, int range, int option, boole
                 if ((regex.anchor & AnchorType.BEGIN_POSITION) != 0) {
                     /* search start-position only */
                     // !begin_position:!
    -                if (range > start) {
    -                    if (gpos > start) {
    -                        if (gpos < range) range = gpos + 1;
    -                    } else {
    -                        range = start + 1;
    -                    }
    -                } else {
    -                    range = start;
    -                }
    +                int lower = Math.min(start, range);
    +                int upper = Math.max(start, range);
    +                if (gpos < lower || gpos > upper) return FAILED;
    +                start = range = gpos;
                 } else if ((regex.anchor & AnchorType.BEGIN_BUF) != 0) {
                     /* search str-position only */
                     if (range > start) {
    @@ -711,7 +706,9 @@ private final boolean endBuf(int start, int range, int minSemiEnd, int maxSemiEn
                 if ((maxSemiEnd - (range - 1)) < regex.anchorDmin) {
                     range = maxSemiEnd - regex.anchorDmin + 1;
                 }
    -            if (start >= range) return true; // mismatch_no_msa;
    +            if (start > range || start == range && regex.anchorDmin > 0) {
    +                return true; // mismatch_no_msa;
    +            }
             } else {
                 if ((minSemiEnd - range) > regex.anchorDmax) {
                     range = minSemiEnd - regex.anchorDmax;
    diff --git a/third_party/joni/src/org/joni/Option.java b/third_party/joni/src/org/joni/Option.java
    index 38d4214e8c..0dcb856edb 100644
    --- a/third_party/joni/src/org/joni/Option.java
    +++ b/third_party/joni/src/org/joni/Option.java
    @@ -52,8 +52,12 @@ public final class Option {
         public static final int PERL_BYTE_PATTERN    = (1 << 20);
         /** Perl /xx: EXTEND plus unescaped horizontal-space elision in classes. */
         public static final int PERL_EXTEND_MORE     = (1 << 21);
    +    /** Perl lexical {@code use re 'strict'} diagnostic policy. */
    +    public static final int PERL_RE_STRICT       = (1 << 22);
    +    /** Perl explicit /a or /aa, distinct from internal ASCII class selection. */
    +    public static final int PERL_EXPLICIT_ASCII  = (1 << 23);
     
    -    public static final int MAXBIT               = (1 << 22); /* limit */
    +    public static final int MAXBIT               = (1 << 24); /* limit */
     
         public static final int DEFAULT              = NONE;
     
    @@ -75,6 +79,8 @@ public static String toString(int option) {
             if (isPerlAsciiStrict(option)) options += "PERL_ASCII_STRICT";
             if (isPerlBytePattern(option)) options += "PERL_BYTE_PATTERN";
             if (isPerlExtendMore(option)) options += "PERL_EXTEND_MORE";
    +        if (isPerlReStrict(option)) options += "PERL_RE_STRICT";
    +        if (isPerlExplicitAscii(option)) options += "PERL_EXPLICIT_ASCII";
             return options;
         }
     
    @@ -90,6 +96,14 @@ public static boolean isPerlExtendMore(int option) {
             return (option & PERL_EXTEND_MORE) != 0;
         }
     
    +    public static boolean isPerlReStrict(int option) {
    +        return (option & PERL_RE_STRICT) != 0;
    +    }
    +
    +    public static boolean isPerlExplicitAscii(int option) {
    +        return (option & PERL_EXPLICIT_ASCII) != 0;
    +    }
    +
         public static boolean isSingleline(int option) {
             return (option & SINGLELINE) != 0;
         }
    diff --git a/third_party/joni/src/org/joni/Parser.java b/third_party/joni/src/org/joni/Parser.java
    index 0ee1339eb5..3a4cc527ba 100644
    --- a/third_party/joni/src/org/joni/Parser.java
    +++ b/third_party/joni/src/org/joni/Parser.java
    @@ -24,6 +24,7 @@
     import static org.joni.Option.isAsciiRange;
     import static org.joni.Option.isDontCaptureGroup;
     import static org.joni.Option.isIgnoreCase;
    +import static org.joni.Option.isPerlReStrict;
     import static org.joni.Option.isPosixBracketAllRange;
     
     import java.nio.charset.StandardCharsets;
    @@ -168,6 +169,240 @@ private void generate(int[] folded, int[] replacement, int index,
     
         protected Parser(Regex regex, Syntax syntax, byte[]bytes, int p, int end, WarnCallback warnings) {
             super(regex, syntax, bytes, p, end, warnings);
    +        emitPerlPosixDiagnostics();
    +    }
    +
    +    private static final Set PERL_POSIX_NAMES = Set.of(
    +            "alnum", "alpha", "ascii", "blank", "cntrl", "digit", "graph",
    +            "lower", "print", "punct", "space", "upper", "word", "xdigit");
    +
    +    private boolean asciiAt(int position, int value) {
    +        return position >= getBegin() && position < getEnd()
    +                && (bytes[position] & 0xff) == value;
    +    }
    +
    +    private boolean asciiOnly(int start, int end) {
    +        for (int cursor = start; cursor < end; cursor++) {
    +            if ((bytes[cursor] & 0x80) != 0) return false;
    +        }
    +        return true;
    +    }
    +
    +    private String asciiText(int start, int end) {
    +        return new String(bytes, start, end - start, StandardCharsets.US_ASCII);
    +    }
    +
    +    private boolean knownPosixName(String name) {
    +        if (name.startsWith("^")) name = name.substring(1);
    +        return PERL_POSIX_NAMES.contains(name);
    +    }
    +
    +    private boolean plausiblePosixName(String name) {
    +        String lower = name.toLowerCase(java.util.Locale.ROOT);
    +        if (knownPosixName(lower)) return true;
    +        if (lower.length() < POSIX_BRACKET_NAME_MIN_LEN) return false;
    +        for (String known : PERL_POSIX_NAMES) {
    +            if (known.length() != lower.length() + 1) continue;
    +            for (int omitted = 0; omitted < known.length(); omitted++) {
    +                if ((known.substring(0, omitted) + known.substring(omitted + 1))
    +                        .equals(lower)) return true;
    +            }
    +        }
    +        return false;
    +    }
    +
    +    private boolean insidePerlCharacterClass(int position) {
    +        boolean inClass = false;
    +        for (int cursor = getBegin(); cursor < position; cursor++) {
    +            if (asciiAt(cursor, '\\')) {
    +                cursor++;
    +                continue;
    +            }
    +            if (!inClass) {
    +                if (asciiAt(cursor, '[')) inClass = true;
    +                continue;
    +            }
    +            if (asciiAt(cursor, '[') && cursor + 2 < position
    +                    && (asciiAt(cursor + 1, ':') || asciiAt(cursor + 1, '.')
    +                            || asciiAt(cursor + 1, '='))) {
    +                int delimiter = bytes[cursor + 1] & 0xff;
    +                int nested = cursor + 2;
    +                while (nested + 1 < position
    +                        && !(asciiAt(nested, delimiter)
    +                                && asciiAt(nested + 1, ']'))) nested++;
    +                if (nested + 1 < position) {
    +                    cursor = nested + 1;
    +                    continue;
    +                }
    +            }
    +            if (asciiAt(cursor, ']')) inClass = false;
    +        }
    +        return inClass;
    +    }
    +
    +    private void posixWarn(String reason, int position) {
    +        syntaxWarn("Assuming NOT a POSIX class since " + reason,
    +                position - getBegin());
    +    }
    +
    +    /**
    +     * Perl diagnoses near-miss POSIX spellings before ordinary character-class
    +     * parsing. Keep that lexical policy in Joni so consumers receive ordered,
    +     * byte-positioned metadata without inspecting regex source themselves.
    +     */
    +    private void emitPerlPosixDiagnostics() {
    +        if (!env.usesPerlDiagnostics() || env.warnings == WarnCallback.NONE) return;
    +
    +        int begin = getBegin();
    +        int end = getEnd();
    +        for (int i = begin; i + 2 < end; i++) {
    +            if (asciiAt(i, '\\')) {
    +                if (++i < end && (bytes[i] & 0x80) != 0) {
    +                    i += enc.length(bytes, i, end) - 1;
    +                }
    +                continue;
    +            }
    +            if (!asciiAt(i, '[')) continue;
    +
    +            // A single bracket around POSIX-looking text is an ordinary class,
    +            // but Perl warns that the construct belongs one bracket deeper.
    +            int delimiter = bytes[i + 1] & 0xff;
    +            if ((delimiter == ':' || delimiter == '.' || delimiter == '=')
    +                    && !insidePerlCharacterClass(i)) {
    +                int cursor = i + 2;
    +                int close = -1;
    +                int delimiterEnd = -1;
    +                while (cursor < end && !asciiAt(cursor, ']')) {
    +                    if (asciiAt(cursor, delimiter)) delimiterEnd = cursor;
    +                    cursor++;
    +                }
    +                if (cursor < end) close = cursor;
    +                if (delimiter != ':') {
    +                    if (delimiterEnd >= i + 2 && delimiterEnd + 1 == close) {
    +                        char delimiterChar = (char)delimiter;
    +                        syntaxWarn("POSIX syntax [" + delimiterChar + " "
    +                                + delimiterChar + "] belongs inside character classes "
    +                                + "(but this one isn't implemented)", close + 1 - begin);
    +                    }
    +                } else if (close >= 0) {
    +                    boolean terminated = delimiterEnd >= i + 2
    +                            && delimiterEnd + 1 == close;
    +                    String name = terminated && asciiOnly(i + 2, delimiterEnd)
    +                            ? asciiText(i + 2, delimiterEnd) : "";
    +                    if (!terminated && (!asciiOnly(i + 2, close)
    +                            || !plausiblePosixName(asciiText(i + 2, close)))) {
    +                        continue;
    +                    }
    +                    boolean valid = terminated && knownPosixName(name.toLowerCase(
    +                            java.util.Locale.ROOT));
    +                    String suffix = valid ? ""
    +                            : " (but this one isn't fully valid)";
    +                    syntaxWarn("POSIX syntax [: :] belongs inside character classes"
    +                            + suffix, terminated ? close + 1 - begin : close - begin);
    +                }
    +            }
    +        }
    +
    +        for (int i = begin; i + 3 < end; i++) {
    +            if (!asciiAt(i, '[') || !asciiAt(i + 1, '[')) continue;
    +
    +            if (asciiAt(i + 2, ':')) {
    +                int nameStart = i + 3;
    +                int cursor = nameStart;
    +                while (cursor < end && !asciiAt(cursor, ':')
    +                        && !asciiAt(cursor, ']')) cursor++;
    +                if (cursor >= end || !asciiOnly(nameStart, cursor)) continue;
    +                String name = asciiText(nameStart, cursor);
    +                if (asciiAt(cursor, ':')) {
    +                    if (!asciiAt(cursor + 1, ']')
    +                            && (plausiblePosixName(name) || name.indexOf('#') >= 0)) {
    +                        posixWarn("there is no terminating ']'", cursor + 1);
    +                    }
    +                } else if (plausiblePosixName(name)) {
    +                    if (!name.equals(name.toLowerCase(java.util.Locale.ROOT))) {
    +                        posixWarn("the name must be all lowercase letters", cursor);
    +                    }
    +                    posixWarn("there is no terminating ':'", cursor);
    +                }
    +                continue;
    +            }
    +
    +            if (asciiAt(i + 2, ' ')) {
    +                emitSpacedPosixDiagnostics(i, end);
    +                continue;
    +            }
    +
    +            int cursor = i + 2;
    +            boolean caret = asciiAt(cursor, '^');
    +            if (caret) cursor++;
    +            int nameStart = cursor;
    +            while (cursor < end && !asciiAt(cursor, ']')) cursor++;
    +            if (cursor >= end || !asciiOnly(nameStart, cursor)) continue;
    +            String name = asciiText(nameStart, cursor);
    +            if (!plausiblePosixName(name)) continue;
    +            if (caret) {
    +                posixWarn("the '^' must come after the colon", nameStart);
    +            }
    +            posixWarn("there must be a starting ':'", nameStart);
    +            posixWarn("there is no terminating ':'", cursor);
    +        }
    +
    +        for (int i = begin; i + 3 < end; i++) {
    +            if (!asciiAt(i, ':') || asciiAt(i - 1, '[')) continue;
    +            int nameEnd = i + 1;
    +            while (nameEnd < end && !asciiAt(nameEnd, ':')
    +                    && !asciiAt(nameEnd, ']')) nameEnd++;
    +            if (!asciiAt(nameEnd, ':') || !asciiAt(nameEnd + 1, ']')
    +                    || !asciiOnly(i + 1, nameEnd)) continue;
    +            if (knownPosixName(asciiText(i + 1, nameEnd))) {
    +                posixWarn("it doesn't start with a '['", i);
    +            }
    +        }
    +
    +        for (int i = begin; i + 3 < end; i++) {
    +            if (!asciiAt(i, ';')) continue;
    +            int nameEnd = i + 1;
    +            while (nameEnd < end && !asciiAt(nameEnd, ';')
    +                    && !asciiAt(nameEnd, ']')) nameEnd++;
    +            if (!asciiAt(nameEnd, ';') || !asciiAt(nameEnd + 1, ']')
    +                    || !asciiOnly(i + 1, nameEnd)
    +                    || !knownPosixName(asciiText(i + 1, nameEnd))) continue;
    +            if (!asciiAt(i - 1, '[')) {
    +                posixWarn("it doesn't start with a '['", i);
    +            }
    +            posixWarn("a semi-colon was found instead of a colon", i + 1);
    +            posixWarn("a semi-colon was found instead of a colon", nameEnd + 2);
    +            i = nameEnd;
    +        }
    +    }
    +
    +    private void emitSpacedPosixDiagnostics(int open, int end) {
    +        int caret = open + 2;
    +        while (caret < end && asciiAt(caret, ' ')) caret++;
    +        if (!asciiAt(caret, '^')) return;
    +        int colon = caret + 1;
    +        while (colon < end && asciiAt(colon, ' ')) colon++;
    +        if (!asciiAt(colon, ':')) return;
    +        int close = colon + 1;
    +        while (close < end && !asciiAt(close, ']')) close++;
    +        if (close >= end) return;
    +        int outerClose = close + 1;
    +        while (outerClose < end && asciiAt(outerClose, ' ')) outerClose++;
    +        if (!asciiAt(outerClose, ']')) return;
    +
    +        posixWarn("no blanks are allowed in one", caret);
    +        posixWarn("the '^' must come after the colon", caret + 1);
    +        if (asciiAt(caret + 1, ' ')) {
    +            posixWarn("no blanks are allowed in one", colon);
    +        }
    +        if (asciiAt(colon + 1, ' ')) {
    +            int nameStart = colon + 1;
    +            while (nameStart < close && asciiAt(nameStart, ' ')) nameStart++;
    +            posixWarn("no blanks are allowed in one", nameStart);
    +        }
    +        if (asciiAt(close + 1, ' ')) {
    +            posixWarn("no blanks are allowed in one", close + 1);
    +        }
         }
     
         private void setLexicalMemNode(EncloseNode node) {
    @@ -184,6 +419,7 @@ private void setLexicalMemNode(EncloseNode node) {
         private static final int POSIX_BRACKET_NAME_MIN_LEN            = 4;
         private static final int POSIX_BRACKET_CHECK_LIMIT_LENGTH      = 20;
         private static final byte[] BRACKET_END                        = ":]".getBytes();
    +    private static final byte[] POSIX_ASCII                        = "ascii".getBytes();
         private boolean parsePosixBracket(CClassNode cc, CClassNode ascCc,
                                           CClassNode foldCc) {
             mark();
    @@ -199,23 +435,72 @@ private boolean parsePosixBracket(CClassNode cc, CClassNode ascCc,
             if (enc.strLength(bytes, p, stop) >= POSIX_BRACKET_NAME_MIN_LEN + 3) { // else goto not_posix_bracket
                 boolean asciiRange = isAsciiRange(env.option) && !isPosixBracketAllRange(env.option);
     
    +            // [:ascii:] is a Perl POSIX extension absent from JCodings' POSIX
    +            // name table. Represent it as its concrete Unicode scalar range
    +            // so it composes with the normal extended-class set operators.
    +            if (enc.strNCmp(bytes, p, stop, POSIX_ASCII, 0, POSIX_ASCII.length) == 0) {
    +                p = enc.step(bytes, p, stop, POSIX_ASCII.length);
    +                if (enc.strNCmp(bytes, p, stop, BRACKET_END, 0, BRACKET_END.length) != 0) {
    +                    if (env.usesPerlDiagnostics()) {
    +                        restore();
    +                        return true;
    +                    }
    +                    newSyntaxException(INVALID_POSIX_BRACKET_TYPE);
    +                }
    +                if (not) {
    +                    cc.addCodeRange(env, 0x80, 0x10FFFF);
    +                } else {
    +                    cc.bs.setRange(env, 0, 0x7F);
    +                }
    +                if (foldCc != null) {
    +                    if (not) {
    +                        foldCc.addCodeRange(env, 0x80, 0x10FFFF);
    +                    } else {
    +                        foldCc.bs.setRange(env, 0, 0x7F);
    +                    }
    +                }
    +                inc();
    +                inc();
    +                return false;
    +            }
    +
                 for (int i=0; i 'z') return false;
    +            cursor += enc.length(bytes, cursor, end);
    +            length++;
    +        }
    +        return length != 1;
    +    }
    +
    +    private void addPerlLiteralPosixText(CClassNode cc, CClassNode ascCc,
    +                                         CClassNode foldCc, int start, int end) {
    +        cc.addCodeRange(env, ':', ':');
    +        if (ascCc != null) ascCc.addCodeRange(env, ':', ':');
    +        if (foldCc != null) foldCc.addCodeRange(env, ':', ':');
    +        for (int cursor = start; cursor < end; ) {
    +            int code = enc.mbcToCode(bytes, cursor, end);
    +            cc.addCodeRange(env, code, code);
    +            if (ascCc != null) ascCc.addCodeRange(env, code, code);
    +            if (foldCc != null) foldCc.addCodeRange(env, code, code);
    +            cursor += enc.length(bytes, cursor, end);
    +        }
    +    }
    +
         private boolean codeExistCheck(int code, boolean ignoreEscaped) {
             mark();
     
    @@ -274,11 +602,29 @@ private boolean codeExistCheck(int code, boolean ignoreEscaped) {
             return false;
         }
     
    +    private boolean extendedPosixPrimaryUsesParser() {
    +        int nameStart = p + 2;
    +        int cursor = nameStart;
    +        while (cursor < stop && !asciiAt(cursor, ':')
    +                && !asciiAt(cursor, ']')) cursor++;
    +        if (!asciiAt(cursor, ':') || !asciiAt(cursor + 1, ']')) return false;
    +        if (!asciiOnly(nameStart, cursor)) return false;
    +        String name = asciiText(nameStart, cursor);
    +        return name.length() >= POSIX_BRACKET_NAME_MIN_LEN;
    +    }
    +
         private record ParsedCharClass(CClassNode standard,
                                        List namedSequences) {}
     
         private record PerlExtendedClassPrimary(CClassNode node,
    -                                            boolean scopedOptionsApplied) {}
    +                                            CClassNode asciiFoldSource,
    +                                            CClassNode foldSource,
    +                                            boolean scopedOptionsApplied) {
    +        private PerlExtendedClassPrimary(
    +                CClassNode node, boolean scopedOptionsApplied) {
    +            this(node, node, node, scopedOptionsApplied);
    +        }
    +    }
     
         private final class PerlCharsetOptionState {
             private int asciiModifierCount;
    @@ -302,6 +648,7 @@ int apply(int option, int modifier, boolean neg, boolean rejectLocale) {
                     option = bsOnOff(option, Option.ASCII_RANGE, false);
                     option = bsOnOff(option, Option.POSIX_BRACKET_ALL_RANGE, true);
                     option = bsOnOff(option, Option.WORD_BOUND_ALL_RANGE, true);
    +                option = bsOnOff(option, Option.PERL_EXPLICIT_ASCII, false);
                     return bsOnOff(option, Option.PERL_ASCII_STRICT,
                             syntax.op2OptionPerl() && asciiModifierCount >= 2
                                     ? false : true);
    @@ -316,6 +663,7 @@ int apply(int option, int modifier, boolean neg, boolean rejectLocale) {
                     option = bsOnOff(option, Option.ASCII_RANGE, true);
                     option = bsOnOff(option, Option.POSIX_BRACKET_ALL_RANGE, true);
                     option = bsOnOff(option, Option.WORD_BOUND_ALL_RANGE, true);
    +                option = bsOnOff(option, Option.PERL_EXPLICIT_ASCII, true);
                     return bsOnOff(option, Option.PERL_ASCII_STRICT, true);
                 case 'd':
                     if (!syntax.op2OptionPerl() || neg) {
    @@ -325,7 +673,13 @@ int apply(int option, int modifier, boolean neg, boolean rejectLocale) {
                         newSyntaxException(PERL_MODIFIERS_D_AND_A_MUTUALLY_EXCLUSIVE);
                     }
                     sawDefaultCharset = true;
    -                option = bsOnOff(option, Option.ASCII_RANGE, true);
    +                // Perl /d keeps character classes byte-oriented when both
    +                // pattern and subject are byte strings, but promotes them for
    +                // a UTF-8 subject. The adapter selects a dedicated
    +                // PERL_BYTE_PATTERN variant for the former case.
    +                option = bsOnOff(option, Option.ASCII_RANGE,
    +                        !Option.isPerlBytePattern(option));
    +                option = bsOnOff(option, Option.PERL_EXPLICIT_ASCII, true);
                     return bsOnOff(option, Option.PERL_ASCII_STRICT, true);
                 case 'l':
                     if (rejectLocale) {
    @@ -342,6 +696,7 @@ int apply(int option, int modifier, boolean neg, boolean rejectLocale) {
                     }
                     sawLocaleCharset = true;
                     option = bsOnOff(option, Option.ASCII_RANGE, true);
    +                option = bsOnOff(option, Option.PERL_EXPLICIT_ASCII, true);
                     return bsOnOff(option, Option.PERL_ASCII_STRICT, true);
                 default:
                     throw new AssertionError(modifier);
    @@ -388,6 +743,11 @@ private ParsedCharClass parseCharClass(ObjPtr ascNode,
             arg.state = CCSTATE.START;
             while (token.type != TokenType.CC_CLOSE) {
                 boolean fetched = false;
    +            arg.toEscaped = token.escaped;
    +            arg.toNamedCharacter = token.namedCharacter;
    +            arg.toFalseRangeEligible = false;
    +            arg.toStart = token.backP - getBegin();
    +            arg.toEnd = p - getBegin();
     
                 switch (token.type) {
                 case CHAR:
    @@ -453,9 +813,25 @@ private ParsedCharClass parseCharClass(ObjPtr ascNode,
                     if (perlExtendedClassLeaf && namedSequence.length == 0) {
                         newSyntaxException(PERL_EXTENDED_CLASS_ZERO_LENGTH_NAMED_CHARACTER);
                     }
    -                if (neg && namedSequence.length > 1) {
    +                boolean namedSequenceStartsRange = false;
    +                if (!neg && namedSequence.length > 1
    +                        && arg.state != CCSTATE.RANGE) {
    +                    // A multi-code-point \N{} is normally an atomic string
    +                    // alternative in a positive class.  Look one token ahead
    +                    // before committing it as a class member: when followed
    +                    // by '-', Perl instead uses one code point as the range
    +                    // endpoint and emits the same warning as for a negated
    +                    // class.  Keeping the fetched token lets the ordinary
    +                    // range state machine consume the '-' on the next pass.
    +                    fetchTokenInCC();
    +                    fetched = true;
    +                    namedSequenceStartsRange = token.type == TokenType.CC_RANGE;
    +                }
    +                if (namedSequence.length > 1
    +                        && (neg || arg.state == CCSTATE.RANGE
    +                                || namedSequenceStartsRange)) {
                         syntaxWarn("Using just the first character returned by \\N{} in character class",
    -                            p - getBegin());
    +                            arg.toEnd);
                         // Perl 5 observably selects the final source-order code
                         // point here, although its warning calls it the "first".
                         arg.to = namedSequence[namedSequence.length - 1];
    @@ -464,7 +840,9 @@ private ParsedCharClass parseCharClass(ObjPtr ascNode,
                     } else {
                         cc.nextStateClass(arg, ascCc, foldCc, env);
                     }
    -                if (!neg && namedSequence.length > 0) {
    +                if (!neg && namedSequence.length > 0
    +                        && !namedSequenceStartsRange
    +                        && arg.state != CCSTATE.COMPLETE) {
                         namedSequences.add(namedCharacterStringNode(
                                 namedSequence));
                     }
    @@ -479,17 +857,29 @@ private ParsedCharClass parseCharClass(ObjPtr ascNode,
     
                 case POSIX_BRACKET_OPEN:
                     if (parsePosixBracket(cc, ascCc, foldCc)) { /* true: is not POSIX bracket */
    -                    env.ccEscWarn("[");
    -                    p = token.backP;
    +                    if (!env.usesPerlDiagnostics()) env.ccEscWarn("[");
    +                    // Perl recovers a POSIX-looking near miss as literal class
    +                    // text. Consume the candidate '[' exactly once; rewinding
    +                    // onto it reparses it as a nested class and can turn a
    +                    // recoverable spelling into a spurious Unmatched [ error.
    +                    p = env.usesPerlDiagnostics()
    +                            ? token.backP + enc.length(bytes, token.backP, stop)
    +                            : token.backP;
                         arg.to = token.getC();
                         arg.toIsRaw = false;
                         parseCharClassValEntry(cc, ascCc, foldCc, arg); // goto val_entry
                         break;
                     }
    +                arg.toStart = token.backP - getBegin() - 1;
    +                arg.toEnd = p - getBegin();
    +                warnFalseRangeBeforeClass(arg, arg.toEnd);
    +                arg.toFalseRangeEligible = true;
                     cc.nextStateClass(arg, ascCc, foldCc, env); // goto next_class
                     break;
     
                 case CHAR_TYPE:
    +                warnFalseRangeBeforeClass(arg, p - getBegin());
    +                arg.toFalseRangeEligible = true;
                     cc.addCType(token.getPropCType(), token.getPropNot(), isAsciiRange(env.option), env, this);
                     if (ascCc != null) {
                         if (token.getPropCType() != CharacterType.WORD) {
    @@ -505,12 +895,28 @@ private ParsedCharClass parseCharClass(ObjPtr ascNode,
     
                 case CHAR_PROPERTY:
                     CharProperty property = fetchCharProperty(true);
    +                arg.toEnd = p - getBegin();
    +                warnFalseRangeBeforeClass(arg, arg.toEnd);
    +                arg.toFalseRangeEligible = true;
                     addCharProperty(cc, ascCc, foldCc, property, token.getPropNot());
                     cc.nextStateClass(arg, ascCc, foldCc, env); // goto next_class
                     break;
     
                 case CC_RANGE:
                     if (arg.state == CCSTATE.VALUE) {
    +                    if (arg.type == CCVALTYPE.CLASS && env.usesPerlDiagnostics()) {
    +                        // Perl accepts [\d-z] as a false range: retain the
    +                        // class and make the hyphen a pending literal value.
    +                        if (arg.fromFalseRangeEligible) warnFalseRangeAfterClass(arg);
    +                        arg.state = CCSTATE.COMPLETE;
    +                        arg.to = '-';
    +                        arg.toIsRaw = false;
    +                        arg.toEscaped = false;
    +                        arg.toNamedCharacter = false;
    +                        arg.inType = CCVALTYPE.SB;
    +                        cc.nextStateValue(arg, ascCc, foldCc, env);
    +                        break;
    +                    }
                         fetchTokenInCC();
                         fetched = true;
                         if (token.type == TokenType.CC_CLOSE) { /* allow [x-] */
    @@ -526,6 +932,8 @@ private ParsedCharClass parseCharClass(ObjPtr ascNode,
                     } else if (arg.state == CCSTATE.START) {
                         arg.to = token.getC(); /* [-xa] is allowed */
                         arg.toIsRaw = false;
    +                    arg.toEscaped = false;
    +                    arg.toNamedCharacter = false;
                         fetchTokenInCC();
                         fetched = true;
                         if (token.type == TokenType.CC_RANGE || andStart) env.ccEscWarn("-"); /* [--x] or [a&&-x] is warned. */
    @@ -558,8 +966,21 @@ private ParsedCharClass parseCharClass(ObjPtr ascNode,
                     break;
     
                 case CC_CC_OPEN: /* [ */
    -                if (perlExtendedClassLeaf) {
    -                    newSyntaxException(PERL_EXTENDED_CLASS_UNEXPECTED_OUTER_CLOSE);
    +                if (perlExtendedClassLeaf && !token.escaped) {
    +                    // A standard class remains a leaf of (?[...]). Ruby's
    +                    // class-set lexer tokenizes '[' specially, but Perl still
    +                    // permits it as an unescaped member here (for example
    +                    // [^][ \\ ] and [a[]).
    +                    //
    +                    // Escapes such as \\h synthesize a nested character class
    +                    // token sequence. They must still be consumed as that
    +                    // sequence; treating their opening token as a literal '['
    +                    // leaves the generated contents in the outer expression.
    +                    arg.inType = CCVALTYPE.SB;
    +                    arg.to = '[';
    +                    arg.toIsRaw = false;
    +                    parseCharClassValEntry2(cc, ascCc, foldCc, arg);
    +                    break;
                     }
                     ObjPtr ascPtr = new ObjPtr<>();
                     ObjPtr foldPtr = new ObjPtr<>();
    @@ -614,6 +1035,14 @@ private ParsedCharClass parseCharClass(ObjPtr ascNode,
                     break;
     
                 case EOT:
    +                // Perl distinguishes an unfinished range after a non-ASCII
    +                // class value (for example /[\xdf-/i) from a bare unmatched
    +                // opening bracket. Preserve the ordinary EOT diagnostic for
    +                // ASCII ranges such as /[a-/.
    +                if (arg.state == CCSTATE.RANGE && arg.to >= 0x80
    +                        && env.usesPerlDiagnostics()) {
    +                    newSyntaxException(PERL_INVALID_RANGE_IN_CHAR_CLASS);
    +                }
                     newSyntaxException(PREMATURE_END_OF_CHAR_CLASS);
     
                 default:
    @@ -627,6 +1056,8 @@ private ParsedCharClass parseCharClass(ObjPtr ascNode,
             if (arg.state == CCSTATE.VALUE) {
                 arg.to = 0;
                 arg.toIsRaw = false;
    +            arg.toEscaped = false;
    +            arg.toNamedCharacter = false;
                 cc.nextStateValue(arg, ascCc, foldCc, env);
             }
     
    @@ -704,6 +1135,8 @@ private void parseCharClassRangeEndVal(CClassNode cc, CClassNode ascCc,
                                                CClassNode foldCc, CCStateArg arg) {
             arg.to = '-';
             arg.toIsRaw = false;
    +        arg.toEscaped = false;
    +        arg.toNamedCharacter = false;
             parseCharClassValEntry(cc, ascCc, foldCc, arg); // goto val_entry
         }
     
    @@ -721,11 +1154,141 @@ private void parseCharClassValEntry(CClassNode cc, CClassNode ascCc,
     
         private void parseCharClassValEntry2(CClassNode cc, CClassNode ascCc,
                                              CClassNode foldCc, CCStateArg arg) {
    +        if (arg.state == CCSTATE.RANGE && arg.from > arg.to
    +                && env.usesPerlDiagnostics() && !syntax.allowEmptyRangeInCC()) {
    +            int sourceStart = getBegin() + arg.fromStart;
    +            int sourceEnd = getBegin() + arg.toEnd;
    +            String range = new String(bytes, sourceStart, sourceEnd - sourceStart,
    +                    enc.getCharset());
    +            String message = env.emptyRangeError();
    +            newSyntaxException(message, arg.toEnd,
    +                    message + " \"" + range + "\"");
    +        }
    +        warnPerlExtendedClassRange(arg);
             cc.nextStateValue(arg, ascCc, foldCc, env);
         }
     
    +    private void warnFalseRangeBeforeClass(CCStateArg arg, int endpointEnd) {
    +        if (arg.state != CCSTATE.RANGE || !env.usesPerlDiagnostics()) return;
    +        warnFalseRange(arg.fromStart, endpointEnd, endpointEnd);
    +    }
    +
    +    private void warnFalseRangeAfterClass(CCStateArg arg) {
    +        warnFalseRange(arg.fromStart, arg.toEnd, arg.toEnd);
    +    }
    +
    +    private void warnFalseRange(int sourceStart, int sourceEnd, int warningPosition) {
    +        if (sourceStart < 0 || sourceEnd < sourceStart
    +                || getBegin() + sourceEnd > stop) return;
    +        String range = new String(bytes, getBegin() + sourceStart,
    +                sourceEnd - sourceStart, enc.getCharset());
    +        String message = "False [] range \"" + range + "\"";
    +        if (perlExtendedClassLeaf) {
    +            newSyntaxException("False [] range", warningPosition, message);
    +        }
    +        env.warnings.warn(message, warningPosition);
    +    }
    +
    +    private void warnPerlExtendedClassRange(CCStateArg arg) {
    +        boolean strictOrdinaryClass = !perlExtendedClassLeaf
    +                && Option.isPerlReStrict(env.option);
    +        if (!perlExtendedClassLeaf && !strictOrdinaryClass
    +                || arg.state != CCSTATE.RANGE
    +                || !env.usesPerlDiagnostics() || arg.from > arg.to) {
    +            return;
    +        }
    +
    +        if (arg.fromEscaped && arg.toEscaped
    +                && arg.fromNamedCharacter != arg.toNamedCharacter) {
    +            long unnamedEndpoint = arg.fromNamedCharacter ? arg.to : arg.from;
    +            int unnamedStart = arg.fromNamedCharacter ? arg.toStart : arg.fromStart;
    +            int unnamedEnd = arg.fromNamedCharacter ? arg.toEnd : arg.fromEnd;
    +            if (isPerlByteRangeEndpoint(unnamedStart, unnamedEnd, unnamedEndpoint)) {
    +                env.warnings.warn("Both or neither range ends should be Unicode",
    +                        perlExtendedRangeWarningPosition());
    +            }
    +            return;
    +        }
    +
    +        int from = (int)arg.from;
    +        int to = (int)arg.to;
    +        if (from == to && !rangeEndpointSource(arg.fromStart, arg.fromEnd)
    +                .equals(rangeEndpointSource(arg.toStart, arg.toEnd))) {
    +            int warningPosition = perlExtendedRangeWarningPosition();
    +            String source = rangeEndpointSource(arg.fromStart, warningPosition);
    +            env.warnings.warn("\"" + source
    +                    + "\" is more clearly written simply as \""
    +                    + perlRangeLiteral(from) + "\"", warningPosition);
    +            return;
    +        }
    +        if (isAsciiPrintable(from) || isAsciiPrintable(to)) {
    +            if (from != to && (arg.fromEscaped || arg.toEscaped
    +                    || !isSameAsciiRangeGroup(from, to))) {
    +                env.warnings.warn("Ranges of ASCII printables should be some subset of "
    +                        + "\"0-9\", \"A-Z\", or \"a-z\"",
    +                        perlExtendedRangeWarningPosition());
    +            }
    +            return;
    +        }
    +
    +        int fromDigit = Character.getNumericValue(from);
    +        int toDigit = Character.getNumericValue(to);
    +        if (fromDigit >= 0 && toDigit >= 0
    +                && fromDigit <= 9 && toDigit <= 9
    +                && from - fromDigit != to - toDigit) {
    +            env.warnings.warn("Ranges of digits should be from the same group of 10",
    +                    perlExtendedRangeWarningPosition());
    +        }
    +    }
    +
    +    private String rangeEndpointSource(int start, int end) {
    +        return new String(bytes, getBegin() + start, end - start, enc.getCharset());
    +    }
    +
    +    private boolean isPerlByteRangeEndpoint(int start, int end, long value) {
    +        if (value > 0xff) return false;
    +        String source = rangeEndpointSource(start, end);
    +        if (source.length() < 2 || source.charAt(0) != '\\') return false;
    +        char escape = source.charAt(1);
    +        return escape == 'x' || escape == 'o'
    +                || escape >= '0' && escape <= '7';
    +    }
    +
    +    private static String perlRangeLiteral(int codePoint) {
    +        return switch (codePoint) {
    +            case '\t' -> "\\t";
    +            case '\n' -> "\\n";
    +            case '\r' -> "\\r";
    +            case '\f' -> "\\f";
    +            default -> isAsciiPrintable(codePoint)
    +                    ? Character.toString(codePoint)
    +                    : String.format("\\x{%X}", codePoint);
    +        };
    +    }
    +
    +    private int perlExtendedRangeWarningPosition() {
    +        int cursor = p;
    +        while (cursor < stop) {
    +            int code = enc.mbcToCode(bytes, cursor, stop);
    +            if (code != ' ' && code != '\t') break;
    +            cursor += enc.length(bytes, cursor, stop);
    +        }
    +        return cursor - getBegin();
    +    }
    +
    +    private static boolean isAsciiPrintable(int codePoint) {
    +        return codePoint >= 0x20 && codePoint <= 0x7e;
    +    }
    +
    +    private static boolean isSameAsciiRangeGroup(int from, int to) {
    +        return from >= '0' && to <= '9'
    +                || from >= 'A' && to <= 'Z'
    +                || from >= 'a' && to <= 'z';
    +    }
    +
         private Node parseEnclose(TokenType term) {
             Node node = null;
    +        int conditionalBodyStart = -1;
     
             if (!left()) newSyntaxException(END_PATTERN_WITH_UNMATCHED_PARENTHESIS);
     
    @@ -738,7 +1301,11 @@ private Node parseEnclose(TokenType term) {
     
             if (peekIs('?') && syntax.op2QMarkGroupEffect()) {
                 inc();
    -            if (!left()) newSyntaxException(END_PATTERN_IN_GROUP);
    +            if (!left()) {
    +                newSyntaxException(syntax.op2OptionPerl()
    +                        ? PERL_GROUP_EFFECT_INCOMPLETE
    +                        : END_PATTERN_IN_GROUP);
    +            }
     
                 boolean listCapture = false;
     
    @@ -754,6 +1321,28 @@ && left() && enc.isDigit(peek())) {
                     return parsePerlRelativeCall(c);
                 }
                 switch(c) {
    +            case ')':
    +                if (syntax.op2OptionPerl()) {
    +                    returnCode = 0;
    +                    return StringNode.EMPTY;
    +                }
    +                newSyntaxException(UNDEFINED_GROUP_OPTION);
    +                break;
    +            case 'R':
    +                if (syntax.op2OptionPerl()) {
    +                    if (!left() || !peekIs(')')) {
    +                        newSyntaxException(UNDEFINED_GROUP_OPTION);
    +                    }
    +                    inc();
    +                    // group 0 with an empty name span denotes a numbered
    +                    // whole-pattern call to the analyser, not a named call.
    +                    CallNode call = new CallNode(bytes, p, p, 0);
    +                    env.numCall++;
    +                    returnCode = 0;
    +                    return call;
    +                }
    +                newSyntaxException(UNDEFINED_GROUP_OPTION);
    +                break;
                 case '{':
                     return parseInternalCallout();
                 case ':':  /* (?:...) grouping only */
    @@ -783,6 +1372,9 @@ && left() && enc.isDigit(peek())) {
                 case '\'':
                     if (Config.USE_NAMED_GROUP) {
                         if (syntax.op2QMarkLtNamedGroup()) {
    +                        if (!left()) {
    +                            newSyntaxException(PERL_QUOTE_NAMED_CAPTURE_NOT_TERMINATED);
    +                        }
                             listCapture = false; // goto named_group1
                             node = parseEncloseNamedGroup2(listCapture);
                             break;
    @@ -792,7 +1384,11 @@ && left() && enc.isDigit(peek())) {
                     } // USE_NAMED_GROUP
                     break;
                 case '<':  /* look behind (?<=...), (?'
    +                                    && !hasCodePointAhead('>')) {
    +                                newSyntaxException(PERL_PYTHON_NAMED_CAPTURE_NOT_TERMINATED,
    +                                        nextClosingParenthesisPosition());
    +                            }
                                 unfetch();
                                 c = '<';
     
    @@ -834,10 +1435,14 @@ && left() && enc.isDigit(peek())) {
                         en.regNum = num;
                         node = en;
                     } else {
    -                    newSyntaxException(UNDEFINED_GROUP_OPTION);
    +                    newSyntaxException(PERL_AT_MARK_GROUP_NOT_IMPLEMENTED);
                     }
                     break;
     
    +            case ';':
    +                newSyntaxException(PERL_SEMICOLON_GROUP_NOT_RECOGNIZED);
    +                break;
    +
                 case 'P':  /* Perl's Python-style (?P...) and (?P=name) */
                     if (!syntax.op2OptionPerl() || !left()) {
                         newSyntaxException(UNDEFINED_GROUP_OPTION);
    @@ -848,7 +1453,7 @@ && left() && enc.isDigit(peek())) {
                             newSyntaxException(PERL_PYTHON_NAMED_CAPTURE_NOT_TERMINATED);
                         }
                         int first = enc.mbcToCode(bytes, p, stop);
    -                    if (enc.isDigit(first) || !enc.isWord(first)) {
    +                    if (!isPerlGroupNameStart(first)) {
                             newValueException(PERL_GROUP_NAME_MUST_START_WITH_WORD);
                         }
                         if (!hasCodePointAhead('>')) {
    @@ -863,7 +1468,7 @@ && left() && enc.isDigit(peek())) {
                             newSyntaxException(PERL_PYTHON_NAMED_BACKREF_NOT_TERMINATED);
                         }
                         int first = enc.mbcToCode(bytes, p, stop);
    -                    if (enc.isDigit(first) || !enc.isWord(first)) {
    +                    if (!isPerlGroupNameStart(first)) {
                             newValueException(PERL_GROUP_NAME_MUST_START_WITH_WORD);
                         }
                         if (!hasCodePointAhead(')')) {
    @@ -892,6 +1497,7 @@ && left() && enc.isDigit(peek())) {
                     if (left() && syntax.op2QMarkLParenCondition()) {
                         int num = -1;
                         int name = -1;
    +                    int physicalNamedCondition = -1;
                         int calloutConditionId = -1;
                         AnchorNode assertionCondition = null;
                         int recursionConditionGroup = -1;
    @@ -903,7 +1509,18 @@ && left() && enc.isDigit(peek())) {
                             node = new EncloseNode(EncloseType.DEFINE);
                             break;
                         } else if (c == '?' && left() && peekIs('{')) {
    +                        int unknownConditionPosition = p - getBegin();
                             fetch();
    +                        // RuntimeRegexTemplate lowers (??{...}) into a trusted
    +                        // internal DYNAMIC callout.  It is valid as a pattern
    +                        // atom, but Perl does not permit it as a conditional
    +                        // operand; retain the source-level diagnostic instead
    +                        // of falling through to the generic group-option error.
    +                        if (startsWith("=DYNAMIC:")) {
    +                            parseInternalCalloutId("=DYNAMIC:");
    +                            newSyntaxException(PERL_UNKNOWN_SWITCH_CONDITION,
    +                                    unknownConditionPosition);
    +                        }
                             calloutConditionId = parseInternalCalloutId();
                         } else if (c == '?' && left() && (peekIs('=') || peekIs('!'))) {
                             fetch();
    @@ -944,24 +1561,59 @@ && left() && enc.isDigit(peek())) {
                             }
                         } else if (enc.isDigit(c)) { /* (n) */
                             unfetch();
    -                        num = fetchName('(', true);
    -                        if (syntax.strictCheckBackref()) {
    +                        if (syntax.op2OptionPerl()) {
    +                            int conditionEnd = p;
    +                            while (conditionEnd < stop
    +                                    && enc.isDigit(enc.mbcToCode(bytes, conditionEnd, stop))) {
    +                                conditionEnd += enc.length(bytes, conditionEnd, stop);
    +                            }
    +                            if (conditionEnd >= stop
    +                                    || enc.mbcToCode(bytes, conditionEnd, stop) != ')') {
    +                                newSyntaxException(PERL_SWITCH_CONDITION_NOT_RECOGNIZED,
    +                                        conditionEnd < stop
    +                                                ? conditionEnd + enc.length(
    +                                                        bytes, conditionEnd, stop) - getBegin()
    +                                                : conditionEnd - getBegin());
    +                            }
    +                        }
    +                        try {
    +                            num = fetchName('(', true);
    +                        } catch (SyntaxException e) {
    +                            if (syntax.op2OptionPerl()) {
    +                                newSyntaxException(PERL_SWITCH_CONDITION_NOT_RECOGNIZED);
    +                            }
    +                            throw e;
    +                        }
    +                        if (syntax.strictCheckBackref() && !syntax.op2OptionPerl()) {
                                 if (num > env.numMem || env.memNodes == null || env.memNodes[num] == null) newValueException(INVALID_BACKREF);
                             }
                         } else {
                             if (Config.USE_NAMED_GROUP) {
                                 if (c == '<' || c == '\'') {    /* (), ('name') */
    +                                if (!left()) {
    +                                    newSyntaxException(c == '<'
    +                                            ? PERL_ANGLE_NAMED_CONDITION_NOT_TERMINATED
    +                                            : PERL_QUOTE_NAMED_CONDITION_NOT_TERMINATED);
    +                                }
                                     name = p;
                                     fetchNamedBackrefToken();
                                     inc();
                                     num = token.getBackrefNum() > 1 ? token.getBackrefRefs()[0] : token.getBackrefRef1();
    +                                NameEntry named = regex.nameToGroupNumbers(bytes, name, value);
    +                                if (named != null && named.backNum == 1) {
    +                                    physicalNamedCondition = named.getPhysicalBackRefs()[0];
    +                                }
    +                            } else {
    +                                newSyntaxException(PERL_UNKNOWN_SWITCH_CONDITION);
                                 }
                             } else { // USE_NAMED_GROUP
    -                            newSyntaxException(INVALID_CONDITION_PATTERN);
    +                            newSyntaxException(PERL_UNKNOWN_SWITCH_CONDITION);
                             }
                         }
    +                    conditionalBodyStart = p;
                         EncloseNode en = new EncloseNode(EncloseType.CONDITION);
                         en.regNum = num;
    +                    en.physicalNamedCondition = physicalNamedCondition;
                         en.calloutConditionId = calloutConditionId;
                         en.assertionCondition = assertionCondition;
                         en.recursionConditionGroup = recursionConditionGroup;
    @@ -970,6 +1622,9 @@ && left() && enc.isDigit(peek())) {
                         if (name != -1) en.setNameRef();
                         node = en;
                     } else {
    +                    if (syntax.op2OptionPerl()) {
    +                        newSyntaxException(PERL_UNKNOWN_SWITCH_CONDITION);
    +                    }
                         newSyntaxException(UNDEFINED_GROUP_OPTION);
                     }
                     break;
    @@ -996,6 +1651,7 @@ && left() && enc.isDigit(peek())) {
                         option = bsOnOff(option, Option.DONT_CAPTURE_GROUP, true);
                         option = bsOnOff(option, Option.CAPTURE_GROUP, false);
                         option = bsOnOff(option, Option.PERL_ASCII_STRICT, true);
    +                    option = bsOnOff(option, Option.PERL_EXPLICIT_ASCII, true);
                         fetch();
                         if (c == '-') {
                             newSyntaxException(PERL_CARET_MINUS_OPTION_NOT_RECOGNIZED);
    @@ -1084,7 +1740,8 @@ && left() && enc.isDigit(peek())) {
                             if (!syntax.op2OptionPerl()) {
                                 newSyntaxException(UNDEFINED_GROUP_OPTION);
                             }
    -                        env.warnings.warn("Useless (?" + (neg ? "-" : "") + "c)");
    +                        env.warnings.warn("Useless (?" + (neg ? "-" : "") + "c)",
    +                                p - getBegin());
                             sawContinueModifier = true;
                             break;
     
    @@ -1095,7 +1752,7 @@ && left() && enc.isDigit(peek())) {
                             }
                             if (c != 'g' || !sawContinueModifier) {
                                 env.warnings.warn("Useless (?" + (neg ? "-" : "")
    -                                    + (char)c + ")");
    +                                    + (char)c + ")", p - getBegin());
                             }
                             break;
     
    @@ -1117,6 +1774,9 @@ && left() && enc.isDigit(peek())) {
                             break;
     
                         case 'l':
    +                        if (neg && syntax.op2OptionPerl()) {
    +                            newSyntaxException(PERL_LOCALE_MODIFIER_AFTER_MINUS);
    +                        }
                             option = charsetOptions.apply(option, c, neg, false);
                             break;
                         default:
    @@ -1145,11 +1805,19 @@ && left() && enc.isDigit(peek())) {
                             returnCode = 0;
                             return node;
                         }
    -                    if (!left()) newSyntaxException(END_PATTERN_IN_GROUP);
    +                    if (!left()) {
    +                        newSyntaxException(syntax.op2OptionPerl()
    +                                ? PERL_OPTION_GROUP_NOT_TERMINATED
    +                                : END_PATTERN_IN_GROUP);
    +                    }
                         fetch();
                     } // while
     
                 default:
    +                if (syntax.op2OptionPerl() && c > 0x7f) {
    +                    newValueException(PERL_GROUP_SEQUENCE_NOT_RECOGNIZED,
    +                            new String(Character.toChars(c)));
    +                }
                     newSyntaxException(UNDEFINED_GROUP_OPTION);
                 } // switch
     
    @@ -1170,7 +1838,27 @@ && left() && enc.isDigit(peek())) {
             }
     
             fetchToken();
    -        Node target = parseSubExp(term);
    +        Node target;
    +        try {
    +            target = parseSubExp(term);
    +        } catch (SyntaxException e) {
    +            if (node instanceof EncloseNode en && en.type == EncloseType.CONDITION
    +                    && END_PATTERN_WITH_UNMATCHED_PARENTHESIS.equals(e.getMessage())) {
    +                newSyntaxException(PERL_SWITCH_CONDITION_NOT_TERMINATED);
    +            }
    +            if (node instanceof AnchorNode anchor
    +                    && END_PATTERN_WITH_UNMATCHED_PARENTHESIS.equals(e.getMessage())) {
    +                String diagnostic = switch (anchor.type) {
    +                case AnchorType.LOOK_BEHIND -> PERL_POSITIVE_LOOKBEHIND_NOT_TERMINATED;
    +                case AnchorType.LOOK_BEHIND_NOT -> PERL_NEGATIVE_LOOKBEHIND_NOT_TERMINATED;
    +                case AnchorType.PREC_READ -> PERL_POSITIVE_LOOKAHEAD_NOT_TERMINATED;
    +                case AnchorType.PREC_READ_NOT -> PERL_NEGATIVE_LOOKAHEAD_NOT_TERMINATED;
    +                default -> null;
    +                };
    +                if (diagnostic != null) newSyntaxException(diagnostic);
    +            }
    +            throw e;
    +        }
     
             if (node.getType() == NodeType.ANCHOR) {
                 AnchorNode an = (AnchorNode)node;
    @@ -1183,6 +1871,17 @@ && left() && enc.isDigit(peek())) {
                 if (en.type == EncloseType.DEFINE && target.getType() == NodeType.ALT) {
                     newSyntaxException(PERL_DEFINE_DOES_NOT_ALLOW_BRANCHES);
                 }
    +            if (en.type == EncloseType.CONDITION && target instanceof ListNode
    +                    && target.getType() == NodeType.ALT
    +                    && ((ListNode)target).tail != null
    +                    && ((ListNode)target).tail.tail != null) {
    +                if (syntax.op2OptionPerl()) {
    +                    newSyntaxException(PERL_SWITCH_CONDITION_TOO_MANY_BRANCHES,
    +                            perlConditionalThirdBranchPosition(
    +                                    conditionalBodyStart, p));
    +                }
    +                newSyntaxException(INVALID_CONDITION_PATTERN);
    +            }
                 en.setTarget(target);
                 if (en.type == EncloseType.MEMORY) {
                     if (syntax.op3OptionECMAScript()) {
    @@ -1210,6 +1909,44 @@ private Node parseControlVerb() {
             Node alphaAssertion = parseAlphaAssertion();
             if (alphaAssertion != null) return alphaAssertion;
     
    +        String missingScriptRunColon = missingControlArgumentDelimiter("script_run");
    +        if (missingScriptRunColon != null) {
    +            newSyntaxException(PERL_ALPHA_ASSERTION_REQUIRES_COLON.replace("%n", missingScriptRunColon),
    +                    p + missingScriptRunColon.length() - getBegin());
    +        }
    +        String missingShortScriptRunColon = missingControlArgumentDelimiter("sr");
    +        if (missingShortScriptRunColon != null) {
    +            newSyntaxException(PERL_ALPHA_ASSERTION_REQUIRES_COLON.replace("%n", missingShortScriptRunColon),
    +                    p + missingShortScriptRunColon.length() - getBegin());
    +        }
    +
    +        // Script-run groups are scoped, non-capturing constructs.  Parse their
    +        // body with the same delimiter discipline as the other Perl (*name:)
    +        // groups; native validation is added by the matcher path.
    +        boolean scriptRun = startsWith("script_run:") || startsWith("sr:");
    +        boolean atomicScriptRun = startsWith("atomic_script_run:") || startsWith("asr:");
    +        if (scriptRun || atomicScriptRun) {
    +            if (startsWith("script_run:")) p += "script_run:".length();
    +            else if (startsWith("atomic_script_run:")) p += "atomic_script_run:".length();
    +            else p += scriptRun ? "sr:".length() : "asr:".length();
    +            fetchToken();
    +            try {
    +                Node target = parseSubExp(TokenType.SUBEXP_CLOSE);
    +                // Keep a recognised enclosure type so this scoped feature can
    +                // own native bytecode without extending the shared analyser.
    +                EncloseNode scope = new EncloseNode(EncloseType.STOP_BACKTRACK);
    +                scope.scriptRun = true;
    +                scope.atomicScriptRun = atomicScriptRun;
    +                scope.setTarget(target);
    +                return scope;
    +            } catch (SyntaxException e) {
    +                if (END_PATTERN_WITH_UNMATCHED_PARENTHESIS.equals(e.getMessage())) {
    +                    newSyntaxException(PERL_UNTERMINATED_CONTROL_ARGUMENT);
    +                }
    +                throw e;
    +            }
    +        }
    +
             final ControlVerbNode.Kind kind;
             final String verb;
             if (startsWith("ACCEPT)") || startsWith("ACCEPT:")) {
    @@ -1236,12 +1973,25 @@ private Node parseControlVerb() {
             } else if (startsWith("MARK)") || startsWith("MARK:")) {
                 kind = ControlVerbNode.Kind.MARK;
                 verb = "MARK";
    +        } else if (startsWith(":")) {
    +            kind = ControlVerbNode.Kind.MARK;
    +            verb = "";
             } else {
                 String construct = controlConstructName();
    -            if (!construct.isEmpty() && Character.isUpperCase(construct.codePointAt(0))) {
    +            int constructEnd = p + construct.getBytes(StandardCharsets.UTF_8).length;
    +            int diagnosticEnd = constructEnd;
    +            if (constructEnd < stop && enc.mbcToCode(bytes, constructEnd, stop) == ')') {
    +                diagnosticEnd += enc.length(bytes, constructEnd, stop);
    +            }
    +            if (construct.isEmpty()) {
                     newValueException(PERL_UNKNOWN_VERB_PATTERN, construct);
                 }
    -            newValueException(PERL_UNKNOWN_CONTROL_CONSTRUCT, construct);
    +            if (Character.isUpperCase(construct.codePointAt(0))) {
    +                newSyntaxException(PERL_UNKNOWN_VERB_PATTERN.replace("%n", construct),
    +                        diagnosticEnd - getBegin());
    +            }
    +            newSyntaxException(PERL_UNKNOWN_CONTROL_CONSTRUCT.replace("%n", construct),
    +                    diagnosticEnd - getBegin());
                 return null;
             }
             p += verb.length();
    @@ -1277,7 +2027,8 @@ private Node parseAlphaAssertion() {
                 return null;
             }
             if (cursor >= stop || enc.mbcToCode(bytes, cursor, stop) != ':') {
    -            newValueException(PERL_ALPHA_ASSERTION_REQUIRES_COLON, name);
    +            newSyntaxException(PERL_ALPHA_ASSERTION_REQUIRES_COLON.replace("%n", name),
    +                    cursor - getBegin());
             }
             p = cursor + enc.length(bytes, cursor, stop);
     
    @@ -1330,6 +2081,16 @@ private String controlConstructName() {
             return new String(bytes, start, cursor - start, StandardCharsets.UTF_8);
         }
     
    +    private String missingControlArgumentDelimiter(String name) {
    +        if (!startsWith(name)) return null;
    +        int afterName = p + name.length();
    +        if (afterName >= stop) {
    +            newSyntaxException(PERL_UNTERMINATED_CONTROL_CONSTRUCT,
    +                    afterName - getBegin());
    +        }
    +        return enc.mbcToCode(bytes, afterName, stop) == ')' ? name : null;
    +    }
    +
         private int parseInternalCalloutId() {
             return parseInternalCalloutId("=CALL:");
         }
    @@ -1376,8 +2137,9 @@ private boolean startsWith(String value) {
         private Node parseEncloseNamedGroup2(boolean listCapture) {
             if (syntax.op2OptionPerl() && left()) {
                 int first = enc.mbcToCode(bytes, p, stop);
    -            if (enc.isDigit(first) || !enc.isWord(first)) {
    -                newValueException(PERL_GROUP_NAME_MUST_START_WITH_WORD);
    +            if (!isPerlGroupNameStart(first)) {
    +                newSyntaxException(PERL_GROUP_NAME_MUST_START_WITH_WORD,
    +                        p + enc.length(bytes, p, stop) - getBegin());
                 }
             }
             int nm = p;
    @@ -1405,6 +2167,16 @@ private boolean hasCodePointAhead(int target) {
             return false;
         }
     
    +    private int nextClosingParenthesisPosition() {
    +        int cursor = p;
    +        while (cursor < stop) {
    +            int code = enc.mbcToCode(bytes, cursor, stop);
    +            if (code == ')') return cursor - getBegin();
    +            cursor += enc.length(bytes, cursor, stop);
    +        }
    +        return stop - getBegin();
    +    }
    +
         private int findStrPosition(int[]s, int n, int from, int to, Ptr nextChar) {
             int x;
             int q;
    @@ -1431,6 +2203,7 @@ private int findStrPosition(int[]s, int n, int from, int to, Ptr nextChar) {
     
         private Node parseExp(TokenType term) {
             if (token.type == term) return StringNode.EMPTY; // goto end_of_token
    +        int expressionStart = token.backP - (token.escaped ? 1 : 0);
             Node node = null;
             boolean group = false;
     
    @@ -1574,40 +2347,79 @@ private Node parseExp(TokenType term) {
     
             fetchToken(); // re_entry:
     
    -        return parseExpRepeat(node, group); // repeat:
    +        return parseExpRepeat(node, group, expressionStart); // repeat:
         }
     
         private CClassNode parsePerlExtendedCharClass() {
    -        skipPerlExtendedClassSpace();
    -        if (!left() || extendedClassAt(']')) {
    -            newSyntaxException(PERL_EXTENDED_CLASS_INCOMPLETE);
    -        }
    -        CClassNode result = parsePerlExtendedClassUnion();
    -        skipPerlExtendedClassSpace();
    -        if (!left() || !extendedClassAt(']')) {
    -            newSyntaxException(PERL_EXTENDED_CLASS_INCOMPLETE);
    -        }
    -        inc();
    -        if (!left() || !extendedClassAt(')')) {
    -            if (left() && extendedClassAt(']')) {
    +        boolean previousExtendedClass = env.inPerlExtendedClass;
    +        env.inPerlExtendedClass = true;
    +        try {
    +            int bodyStart = p;
    +            skipPerlExtendedClassSpace();
    +            if (!left() || extendedClassAt(']')) {
    +                newSyntaxException(PERL_EXTENDED_CLASS_INCOMPLETE);
    +            }
    +            CClassNode result;
    +            try {
    +                result = parsePerlExtendedClassUnion();
    +            } catch (SyntaxException error) {
    +                if (extendedClassBodyStartsWithControlCloseGroup(bodyStart)
    +                        && PERL_EXTENDED_CLASS_UNEXPECTED_CHARACTER.equals(
    +                                error.getMessage())) {
    +                    newSyntaxException(PERL_EXTENDED_CLASS_SYNTAX,
    +                            stop - getBegin());
    +                }
    +                throw error;
    +            }
    +            skipPerlExtendedClassSpace();
    +            if (!left() || !extendedClassAt(']')) {
    +                if (extendedClassBodyStartsWithControlCloseGroup(bodyStart)
    +                        || extendedClassBodyStartsWithSpacedStandardClass(bodyStart)
    +                        || extendedClassBodyStartsWithPosixLeaf(bodyStart)) {
    +                    newSyntaxException(PERL_EXTENDED_CLASS_SYNTAX,
    +                            stop - getBegin());
    +                }
    +                newSyntaxException(PERL_EXTENDED_CLASS_INCOMPLETE);
    +            }
    +            inc();
    +            if (!left() || !extendedClassAt(')')) {
    +                if (extendedClassBodyStartsWithSpacedStandardClass(bodyStart)) {
    +                    newSyntaxException(PERL_EXTENDED_CLASS_SYNTAX);
    +                }
                     newSyntaxException(PERL_EXTENDED_CLASS_UNEXPECTED_OUTER_CLOSE);
                 }
    -            newSyntaxException(PERL_EXTENDED_CLASS_SYNTAX);
    +            inc();
    +            return result;
    +        } finally {
    +            env.inPerlExtendedClass = previousExtendedClass;
             }
    -        inc();
    -        return result;
         }
     
         private CClassNode parsePerlExtendedClassUnion() {
    -        CClassNode left = parsePerlExtendedClassIntersection();
    +        CClassNode left = parsePerlExtendedClassIntersection(false);
             while (true) {
                 skipPerlExtendedClassSpace();
                 if (!left()) return left;
                 int operator = extendedClassCode();
                 if (operator != '+' && operator != '|' && operator != '-'
    -                    && operator != '^') return left;
    +                    && operator != '^') {
    +                if (operator == ']' || operator == ')') return left;
    +                if (operator == '(') {
    +                    inc();
    +                    newSyntaxException(PERL_EXTENDED_CLASS_UNEXPECTED_OPEN_PAREN);
    +                }
    +                if (extendedClassStarts("\\]")) {
    +                    p += 2;
    +                    newSyntaxException(PERL_EXTENDED_CLASS_UNEXPECTED_OUTER_CLOSE,
    +                            p - getBegin());
    +                }
    +                int operandStart = p;
    +                parsePerlExtendedClassIntersection(false);
    +                newSyntaxException(PERL_EXTENDED_CLASS_OPERAND_WITHOUT_OPERATOR,
    +                        perlExtendedUnexpectedOperandPosition(operandStart, p));
    +            }
                 inc();
    -            CClassNode right = parsePerlExtendedClassIntersection();
    +            CClassNode right = parsePerlExtendedClassIntersection(true);
                 switch (operator) {
                 case '+':
                 case '|':
    @@ -1633,38 +2445,62 @@ private CClassNode parsePerlExtendedClassUnion() {
             }
         }
     
    -    private CClassNode parsePerlExtendedClassIntersection() {
    -        CClassNode left = parsePerlExtendedClassUnary();
    +    private CClassNode parsePerlExtendedClassIntersection(boolean afterOperator) {
    +        CClassNode left = parsePerlExtendedClassUnary(afterOperator);
             while (true) {
                 skipPerlExtendedClassSpace();
                 if (!left() || !extendedClassAt('&')) return left;
                 inc();
    -            left.and(parsePerlExtendedClassUnary(), env);
    +            left.and(parsePerlExtendedClassUnary(true), env);
             }
         }
     
    -    private CClassNode parsePerlExtendedClassUnary() {
    +    private CClassNode parsePerlExtendedClassUnary(boolean afterOperator) {
             skipPerlExtendedClassSpace();
             if (!left()) newSyntaxException(PERL_EXTENDED_CLASS_INCOMPLETE);
             if (extendedClassAt('!')) {
                 inc();
    -            CClassNode result = parsePerlExtendedClassUnary();
    +            CClassNode result = parsePerlExtendedClassUnary(true);
                 if (result.isNot()) result.clearNot();
                 else result.setNot();
                 return result;
             }
    -        PerlExtendedClassPrimary primary = parsePerlExtendedClassPrimary();
    +        PerlExtendedClassPrimary primary = parsePerlExtendedClassPrimary(afterOperator);
             CClassNode result = primary.node();
             if (!primary.scopedOptionsApplied() && isIgnoreCase(env.option)) {
    -            cClassCaseFold(result, result, result, result);
    +            caseFoldPerlExtendedClass(primary);
             }
             return result;
         }
     
    -    private PerlExtendedClassPrimary parsePerlExtendedClassPrimary() {
    +    private void caseFoldPerlExtendedClass(PerlExtendedClassPrimary primary) {
    +        int previousOption = env.option;
    +        env.option &= ~Option.PERL_BYTE_PATTERN;
    +        try {
    +            cClassCaseFold(primary.node(), primary.node(),
    +                    primary.asciiFoldSource(), primary.foldSource());
    +        } finally {
    +            env.option = previousOption;
    +        }
    +    }
    +
    +    private PerlExtendedClassPrimary parsePerlExtendedClassPrimary(boolean afterOperator) {
             skipPerlExtendedClassSpace();
             if (!left()) newSyntaxException(PERL_EXTENDED_CLASS_INCOMPLETE);
     
    +        int codePoint = extendedClassCode();
    +        if (codePoint == '+' || codePoint == '|' || codePoint == '-'
    +                || codePoint == '^' || codePoint == '&') {
    +            inc();
    +            newSyntaxException(String.format(
    +                    PERL_EXTENDED_CLASS_BINARY_OPERATOR_WITHOUT_OPERAND,
    +                    (char) codePoint));
    +        }
    +        if (codePoint == ')') {
    +            inc();
    +            newSyntaxException(PERL_EXTENDED_CLASS_UNEXPECTED_CLOSE_PAREN);
    +        }
    +
             if (extendedClassStarts("(?[")) {
                 p += 3;
                 return new PerlExtendedClassPrimary(parsePerlExtendedCharClass(), true);
    @@ -1673,7 +2509,9 @@ private PerlExtendedClassPrimary parsePerlExtendedClassPrimary() {
                 p += 2;
                 int previousOption = env.option;
                 int nestedOption = previousOption;
    +            boolean caretOptions = false;
                 if (left() && extendedClassAt('^')) {
    +                caretOptions = true;
                     nestedOption = bsOnOff(nestedOption, Option.ASCII_RANGE, true);
                     nestedOption = bsOnOff(nestedOption, Option.IGNORECASE, true);
                     nestedOption = bsOnOff(nestedOption, Option.SINGLELINE, false);
    @@ -1683,6 +2521,8 @@ private PerlExtendedClassPrimary parsePerlExtendedClassPrimary() {
                     nestedOption = bsOnOff(nestedOption, Option.DONT_CAPTURE_GROUP, true);
                     nestedOption = bsOnOff(nestedOption, Option.CAPTURE_GROUP, false);
                     nestedOption = bsOnOff(nestedOption, Option.PERL_ASCII_STRICT, true);
    +                nestedOption = bsOnOff(
    +                        nestedOption, Option.PERL_EXPLICIT_ASCII, true);
                     inc();
                 }
                 boolean negateOption = false;
    @@ -1694,7 +2534,14 @@ private PerlExtendedClassPrimary parsePerlExtendedClassPrimary() {
                             && option != 'l' && option != 'm' && option != 'n'
                             && option != 'p' && option != 's' && option != 'u'
                             && option != 'x' && option != '-') {
    -                    newSyntaxException(PERL_EXTENDED_CLASS_SYNTAX);
    +                    if (option == '(' && caretOptions) {
    +                        newSyntaxException(
    +                                PERL_CARET_GROUP_SEQUENCE_NOT_RECOGNIZED,
    +                                p + enc.length(bytes, p, stop) - getBegin());
    +                    }
    +                    newSyntaxException(option == '('
    +                            ? PERL_EXTENDED_CLASS_UNEXPECTED_CHARACTER
    +                            : PERL_EXTENDED_CLASS_SYNTAX);
                     }
                     if (option == '-') negateOption = true;
                     else if (option == 'i') {
    @@ -1723,11 +2570,10 @@ else if (option == 'i') {
                 CClassNode nested;
                 try {
                     skipPerlExtendedClassSpace();
    -                if (!extendedClassStarts("(?[")) {
    +                if (!extendedClassStarts("(?")) {
                         newSyntaxException(PERL_EXTENDED_CLASS_EXPECTING_INTERPOLATED);
                     }
    -                p += 3;
    -                nested = parsePerlExtendedCharClass();
    +                nested = parsePerlExtendedClassPrimary(false).node();
                     skipPerlExtendedClassSpace();
                     if (!left() || !extendedClassAt(')')) {
                         newSyntaxException(PERL_EXTENDED_CLASS_SYNTAX);
    @@ -1740,42 +2586,117 @@ else if (option == 'i') {
             }
             if (extendedClassAt('(')) {
                 inc();
    +            skipPerlExtendedClassSpace();
    +            if (left() && extendedClassAt(')')) {
    +                inc();
    +                newSyntaxException(PERL_EXTENDED_CLASS_INCOMPLETE);
    +            }
                 CClassNode nested = parsePerlExtendedClassUnion();
                 skipPerlExtendedClassSpace();
                 if (!left() || !extendedClassAt(')')) {
    -                newSyntaxException(PERL_EXTENDED_CLASS_SYNTAX);
    +                newSyntaxException(PERL_UNMATCHED_OPEN_PARENTHESIS,
    +                        p - getBegin());
                 }
                 inc();
                 return new PerlExtendedClassPrimary(nested, true);
             }
    +        if (extendedClassStarts("[:") && extendedPosixPrimaryUsesParser()) {
    +            // In (?[...]), a POSIX bracket is itself a primary: [:alpha:]
    +            // is not the nested standard-class spelling [[:alpha:]].
    +            p += 2;
    +            int literalNameStart = p;
    +            CClassNode result = new CClassNode();
    +            int literalNameEnd = p;
    +            while (literalNameEnd < stop
    +                    && enc.mbcToCode(bytes, literalNameEnd, stop) != ']') {
    +                literalNameEnd += enc.length(bytes, literalNameEnd, stop);
    +            }
    +            if (literalNameEnd >= stop) {
    +                newSyntaxException(PERL_EXTENDED_CLASS_SYNTAX);
    +            }
    +            int previous = enc.prevCharHead(bytes, literalNameStart,
    +                    literalNameEnd, stop);
    +            if (previous < literalNameStart
    +                    || enc.mbcToCode(bytes, previous, stop) != ':') {
    +                addPerlLiteralPosixText(result, null, null,
    +                        literalNameStart, literalNameEnd);
    +                p = literalNameEnd + enc.length(bytes, literalNameEnd, stop);
    +                return new PerlExtendedClassPrimary(result, false);
    +            }
    +            if (parsePosixBracket(result, null, null)) {
    +                literalNameEnd = p;
    +                while (literalNameEnd < stop
    +                        && enc.mbcToCode(bytes, literalNameEnd, stop) != ']') {
    +                    literalNameEnd += enc.length(bytes, literalNameEnd, stop);
    +                }
    +                if (literalNameEnd >= stop) {
    +                    newSyntaxException(PERL_EXTENDED_CLASS_SYNTAX);
    +                }
    +                addPerlLiteralPosixText(result, null, null,
    +                        literalNameStart, literalNameEnd);
    +                p = literalNameEnd + enc.length(bytes, literalNameEnd, stop);
    +            }
    +            return new PerlExtendedClassPrimary(result, false);
    +        }
             if (extendedClassAt('[')) {
                 inc();
                 ObjPtr ascPtr = new ObjPtr<>();
                 ObjPtr foldPtr = new ObjPtr<>();
                 boolean previousExtendedLeaf = perlExtendedClassLeaf;
    +            int previousOption = env.option;
                 perlExtendedClassLeaf = true;
    +            env.option |= Option.PERL_EXTEND_MORE;
                 ParsedCharClass parsed;
                 try {
                     parsed = parseCharClass(ascPtr, foldPtr);
                 } finally {
    +                env.option = previousOption;
                     perlExtendedClassLeaf = previousExtendedLeaf;
                 }
                 if (!parsed.namedSequences().isEmpty()) {
                     newSyntaxException(PERL_EXTENDED_CLASS_MULTI_NAMED_CHARACTER);
                 }
    -            return new PerlExtendedClassPrimary(parsed.standard(), false);
    +            return new PerlExtendedClassPrimary(parsed.standard(),
    +                    ascPtr.p, foldPtr.p, false);
             }
             if (extendedClassAt('\\')) {
                 return parsePerlExtendedClassEscape();
             }
    -        newSyntaxException(PERL_EXTENDED_CLASS_BARE_CHARACTER);
    +        if (afterOperator) newSyntaxException(PERL_EXTENDED_CLASS_INCOMPLETE);
    +        newSyntaxException(PERL_EXTENDED_CLASS_UNEXPECTED_CHARACTER,
    +                p + enc.length(bytes, p, stop) - getBegin());
             return null;
         }
     
         private PerlExtendedClassPrimary parsePerlExtendedClassEscape() {
             int escapeStart = p;
    +        int escapeCode = -1;
             if (escapeStart < stop && enc.mbcToCode(bytes, escapeStart, stop) == '\\') {
                 int cursor = escapeStart + enc.length(bytes, escapeStart, stop);
    +            if (cursor < stop) escapeCode = enc.mbcToCode(bytes, cursor, stop);
    +            if (cursor < stop && enc.mbcToCode(bytes, cursor, stop) == 'x') {
    +                cursor += enc.length(bytes, cursor, stop);
    +                if (cursor < stop && enc.mbcToCode(bytes, cursor, stop) == '{') {
    +                    int close = cursor + enc.length(bytes, cursor, stop);
    +                    if (close < stop && enc.mbcToCode(bytes, close, stop) == '}') {
    +                        close += enc.length(bytes, close, stop);
    +                        newSyntaxException(PERL_EMPTY_HEX_ESCAPE,
    +                                close - getBegin());
    +                    }
    +                } else {
    +                    int digitCount = 0;
    +                    while (cursor < stop && digitCount < 3
    +                            && enc.isXDigit(enc.mbcToCode(bytes, cursor, stop))) {
    +                        cursor += enc.length(bytes, cursor, stop);
    +                        digitCount++;
    +                    }
    +                    if (digitCount == 3) {
    +                        newSyntaxException(PERL_HEX_ESCAPE_MORE_THAN_TWO_DIGITS,
    +                                cursor - getBegin());
    +                    }
    +                }
    +            }
    +            cursor = escapeStart + enc.length(bytes, escapeStart, stop);
                 if (cursor < stop && enc.mbcToCode(bytes, cursor, stop) == '0') {
                     int digits = 0;
                     while (cursor < stop) {
    @@ -1785,7 +2706,14 @@ private PerlExtendedClassPrimary parsePerlExtendedClassEscape() {
                         cursor += enc.length(bytes, cursor, stop);
                     }
                     if (digits != 3) {
    -                    newSyntaxException(PERL_EXTENDED_CLASS_OCTAL_WIDTH);
    +                    while (cursor < stop) {
    +                        int next = enc.mbcToCode(bytes, cursor, stop);
    +                        if (next != ' ' && next != '\t' && next != '\n'
    +                                && next != '\r' && next != '\f') break;
    +                        cursor += enc.length(bytes, cursor, stop);
    +                    }
    +                    newSyntaxException(PERL_EXTENDED_CLASS_OCTAL_WIDTH,
    +                            cursor - getBegin());
                     }
                 }
             }
    @@ -1800,6 +2728,10 @@ private PerlExtendedClassPrimary parsePerlExtendedClassEscape() {
                 return new PerlExtendedClassPrimary(result, false);
             case RAW_BYTE:
             case STRING:
    +            if (token.escaped && Character.isLetterOrDigit(token.getC())) {
    +                newValueException(PERL_UNRECOGNIZED_ESCAPE_IN_CHAR_CLASS,
    +                        Character.toString(token.getC()));
    +            }
                 addPerlExtendedClassCode(result, token.getC());
                 return new PerlExtendedClassPrimary(result, false);
             case NAMED_STRING:
    @@ -1829,6 +2761,10 @@ private PerlExtendedClassPrimary parsePerlExtendedClassEscape() {
                 }
                 return new PerlExtendedClassPrimary(parsed.standard(), false);
             default:
    +            if (Character.isLetterOrDigit(escapeCode)) {
    +                newValueException(PERL_UNRECOGNIZED_ESCAPE_IN_CHAR_CLASS,
    +                        Character.toString(escapeCode));
    +            }
                 newSyntaxException(PERL_EXTENDED_CLASS_SYNTAX);
                 return null;
             }
    @@ -1843,14 +2779,82 @@ private void addPerlExtendedClassCode(CClassNode cc, int codePoint) {
             }
         }
     
    +    private int perlExtendedUnexpectedOperandPosition(int start, int end) {
    +        int cursor = end;
    +        while (cursor > start) {
    +            int previous = enc.prevCharHead(bytes, start, cursor, end);
    +            int codePoint = enc.mbcToCode(bytes, previous, end);
    +            if (codePoint != ' ' && codePoint != '\t' && codePoint != '\n'
    +                    && codePoint != '\r' && codePoint != '\f') break;
    +            cursor = previous;
    +        }
    +        int first = start;
    +        while (first < cursor) {
    +            int codePoint = enc.mbcToCode(bytes, first, cursor);
    +            if (codePoint != ' ' && codePoint != '\t' && codePoint != '\n'
    +                    && codePoint != '\r' && codePoint != '\f') break;
    +            first += enc.length(bytes, first, cursor);
    +        }
    +        if (first < cursor && enc.mbcToCode(bytes, first, cursor) == '[') {
    +            int previous = enc.prevCharHead(bytes, first, cursor, cursor);
    +            if (enc.mbcToCode(bytes, previous, cursor) == ']') cursor = previous;
    +        }
    +        return cursor - getBegin();
    +    }
    +
    +    private int perlConditionalThirdBranchPosition(int start, int end) {
    +        int depth = 0;
    +        boolean inClass = false;
    +        boolean escaped = false;
    +        int alternatives = 0;
    +        int cursor = Math.max(start, getBegin());
    +        while (cursor < end) {
    +            int codePoint = enc.mbcToCode(bytes, cursor, end);
    +            int next = cursor + enc.length(bytes, cursor, end);
    +            if (escaped) {
    +                escaped = false;
    +            } else if (codePoint == '\\') {
    +                escaped = true;
    +            } else if (inClass) {
    +                if (codePoint == ']') inClass = false;
    +            } else if (codePoint == '[') {
    +                inClass = true;
    +            } else if (codePoint == '(') {
    +                depth++;
    +            } else if (codePoint == ')' && depth > 0) {
    +                depth--;
    +            } else if (codePoint == '|' && depth == 0 && ++alternatives == 2) {
    +                return next - getBegin();
    +            }
    +            cursor = next;
    +        }
    +        return end - getBegin();
    +    }
    +
         private void skipPerlExtendedClassSpace() {
             while (left()) {
                 int codePoint = extendedClassCode();
    +            if (extendedClassStarts("(?#")) {
    +                p += 3;
    +                while (left() && !extendedClassAt(')')) {
    +                    p += enc.length(bytes, p, stop);
    +                }
    +                if (!left()) {
    +                    newSyntaxException(PERL_EXTENDED_CLASS_SYNTAX,
    +                            stop - getBegin());
    +                }
    +                p += enc.length(bytes, p, stop);
    +                continue;
    +            }
                 if (codePoint == '#') {
                     do {
                         int length = enc.length(bytes, p, stop);
                         p += length;
                     } while (left() && !enc.isNewLine(extendedClassCode()));
    +                if (!left()) {
    +                    newSyntaxException(PERL_EXTENDED_CLASS_SYNTAX,
    +                            stop - getBegin());
    +                }
                     continue;
                 }
                 if (!Character.isWhitespace(codePoint) && codePoint != 0x85) return;
    @@ -1858,6 +2862,61 @@ private void skipPerlExtendedClassSpace() {
             }
         }
     
    +    private boolean extendedClassBodyStartsWithSpacedStandardClass(int bodyStart) {
    +        int cursor = bodyStart;
    +        while (cursor < stop) {
    +            int codePoint = enc.mbcToCode(bytes, cursor, stop);
    +            if (codePoint != ' ' && codePoint != '\t' && codePoint != '\n'
    +                    && codePoint != '\r' && codePoint != '\f') {
    +                if (codePoint != '[') return false;
    +                cursor += enc.length(bytes, cursor, stop);
    +                if (cursor >= stop) return false;
    +                int firstLeafCodePoint = enc.mbcToCode(bytes, cursor, stop);
    +                return firstLeafCodePoint == ' ' || firstLeafCodePoint == '\t'
    +                        || firstLeafCodePoint == '\n' || firstLeafCodePoint == '\r'
    +                        || firstLeafCodePoint == '\f';
    +            }
    +            cursor += enc.length(bytes, cursor, stop);
    +        }
    +        return false;
    +    }
    +
    +    private boolean extendedClassBodyStartsWithPosixLeaf(int bodyStart) {
    +        int cursor = bodyStart;
    +        while (cursor < stop) {
    +            int codePoint = enc.mbcToCode(bytes, cursor, stop);
    +            if (codePoint != ' ' && codePoint != '\t' && codePoint != '\n'
    +                    && codePoint != '\r' && codePoint != '\f') {
    +                if (codePoint != '[') return false;
    +                cursor += enc.length(bytes, cursor, stop);
    +                if (cursor >= stop || enc.mbcToCode(bytes, cursor, stop) != '[') {
    +                    return false;
    +                }
    +                cursor += enc.length(bytes, cursor, stop);
    +                return cursor < stop && enc.mbcToCode(bytes, cursor, stop) == ':';
    +            }
    +            cursor += enc.length(bytes, cursor, stop);
    +        }
    +        return false;
    +    }
    +
    +    private boolean extendedClassBodyStartsWithControlCloseGroup(int bodyStart) {
    +        int cursor = bodyStart;
    +        while (cursor < stop && Character.isWhitespace(
    +                enc.mbcToCode(bytes, cursor, stop))) {
    +            cursor += enc.length(bytes, cursor, stop);
    +        }
    +        int[] expected = {'(', '\\', 'c', ']'};
    +        for (int codePoint : expected) {
    +            if (cursor >= stop
    +                    || enc.mbcToCode(bytes, cursor, stop) != codePoint) {
    +                return false;
    +            }
    +            cursor += enc.length(bytes, cursor, stop);
    +        }
    +        return true;
    +    }
    +
         private boolean extendedClassAt(int codePoint) {
             return left() && extendedClassCode() == codePoint;
         }
    @@ -1891,9 +2950,11 @@ private Node parseLineBreak() {
                 right.bs.setRange(env, 0x0A, 0x0D);
             }
     
    +        if (enc.isUnicode() || enc.codeToMbcLength(0x85) == 1) {
    +            right.addCodeRange(env, 0x85, 0x85);
    +        }
             if (enc.isUnicode()) {
                 /* UTF-8, UTF-16BE/LE, UTF-32BE/LE */
    -            right.addCodeRange(env, 0x85, 0x85);
                 right.addCodeRange(env, 0x2028, 0x2029);
             }
             /* (?>...) */
    @@ -2138,6 +3199,10 @@ private Node parseExpTkRawByte(boolean group) {
         }
     
         private Node parseExpRepeat(Node target, boolean group) {
    +        return parseExpRepeat(target, group, -1);
    +    }
    +
    +    private Node parseExpRepeat(Node target, boolean group, int expressionStart) {
             while (token.type == TokenType.OP_REPEAT || token.type == TokenType.INTERVAL) { // repeat:
                 if (isInvalidQuantifier(target)) newSyntaxException(TARGET_OF_REPEAT_OPERATOR_INVALID);
     
    @@ -2148,25 +3213,41 @@ private Node parseExpRepeat(Node target, boolean group) {
                                                          token.getRepeatUpper(),
                                                          token.type == TokenType.INTERVAL);
     
    +            if (expressionStart >= getBegin()
    +                    && target.getType() == NodeType.ANCHOR
    +                    && token.getRepeatUpper() == QuantifierNode.REPEAT_INFINITE
    +                    && env.usesPerlDiagnostics()) {
    +                String repeated = new String(bytes, expressionStart,
    +                        p - expressionStart, enc.getCharset());
    +                env.warnings.warn(repeated + " matches null string many times",
    +                        p - getBegin());
    +            }
    +
                 qtfr.greedy = token.getRepeatGreedy();
    -            int ret = qtfr.setQuantifier(target, group, env, bytes, getBegin(), getEnd());
    +            int ret = qtfr.setQuantifier(target, group, env, bytes, getBegin(), getEnd(),
    +                    getPatternPosition());
                 Node qn = qtfr;
     
                 if (token.getRepeatPossessive()) {
    +                // A bare {1} is normally a no-op, but {1}+ still establishes
    +                // an atomic boundary around its target.  Keep that boundary
    +                // instead of taking the ordinary no-op return path.
    +                if (ret == 1) qtfr.setTarget(target);
                     EncloseNode en = new EncloseNode(EncloseType.STOP_BACKTRACK); // node_new_enclose
                     en.setTarget(qn);
                     qn = en;
                 }
     
    -            if (ret == 0 || (syntax.op3OptionECMAScript() && ret == 1)) {
    -                target = qn;
    -            } else if (ret == 2) { /* split case: /abc+/ */
    +            if (ret == 2) { /* split case: /abc+/ */
                     target = ListNode.newList(target, null);
                     ListNode tmp = ListNode.newList(qn, null);
                     ((ListNode)target).setTail(tmp);
     
                     fetchToken();
                     return parseExpRepeatForCar(target, tmp, group);
    +            } else if (ret == 0 || token.getRepeatPossessive()
    +                    || (syntax.op3OptionECMAScript() && ret == 1)) {
    +                target = qn;
                 }
                 fetchToken(); // goto re_entry
             }
    @@ -2182,16 +3263,18 @@ private Node parseExpRepeatForCar(Node top, ListNode target, boolean group) {
                                                          token.type == TokenType.INTERVAL);
     
                 qtfr.greedy = token.getRepeatGreedy();
    -            int ret = qtfr.setQuantifier(target.value, group, env, bytes, getBegin(), getEnd());
    +            int ret = qtfr.setQuantifier(target.value, group, env, bytes, getBegin(), getEnd(),
    +                    getPatternPosition());
                 Node qn = qtfr;
     
                 if (token.getRepeatPossessive()) {
    +                if (ret == 1) qtfr.setTarget(target.value);
                     EncloseNode en = new EncloseNode(EncloseType.STOP_BACKTRACK); // node_new_enclose
                     en.setTarget(qn);
                     qn = en;
                 }
     
    -            if (ret == 0) {
    +            if (ret == 0 || token.getRepeatPossessive()) {
                     target.setValue(qn);
                 } else if (ret == 2) { /* split case: /abc+/ */
                     assert false;
    @@ -2277,7 +3360,8 @@ private Node cClassCaseFold(Node node, CClassNode cc, CClassNode ascCc,
         private Node cClassCaseFold(Node node, CClassNode cc, CClassNode ascCc,
                                     CClassNode foldCc, boolean preservePropertyAsciiCrossings) {
             ApplyCaseFoldArg arg = new ApplyCaseFoldArg(
    -                env, cc, ascCc, foldCc, preservePropertyAsciiCrossings);
    +                env, cc, ascCc, foldCc, cc.propertyFoldMask(),
    +                preservePropertyAsciiCrossings);
             enc.applyAllCaseFold(env.caseFoldFlagFor(env.option), ApplyCaseFold.INSTANCE, arg);
             if (syntax.op2OptionPerl()) {
                 ApplyCaseFold.applyPerlSimpleClassClosure(arg);
    @@ -2322,6 +3406,9 @@ private void addCharProperty(CClassNode cc, CClassNode ascCc,
                 if (foldCc != null) {
                     foldCc.addCType(property.ctype, not, false, env, this);
                 }
    +            if (property.caseFold) {
    +                cc.markPropertyFoldCType(property.ctype, false, env, this);
    +            }
                 return;
             }
             cc.addCodeRanges(property.ranges, property.wideRanges, not, env);
    @@ -2331,6 +3418,10 @@ private void addCharProperty(CClassNode cc, CClassNode ascCc,
             if (foldCc != null && property.caseFold) {
                 foldCc.addCodeRanges(property.ranges, property.wideRanges, not, env);
             }
    +        if (property.caseFold) {
    +            cc.markPropertyFoldCodeRanges(
    +                    property.ranges, property.wideRanges, false, env);
    +        }
         }
     
         private Node parseAnycharAnytime() {
    @@ -2366,6 +3457,10 @@ private Node parseBackref() {
         }
     
         private BackRefNode newBackRef(int[]backRefs) {
    +        if (token.getBackrefNameP() >= 0) {
    +            return new BackRefNode(bytes, token.getBackrefNameP(),
    +                    token.getBackrefNameEnd(), env);
    +        }
             return new BackRefNode(token.getBackrefNum(),
                 backRefs,
                 token.getBackrefByName(),
    @@ -2439,7 +3534,7 @@ private Node parsePerlNamedCall() {
             int cursor = p;
             int first = enc.mbcToCode(bytes, cursor, stop);
             int firstEnd = cursor + enc.length(bytes, cursor, stop);
    -        if (first == ')' || enc.isDigit(first) || !enc.isWord(first)) {
    +        if (first == ')' || !isPerlGroupNameStart(first)) {
                 newSyntaxException(PERL_GROUP_NAME_MUST_START_WITH_WORD,
                         firstEnd - getBegin());
             }
    diff --git a/third_party/joni/src/org/joni/Regex.java b/third_party/joni/src/org/joni/Regex.java
    index eb855e5195..a1a67631f1 100644
    --- a/third_party/joni/src/org/joni/Regex.java
    +++ b/third_party/joni/src/org/joni/Regex.java
    @@ -25,6 +25,7 @@
     import static org.joni.Option.isDontCaptureGroup;
     
     import java.nio.charset.Charset;
    +import java.nio.charset.StandardCharsets;
     import java.util.Collections;
     import java.util.Iterator;
     
    @@ -60,10 +61,13 @@ public final class Regex {
     
         int[]repeatRangeLo;
         int[]repeatRangeHi;
    +    int[][] repeatCaptureClearGroups;
    +    int numRepeatCaptureClearGroups;
     
         MatcherFactory factory;
     
         final Encoding enc;
    +    final boolean perlSyntax;
         int options;
         int userOptions;
         Object userObject;
    @@ -89,12 +93,16 @@ public final class Regex {
         int[]intMapBackward;                    /* BM skip for backward search */
         int dMin;                               /* min-distance of exact or map */
         int dMax;                               /* max-distance of exact or map */
    +    int minimumLength;                      /* minimum match length */
    +    boolean exactReachEnd;                  /* selected exact reaches pattern end */
    +    boolean characterMapOptimization;       /* selected search uses the char map */
     
         byte[][]templates;                      /* fixed pattern strings not embedded in bytecode */
         int templateNum;
         String[] controlVerbLabels;
         CClassNode[] wideScalarClasses;
         final WideScalarCodec wideScalarCodec;
    +    final CharacterPropertyResolver characterPropertyResolver;
     
         private static final Encoding DEFAULT_ENCODING;
         static {
    @@ -173,7 +181,9 @@ public Regex(byte[]bytes, int p, int end, int option, int caseFoldFlag, Encoding
             }
     
             this.enc = enc;
    +        this.perlSyntax = syntax.op2OptionPerl();
             this.wideScalarCodec = syntax.wideScalarCodec;
    +        this.characterPropertyResolver = syntax.characterPropertyResolver;
             this.options = option;
             this.caseFoldFlag = caseFoldFlag;
             new Analyser(this, syntax, bytes, p, end, warnings).compile();
    @@ -437,6 +447,8 @@ void setOptimizeExactInfo(OptExactInfo e) {
     
             dMin = e.mmd.min;
             dMax = e.mmd.max;
    +        exactReachEnd = e.reachEnd;
    +        characterMapOptimization = false;
     
             if (dMin != MinMaxLen.INFINITE_DISTANCE) {
                 thresholdLength = dMin + (exactEnd - exactP);
    @@ -456,6 +468,8 @@ void setOptimizeMapInfo(OptMapInfo m) {
     
             dMin = m.mmd.min;
             dMax = m.mmd.max;
    +        exactReachEnd = false;
    +        characterMapOptimization = true;
     
             if (dMin != MinMaxLen.INFINITE_DISTANCE) {
                 thresholdLength = dMin + 1;
    @@ -477,6 +491,9 @@ void clearOptimizeInfo() {
     
             exact = null;
             exactP = exactEnd = 0;
    +        minimumLength = 0;
    +        exactReachEnd = false;
    +        characterMapOptimization = false;
         }
     
         public String optimizeInfoToString() {
    @@ -530,6 +547,79 @@ public int getOptions() {
             return options;
         }
     
    +    /** Returns the optimizer anchor flags selected for this compiled regex. */
    +    public int getAnchor() {
    +        return anchor;
    +    }
    +
    +    /** Immutable view of optimization facts computed for this compiled regex. */
    +    public static final class OptimizationInfo {
    +        private final int minimumLength;
    +        private final String exact;
    +        private final int minimumOffset;
    +        private final Integer maximumOffset;
    +        private final boolean exactReachEnd;
    +        private final int anchor;
    +        private final int subAnchor;
    +        private final String searchAlgorithm;
    +        private final boolean characterMap;
    +        private final boolean captures;
    +
    +        private OptimizationInfo(int minimumLength, String exact,
    +                int minimumOffset, Integer maximumOffset, boolean exactReachEnd,
    +                int anchor, int subAnchor, String searchAlgorithm,
    +                boolean characterMap, boolean captures) {
    +            this.minimumLength = minimumLength;
    +            this.exact = exact;
    +            this.minimumOffset = minimumOffset;
    +            this.maximumOffset = maximumOffset;
    +            this.exactReachEnd = exactReachEnd;
    +            this.anchor = anchor;
    +            this.subAnchor = subAnchor;
    +            this.searchAlgorithm = searchAlgorithm;
    +            this.characterMap = characterMap;
    +            this.captures = captures;
    +        }
    +
    +        public int minimumLength() { return minimumLength; }
    +        public String exact() { return exact; }
    +        public int minimumOffset() { return minimumOffset; }
    +        public Integer maximumOffset() { return maximumOffset; }
    +        public boolean exactReachEnd() { return exactReachEnd; }
    +        public int anchor() { return anchor; }
    +        public int subAnchor() { return subAnchor; }
    +        public String searchAlgorithm() { return searchAlgorithm; }
    +        public boolean characterMap() { return characterMap; }
    +        public boolean hasCaptures() { return captures; }
    +        public boolean beginBufferAnchored() {
    +            return (anchor & AnchorType.BEGIN_BUF) != 0;
    +        }
    +        public boolean beginPositionAnchored() {
    +            return (anchor & AnchorType.BEGIN_POSITION) != 0;
    +        }
    +        public boolean implicitSingleLineAnchor() {
    +            return (anchor & AnchorType.ANYCHAR_STAR) != 0;
    +        }
    +        public boolean implicitMultiLineAnchor() {
    +            return (anchor & AnchorType.ANYCHAR_STAR_ML) != 0;
    +        }
    +    }
    +
    +    /** Returns the optimizer's actual selected search and length metadata. */
    +    public OptimizationInfo getOptimizationInfo() {
    +        String exactString = null;
    +        if (exact != null) {
    +            Charset charset = enc.isSingleByte()
    +                    ? StandardCharsets.ISO_8859_1 : StandardCharsets.UTF_8;
    +            exactString = new String(exact, exactP, exactEnd - exactP, charset);
    +        }
    +        Integer maximumOffset = dMax == MinMaxLen.INFINITE_DISTANCE ? null : dMax;
    +        return new OptimizationInfo(minimumLength, exactString, dMin,
    +                maximumOffset, exactReachEnd, anchor, subAnchor,
    +                forward == null ? "NONE" : forward.getName(),
    +                characterMapOptimization, numMem > 0);
    +    }
    +
         public void setUserOptions(int options) {
             this.userOptions = options;
         }
    diff --git a/third_party/joni/src/org/joni/ScanEnvironment.java b/third_party/joni/src/org/joni/ScanEnvironment.java
    index 886eb2cab6..af6e117e1c 100644
    --- a/third_party/joni/src/org/joni/ScanEnvironment.java
    +++ b/third_party/joni/src/org/joni/ScanEnvironment.java
    @@ -46,6 +46,7 @@ public final class ScanEnvironment {
         int numNamed; // USE_NAMED_GROUP
     
         public EncloseNode[] memNodes;
    +    private EncloseNode[] physicalNamedMemNodes;
     
         // USE_COMBINATION_EXPLOSION_CHECK
         int numCombExpCheck;
    @@ -54,6 +55,7 @@ public final class ScanEnvironment {
         boolean hasRecursion;
         boolean hasControlVerb;
         boolean hasCallout;
    +    boolean inPerlExtendedClass;
         private int warningsFlag;
     
         int numPrecReadNotNodes;
    @@ -104,11 +106,32 @@ void setMemNode(int num, EncloseNode node) {
                 } else if (memNodes[num] != node) {
                     multiplexMemNodes[num] = true;
                 }
    +            if (node.physicalNamedCaptureId > 0) {
    +                setPhysicalNamedMemNode(node.physicalNamedCaptureId, node);
    +            }
             } else {
                 throw new InternalException(ErrorMessages.PARSER_BUG);
             }
         }
     
    +    private void setPhysicalNamedMemNode(int physicalId, EncloseNode node) {
    +        if (physicalNamedMemNodes == null) {
    +            physicalNamedMemNodes = new EncloseNode[Config.SCANENV_MEMNODES_SIZE];
    +        } else if (physicalId >= physicalNamedMemNodes.length) {
    +            EncloseNode[] expanded = new EncloseNode[physicalNamedMemNodes.length << 1];
    +            System.arraycopy(physicalNamedMemNodes, 0, expanded, 0,
    +                    physicalNamedMemNodes.length);
    +            physicalNamedMemNodes = expanded;
    +        }
    +        physicalNamedMemNodes[physicalId] = node;
    +    }
    +
    +    EncloseNode physicalNamedMemNode(int physicalId) {
    +        return physicalNamedMemNodes == null || physicalId <= 0
    +                || physicalId >= physicalNamedMemNodes.length
    +                ? null : physicalNamedMemNodes[physicalId];
    +    }
    +
         boolean isMultiplexMemNode(int num) {
             return multiplexMemNodes != null && multiplexMemNodes[num];
         }
    diff --git a/third_party/joni/src/org/joni/ScannerSupport.java b/third_party/joni/src/org/joni/ScannerSupport.java
    index 43d3849579..6e007f02ca 100644
    --- a/third_party/joni/src/org/joni/ScannerSupport.java
    +++ b/third_party/joni/src/org/joni/ScannerSupport.java
    @@ -53,20 +53,26 @@ protected final int getEnd() {
             return end;
         }
     
    +    protected final int getLastFetched() {
    +        return lastFetched;
    +    }
    +
         protected final int getPatternPosition() {
             return p - begin;
         }
     
    -    private static final int INT_SIGN_BIT = 1 << 31;
         protected final int scanUnsignedNumber() {
             int last = c;
             int num = 0; // long ???
             while(left()) {
                 fetch();
                 if (enc.isDigit(c)) {
    -                int onum = num;
    -                num = num * 10 + Encoding.digitVal(c);
    -                if (((onum ^ num) & INT_SIGN_BIT) != 0) return -1;
    +                int digit = Encoding.digitVal(c);
    +                if (num > (Integer.MAX_VALUE - digit) / 10) {
    +                    c = last;
    +                    return -1;
    +                }
    +                num = num * 10 + digit;
                 } else {
                     unfetch();
                     break;
    @@ -103,10 +109,12 @@ protected final int scanUnsignedOctalNumber(int maxLength) {
             while(left() && maxLength-- != 0) {
                 fetch();
                 if (enc.isDigit(c) && c < '8') {
    -                int onum = num;
                     int val = Encoding.odigitVal(c);
    +                if (num > (Integer.MAX_VALUE - val) / 8) {
    +                    c = last;
    +                    return -1;
    +                }
                     num = (num << 3) + val;
    -                if (((onum ^ num) & INT_SIGN_BIT) != 0) return -1;
                 } else {
                     unfetch();
                     break;
    @@ -171,6 +179,11 @@ protected void newSyntaxException(String message, int patternPosition) {
             throw new SyntaxException(message, patternPosition);
         }
     
    +    protected void newSyntaxException(String message, int patternPosition,
    +            String diagnosticMessage) {
    +        throw new SyntaxException(message, patternPosition, diagnosticMessage);
    +    }
    +
         protected void newValueException(String message) {
             throw new ValueException(message, getPatternPosition());
         }
    diff --git a/third_party/joni/src/org/joni/StackEntry.java b/third_party/joni/src/org/joni/StackEntry.java
    index a9600ee438..a6370108ef 100644
    --- a/third_party/joni/src/org/joni/StackEntry.java
    +++ b/third_party/joni/src/org/joni/StackEntry.java
    @@ -27,6 +27,8 @@ class StackEntry {
         private String previousControlMarkName;
         private String controlMarkLabel;
         private int[] callFrameCaptureSnapshot;
    +    private boolean callFrameRestoreCallerCaptures;
    +    private boolean callFrameRecursiveVisibility;
     
         // first union member
         /* byte code position */
    @@ -190,6 +192,18 @@ void setCallFrameCaptureSnapshot(int[] snapshot) {
         int[] getCallFrameCaptureSnapshot() {
             return callFrameCaptureSnapshot;
         }
    +    void setCallFrameRestoreCallerCaptures(boolean restore) {
    +        callFrameRestoreCallerCaptures = restore;
    +    }
    +    boolean getCallFrameRestoreCallerCaptures() {
    +        return callFrameRestoreCallerCaptures;
    +    }
    +    void setCallFrameRecursiveVisibility(boolean recursive) {
    +        callFrameRecursiveVisibility = recursive;
    +    }
    +    boolean getCallFrameRecursiveVisibility() {
    +        return callFrameRecursiveVisibility;
    +    }
     
         /* absent position */
         void setAbsentStr(int pos) {
    diff --git a/third_party/joni/src/org/joni/StackMachine.java b/third_party/joni/src/org/joni/StackMachine.java
    index a5711be34d..716c4f2107 100644
    --- a/third_party/joni/src/org/joni/StackMachine.java
    +++ b/third_party/joni/src/org/joni/StackMachine.java
    @@ -32,6 +32,7 @@ abstract class StackMachine extends Matcher implements StackType {
         protected static final int INVALID_INDEX = -1;
     
         protected StackEntry[]stack;
    +    private boolean usesThreadLocalStack;
         protected int stk;  // stkEnd
         protected final int[]repeatStk;
         protected final int[] physicalNamedCaptureBeg;
    @@ -45,6 +46,7 @@ abstract class StackMachine extends Matcher implements StackType {
         protected StackMachine(Regex regex, Region region, byte[]bytes, int p , int end) {
             super(regex, region, bytes, p, end);
             stack = regex.requireStack ? fetchStack() : null;
    +        usesThreadLocalStack = stack != null;
             final int n;
             if (Config.USE_SUBEXP_CALL) {
                 n = regex.numRepeat + ((regex.numMem + 1) << 1);
    @@ -104,7 +106,32 @@ private static StackEntry[] allocateStack() {
     
         /** Nested matchers on the same thread must not overwrite their caller's stack. */
         protected final void useIndependentStack() {
    -        if (stack != null) stack = allocateStack();
    +        if (stack != null) {
    +            stack = allocateStack();
    +            usesThreadLocalStack = false;
    +        }
    +    }
    +
    +    // Keep a mutable counter per thread. Removing/recreating a boxed Integer
    +    // for every match made small global matches spend more time maintaining
    +    // ThreadLocalMap entries than executing regex bytecode.
    +    private static final ThreadLocal activeMatchers =
    +            ThreadLocal.withInitial(() -> new int[1]);
    +
    +    /** Protect the pooled stack when a callback starts another matcher. */
    +    protected final void enterMatcherExecution() {
    +        int[] counter = activeMatchers.get();
    +        int depth = counter[0];
    +        if (depth > 0 && usesThreadLocalStack) {
    +            stack = allocateStack();
    +            usesThreadLocalStack = false;
    +        }
    +        counter[0] = depth + 1;
    +    }
    +
    +    protected final void leaveMatcherExecution() {
    +        int[] counter = activeMatchers.get();
    +        counter[0]--;
         }
     
         private void doubleStack() {
    @@ -309,6 +336,71 @@ protected final void pushMemEndMark(int mnum) {
             stk++;
         }
     
    +    protected final void beginRepeatCaptureIteration(int id, int[] groups) {
    +        StackEntry marker = ensure1();
    +        marker.type = REPEAT_CAPTURE_BEGIN;
    +        marker.setMemNum(id);
    +        stk++;
    +
    +        for (int mnum : groups) {
    +            int oldStart = repeatStk[memStartStk + mnum];
    +            int oldEnd = repeatStk[memEndStk + mnum];
    +            StackEntry e = ensure1();
    +            e.type = REPEAT_CAPTURE_SNAPSHOT;
    +            e.setMemNum(mnum);
    +            e.setMemPstr(id);
    +            e.setMemStart(oldStart);
    +            e.setMemEnd(oldEnd);
    +            stk++;
    +        }
    +    }
    +
    +    protected final void endRepeatCaptureIteration(int id) {
    +        for (int index = stk - 1; index >= 0; index--) {
    +            StackEntry e = stack[index];
    +            if (e.type == REPEAT_CAPTURE_BEGIN && e.getMemNum() == id) {
    +                return;
    +            }
    +            if (e.type != REPEAT_CAPTURE_SNAPSHOT || e.getMemPStr() != id) continue;
    +
    +            int mnum = e.getMemNum();
    +            if (repeatStk[memStartStk + mnum] == e.getMemStart()
    +                    && repeatStk[memEndStk + mnum] == e.getMemEnd()) {
    +                pushRepeatCaptureClear(mnum, e.getMemStart(), e.getMemEnd());
    +                repeatStk[memStartStk + mnum] = INVALID_INDEX;
    +                repeatStk[memEndStk + mnum] = INVALID_INDEX;
    +            }
    +        }
    +        // A combination-explosion guard can unwind the bookkeeping marker
    +        // while preserving a continuation inside the optimized repeat body.
    +        // In that path there is no surviving entry snapshot to finalize.
    +    }
    +
    +    /** Previous completed value visible while the same repeated capture is open. */
    +    protected final StackEntry repeatCaptureSnapshot(int mnum) {
    +        for (int index = stk - 1; index >= 0; index--) {
    +            StackEntry entry = stack[index];
    +            if (entry.type == REPEAT_CAPTURE_SNAPSHOT && entry.getMemNum() == mnum) {
    +                return entry;
    +            }
    +        }
    +        return null;
    +    }
    +
    +    private void pushRepeatCaptureClear(int mnum, int oldStart, int oldEnd) {
    +        StackEntry clear = ensure1();
    +        clear.type = REPEAT_CAPTURE_CLEAR;
    +        clear.setMemNum(mnum);
    +        clear.setMemStart(oldStart);
    +        clear.setMemEnd(oldEnd);
    +        stk++;
    +    }
    +
    +    private void restoreRepeatCaptureClear(StackEntry e) {
    +        repeatStk[memStartStk + e.getMemNum()] = e.getMemStart();
    +        repeatStk[memEndStk + e.getMemNum()] = e.getMemEnd();
    +    }
    +
         protected final int getMemStart(int mnum) {
             int level = 0;
             int stkp = stk;
    @@ -341,12 +433,17 @@ protected final void pushNullCheckEnd(int cnum) {
             stk++;
         }
     
    -    protected final void pushCallFrame(int pat, int groupNum, boolean recursive) {
    +    protected final void pushCallFrame(int pat, int groupNum, boolean snapshotCaptures,
    +            boolean restoreCallerCaptures, boolean recursiveVisibility) {
             StackEntry e = ensure1();
             e.type = CALL_FRAME;
             e.setCallFrameRetAddr(pat);
             e.setCallFrameNum(groupNum);
    -        e.setCallFrameCaptureSnapshot(recursive ? captureSnapshot() : null);
    +        // Joni uses snapshots to mark completed recursive calls for MatchView,
    +        // independently of PerlOnJava's caller-capture restoration policy.
    +        e.setCallFrameCaptureSnapshot(snapshotCaptures ? captureSnapshot() : null);
    +        e.setCallFrameRestoreCallerCaptures(restoreCallerCaptures);
    +        e.setCallFrameRecursiveVisibility(recursiveVisibility);
             stk++;
         }
     
    @@ -358,6 +455,41 @@ private int[] captureSnapshot() {
             return snapshot;
         }
     
    +    /** Restore caller captures that a nested Perl subroutine call may overwrite. */
    +    protected final void restoreCallFrameCaptureSnapshot(StackEntry frame) {
    +        if (!frame.getCallFrameRestoreCallerCaptures()) return;
    +        int[] snapshot = frame.getCallFrameCaptureSnapshot();
    +        if (snapshot == null) return;
    +        int count = regex.numMem + 1;
    +        int groupNum = frame.getCallFrameNum();
    +        if (groupNum == 0) {
    +            // Whole-pattern recursion has no ordinary capture slot.  Preserve
    +            // its established snapshot behavior, covered by the recursive
    +            // backreference reducer.
    +            System.arraycopy(snapshot, 0, repeatStk, memStartStk, count);
    +            System.arraycopy(snapshot, count, repeatStk, memEndStk, count);
    +            return;
    +        }
    +
    +        // A nested call reuses physical capture slots.  Closed values belonged
    +        // to the caller before the call and must be visible again after return
    +        // (for example, a palindrome's enclosing character backreference).
    +        // Deliberately do not restore open or unset slots: their final state
    +        // belongs to the successful nested path.
    +        for (int mem = 1; mem < count; mem++) {
    +            if (snapshot[mem] != INVALID_INDEX
    +                    && snapshot[count + mem] != INVALID_INDEX) {
    +                repeatStk[memStartStk + mem] = snapshot[mem];
    +                repeatStk[memEndStk + mem] = snapshot[count + mem];
    +            }
    +        }
    +
    +        if (groupNum > 0 && groupNum < count) {
    +            repeatStk[memStartStk + groupNum] = snapshot[groupNum];
    +            repeatStk[memEndStk + groupNum] = snapshot[count + groupNum];
    +        }
    +    }
    +
         protected final boolean isInsideSubexpCall(int groupNum) {
             int returned = 0;
             for (int i = stk - 1; i >= 0; i--) {
    @@ -445,6 +577,8 @@ private StackEntry popFree() {
                     restoreControlMark(e.getPreviousControlMarkName());
                 } else if (e.type == PHYSICAL_NAMED_CAPTURE) {
                     restorePhysicalNamedCapture(e);
    +            } else if (e.type == REPEAT_CAPTURE_CLEAR) {
    +                restoreRepeatCaptureClear(e);
                 } else if (USE_CEC) {
                     if (e.type == STATE_CHECK_MARK) stateCheckMark();
                 }
    @@ -462,6 +596,8 @@ private StackEntry popMemStart() {
                     restoreControlMark(e.getPreviousControlMarkName());
                 } else if (e.type == PHYSICAL_NAMED_CAPTURE) {
                     restorePhysicalNamedCapture(e);
    +            } else if (e.type == REPEAT_CAPTURE_CLEAR) {
    +                restoreRepeatCaptureClear(e);
                 } else if (e.type == MEM_START) {
                     repeatStk[memStartStk + e.getMemNum()] = e.getMemStart();
                     repeatStk[memEndStk + e.getMemNum()] = e.getMemEnd();
    @@ -478,6 +614,8 @@ private void popRewrite(StackEntry e) {
                 restoreControlMark(e.getPreviousControlMarkName());
             } else if (e.type == PHYSICAL_NAMED_CAPTURE) {
                 restorePhysicalNamedCapture(e);
    +        } else if (e.type == REPEAT_CAPTURE_CLEAR) {
    +            restoreRepeatCaptureClear(e);
             } else if (e.type == MEM_START) {
                 repeatStk[memStartStk + e.getMemNum()] = e.getMemStart();
                 repeatStk[memEndStk + e.getMemNum()] = e.getMemEnd();
    @@ -578,7 +716,14 @@ private void completeCallout(StackEntry entry) {
     
         private void unwindCallout(StackEntry entry) {
             Object token = entry.takeCalloutToken();
    -        if (token != null) getCalloutHandler().unwind(token);
    +        if (token == null) return;
    +        if (completeCalloutsOnUnwind()) getCalloutHandler().complete(token);
    +        else getCalloutHandler().unwind(token);
    +    }
    +
    +    /** Whether the current failure path commits callback side effects. */
    +    protected boolean completeCalloutsOnUnwind() {
    +        return false;
         }
     
         private void completeDynamic(StackEntry entry) {
    diff --git a/third_party/joni/src/org/joni/Syntax.java b/third_party/joni/src/org/joni/Syntax.java
    index a07817c67c..ab067b3c0b 100644
    --- a/third_party/joni/src/org/joni/Syntax.java
    +++ b/third_party/joni/src/org/joni/Syntax.java
    @@ -370,6 +370,10 @@ public boolean op3OptionECMAScript() {
             return isOp3(OP3_OPTION_ECMASCRIPT);
         }
     
    +    public boolean op3PerlLiteralOpenInCC() {
    +        return isOp3(OP3_PERL_LITERAL_OPEN_IN_CC);
    +    }
    +
     
         /**
          * BEHAVIOR
    diff --git a/third_party/joni/src/org/joni/Token.java b/third_party/joni/src/org/joni/Token.java
    index e074a9a496..0c788d4577 100644
    --- a/third_party/joni/src/org/joni/Token.java
    +++ b/third_party/joni/src/org/joni/Token.java
    @@ -24,6 +24,7 @@
     final class Token {
         TokenType type;
         boolean escaped;
    +    boolean namedCharacter;
         int base;               /* is number: 8, 16 (used in [....]) */
         int backP;
     
    @@ -32,6 +33,8 @@ final class Token {
         private int []INTA1;
         private int []INTA2;
         private long LONG1;
    +    private int backrefNameP = -1;
    +    private int backrefNameEnd = -1;
     
         // union accessors
         int getC() {
    @@ -151,6 +154,19 @@ void setBackrefLevel(int level) {
             INT5 = level;
         }
     
    +    int getBackrefNameP() {
    +        return backrefNameP;
    +    }
    +
    +    void setBackrefName(int nameP, int nameEnd) {
    +        backrefNameP = nameP;
    +        backrefNameEnd = nameEnd;
    +    }
    +
    +    int getBackrefNameEnd() {
    +        return backrefNameEnd;
    +    }
    +
         // call union member
         int getCallNameP() {
             return INT1;
    diff --git a/third_party/joni/src/org/joni/ast/AnchorNode.java b/third_party/joni/src/org/joni/ast/AnchorNode.java
    index fde55ef7dd..9657eb695f 100644
    --- a/third_party/joni/src/org/joni/ast/AnchorNode.java
    +++ b/third_party/joni/src/org/joni/ast/AnchorNode.java
    @@ -29,6 +29,7 @@ public final class AnchorNode extends Node {
         public int variableLookBehindMin;
         public int variableLookBehindMax;
         public int variableLookBehindTargetLength;
    +    public boolean variableLookBehindCaptureWarned;
     
         public AnchorNode(int type, boolean asciiRange) {
             super(ANCHOR);
    @@ -37,6 +38,7 @@ public AnchorNode(int type, boolean asciiRange) {
             variableLookBehindMin = -1;
             variableLookBehindMax = -1;
             variableLookBehindTargetLength = -1;
    +        variableLookBehindCaptureWarned = false;
             this.asciiRange = asciiRange;
         }
     
    diff --git a/third_party/joni/src/org/joni/ast/BackRefNode.java b/third_party/joni/src/org/joni/ast/BackRefNode.java
    index fd50d021d5..a27b9c2baa 100644
    --- a/third_party/joni/src/org/joni/ast/BackRefNode.java
    +++ b/third_party/joni/src/org/joni/ast/BackRefNode.java
    @@ -25,13 +25,19 @@
     import org.joni.exception.ValueException;
     
     public final class BackRefNode extends StateNode {
    -    public final int[] back;
    +    public int[] back;
         public int backNum;
         public int nestLevel;
    +    public final byte[] unresolvedName;
    +    public final int unresolvedNameP;
    +    public final int unresolvedNameEnd;
     
         private BackRefNode(int backNum, int[]backRefs, boolean byName, ScanEnvironment env) {
             super(BREF);
             this.backNum = backNum;
    +        unresolvedName = null;
    +        unresolvedNameP = -1;
    +        unresolvedNameEnd = -1;
             if (byName) setNameRef();
     
             for (int i=0; i= maxCode) bs.set(env, c);
                     }
    -                addAllMultiByteRange(env);
    +                if (asciiRange || enc.minLength() > 1) addAllMultiByteRange(env);
                 } else {
    -                for (int c=0; c 0 && /* check invalid code point */
    -                            !(enc.isWord(c) || c >= maxCode)) bs.set(env, c);
    +                            (!enc.isWord(c) || c >= maxCode)) bs.set(env, c);
                     }
                     if (asciiRange) addAllMultiByteRange(env);
                 }
    @@ -611,6 +675,12 @@ public void addCType(int ctype, boolean not, boolean asciiRange, ScanEnvironment
             } // switch
         }
     
    +    public void markPropertyFoldCType(int ctype, boolean not,
    +                                      ScanEnvironment env, IntHolder sbOut) {
    +        if (propertyFoldMask == null) propertyFoldMask = new CClassNode();
    +        propertyFoldMask.addCType(ctype, not, false, env, sbOut);
    +    }
    +
         public enum CCVALTYPE {
             SB,
             CODE_POINT,
    @@ -630,6 +700,16 @@ public static final class CCStateArg {
             public long to;
             public boolean fromIsRaw;
             public boolean toIsRaw;
    +        public boolean fromEscaped;
    +        public boolean toEscaped;
    +        public boolean fromNamedCharacter;
    +        public boolean toNamedCharacter;
    +        public boolean fromFalseRangeEligible;
    +        public boolean toFalseRangeEligible;
    +        public int fromStart;
    +        public int fromEnd;
    +        public int toStart;
    +        public int toEnd;
             public CCVALTYPE inType;
             public CCVALTYPE type;
             public CCSTATE state;
    @@ -637,7 +717,21 @@ public static final class CCStateArg {
     
         public void nextStateClass(CCStateArg arg, CClassNode ascCc,
                                    CClassNode foldCc, ScanEnvironment env) {
    -        if (arg.state == CCSTATE.RANGE) throw new SyntaxException(ErrorMessages.CHAR_CLASS_VALUE_AT_END_OF_RANGE);
    +        if (arg.state == CCSTATE.RANGE) {
    +            if (!env.usesPerlDiagnostics()) {
    +                throw new SyntaxException(ErrorMessages.CHAR_CLASS_VALUE_AT_END_OF_RANGE);
    +            }
    +
    +            // Perl accepts a character class as a false range endpoint, such
    +            // as [a-\d].  The hyphen is literal and both operands remain
    +            // members of the surrounding class.
    +            arg.state = CCSTATE.VALUE;
    +            nextStateValue(arg, ascCc, foldCc, env);
    +            arg.to = '-';
    +            arg.toIsRaw = false;
    +            arg.inType = CCVALTYPE.SB;
    +            nextStateValue(arg, ascCc, foldCc, env);
    +        }
     
             if (arg.state == CCSTATE.VALUE && arg.type != CCVALTYPE.CLASS) {
                 if (arg.type == CCVALTYPE.SB) {
    @@ -654,6 +748,10 @@ public void nextStateClass(CCStateArg arg, CClassNode ascCc,
             }
             arg.state = CCSTATE.VALUE;
             arg.type = CCVALTYPE.CLASS;
    +        arg.fromStart = arg.toStart;
    +        arg.fromEnd = arg.toEnd;
    +        arg.fromNamedCharacter = arg.toNamedCharacter;
    +        arg.fromFalseRangeEligible = arg.toFalseRangeEligible;
         }
     
         public void nextStateValue(CCStateArg arg, CClassNode ascCc,
    @@ -744,6 +842,11 @@ public void nextStateValue(CCStateArg arg, CClassNode ascCc,
             } // switch
     
             arg.fromIsRaw = arg.toIsRaw;
    +        arg.fromEscaped = arg.toEscaped;
    +        arg.fromNamedCharacter = arg.toNamedCharacter;
    +        arg.fromFalseRangeEligible = arg.toFalseRangeEligible;
    +        arg.fromStart = arg.toStart;
    +        arg.fromEnd = arg.toEnd;
             arg.from = arg.to;
             arg.type = arg.inType;
         }
    diff --git a/third_party/joni/src/org/joni/ast/CallNode.java b/third_party/joni/src/org/joni/ast/CallNode.java
    index 1035bc16da..15f3a2c235 100644
    --- a/third_party/joni/src/org/joni/ast/CallNode.java
    +++ b/third_party/joni/src/org/joni/ast/CallNode.java
    @@ -27,6 +27,8 @@ public final class CallNode extends StateNode {
         public final int nameEnd;
     
         public int groupNum;
    +    /** Perl subroutine calls retain captures that were visible to their caller. */
    +    public boolean preserveCallerCaptures;
         public EncloseNode lexicalTarget;
         public EncloseNode target;
         public UnsetAddrList unsetAddrList;
    diff --git a/third_party/joni/src/org/joni/ast/EncloseNode.java b/third_party/joni/src/org/joni/ast/EncloseNode.java
    index 3271d0ccd0..91754eb3cd 100644
    --- a/third_party/joni/src/org/joni/ast/EncloseNode.java
    +++ b/third_party/joni/src/org/joni/ast/EncloseNode.java
    @@ -35,11 +35,17 @@ public final class EncloseNode extends StateNode implements EncloseType {
         public int charLength;
         public int optCount;            // referenced count in optimize_node_left()
         public int calloutConditionId = -1;
    +    /** Distinguishes unique named captures that reuse a branch-reset slot. */
    +    public int physicalNamedCondition = -1;
         public AnchorNode assertionCondition;
         public int recursionConditionGroup = -1;
         public int recursionConditionNameP = -1;
         public int recursionConditionNameEnd = -1;
         public Node containingAnchor;   //
    +    /** Perl (*script_run:...) scope; separate from historical enclosure bits. */
    +    public boolean scriptRun;
    +    /** Whether the script-run scope has the documented atomic boundary. */
    +    public boolean atomicScriptRun;
     
         // node_new_enclose / onig_node_new_enclose
         public EncloseNode(int type) {
    @@ -107,6 +113,7 @@ public String typeToString() {
             if (isCondition()) types.append("CONDITION ");
             if (isAbsent()) types.append("ABSENT ");
             if (isDefine()) types.append("DEFINE ");
    +        if (scriptRun) types.append(atomicScriptRun ? "ATOMIC_SCRIPT_RUN " : "SCRIPT_RUN ");
             return types.toString();
         }
     
    diff --git a/third_party/joni/src/org/joni/ast/QuantifierNode.java b/third_party/joni/src/org/joni/ast/QuantifierNode.java
    index 8b1a655f1f..a286341382 100644
    --- a/third_party/joni/src/org/joni/ast/QuantifierNode.java
    +++ b/third_party/joni/src/org/joni/ast/QuantifierNode.java
    @@ -204,7 +204,8 @@ public void reduceNestedQuantifier(QuantifierNode other) {
         static final String[] PopularQStr = new String[] {"?", "*", "+", "??", "*?", "+?"};
         static final String[] ReduceQStr = new String[] {"", "", "*", "*?", "??", "+ and ??", "+? and ?"};
     
    -    public int setQuantifier(Node tgt, boolean group, ScanEnvironment env, byte[]bytes, int p, int end) {
    +    public int setQuantifier(Node tgt, boolean group, ScanEnvironment env, byte[]bytes,
    +            int p, int end, int patternPosition) {
             if (lower == 1 && upper == 1) {
                 if (env.syntax.op3OptionECMAScript()) {
                     setTarget(tgt);
    @@ -233,7 +234,8 @@ public int setQuantifier(Node tgt, boolean group, ScanEnvironment env, byte[]byt
                 QuantifierNode qnt = (QuantifierNode)tgt;
                 if (env.usesPerlDiagnostics()) {
                     if (!group) {
    -                    throw new ValueException(ErrorMessages.PERL_NESTED_QUANTIFIERS);
    +                    throw new ValueException(ErrorMessages.PERL_NESTED_QUANTIFIERS,
    +                            patternPosition);
                     }
                     // Parentheses are a semantic boundary in Perl.  Keep both
                     // quantifiers instead of applying Oniguruma's reduction table
    diff --git a/third_party/joni/src/org/joni/constants/SyntaxProperties.java b/third_party/joni/src/org/joni/constants/SyntaxProperties.java
    index 62709e195c..7aa08441c1 100644
    --- a/third_party/joni/src/org/joni/constants/SyntaxProperties.java
    +++ b/third_party/joni/src/org/joni/constants/SyntaxProperties.java
    @@ -89,6 +89,7 @@ public interface SyntaxProperties {
     
         int OP3_OPTION_JAVA                = (1<<0); /* (?idmsux), (?-idmsux) */
         int OP3_OPTION_ECMASCRIPT          = (1<<1); /* EcmaScript quirks */
    +    int OP3_PERL_LITERAL_OPEN_IN_CC    = (1<<2); /* ordinary [ is literal inside Perl [...] */
     
         /* syntax (behavior); */
         int CONTEXT_INDEP_ANCHORS           = (1<<31); /* not implemented */
    diff --git a/third_party/joni/src/org/joni/constants/internal/OPCode.java b/third_party/joni/src/org/joni/constants/internal/OPCode.java
    index 15d182e88a..31a3ed8b22 100644
    --- a/third_party/joni/src/org/joni/constants/internal/OPCode.java
    +++ b/third_party/joni/src/org/joni/constants/internal/OPCode.java
    @@ -168,6 +168,11 @@ public interface OPCode {
         int WIDE_SCALAR_CLASS             = 124;
         int PUSH_BRANCH                   = 125;          /* push a syntactic alternation branch */
         int CONTROL_FAIL                  = 126;          /* explicit Perl (*FAIL[:name]) verb */
    +    int REPEAT_CAPTURE_CLEAR          = 127;          /* begin repeat capture-lifetime scope */
    +    int REPEAT_CAPTURE_CLEAR_END      = 128;          /* clear captures untouched by repeat body */
    +    int BACKREFN_PREV                 = 129;          /* Perl self-reference may use prior repeat iteration */
    +    int BACKREFN_PREV_IC              = 130;          /* case-folded prior repeat self-reference */
    +    int SCRIPT_RUN                    = 131;          /* validate the current (*script_run:...) span */
     
         String[] OpCodeNames = Config.DEBUG_COMPILE ? new String[] {
             "finish", /*OP_FINISH*/
    @@ -298,6 +303,11 @@ public interface OPCode {
             "wide-scalar-class",
             "push-branch",
             "control-fail",
    +        "repeat-capture-clear",
    +        "repeat-capture-clear-end",
    +        "backrefn-prev",
    +        "backrefn-prev-ic",
    +        "script-run",
         } : null;
     
         int[] OpCodeArgTypes = Config.DEBUG_COMPILE ? new int[] {
    @@ -429,5 +439,10 @@ public interface OPCode {
             Arguments.MEMNUM, /*OP_WIDE_SCALAR_CLASS*/
             Arguments.RELADDR, /*OP_PUSH_BRANCH*/
             Arguments.MEMNUM, /*OP_CONTROL_FAIL*/
    +        Arguments.MEMNUM, /*OP_REPEAT_CAPTURE_CLEAR*/
    +        Arguments.MEMNUM, /*OP_REPEAT_CAPTURE_CLEAR_END*/
    +        Arguments.MEMNUM, /*OP_BACKREFN_PREV*/
    +        Arguments.MEMNUM, /*OP_BACKREFN_PREV_IC*/
    +        Arguments.NON, /*OP_SCRIPT_RUN*/
         } : null;
     }
    diff --git a/third_party/joni/src/org/joni/constants/internal/OPSize.java b/third_party/joni/src/org/joni/constants/internal/OPSize.java
    index 3b17b0e9a7..c2ebab49f8 100644
    --- a/third_party/joni/src/org/joni/constants/internal/OPSize.java
    +++ b/third_party/joni/src/org/joni/constants/internal/OPSize.java
    @@ -45,6 +45,8 @@ public interface OPSize {
         int PUSH_IF_PEEK_NEXT             = (OPCODE + RELADDR + 1);
         int REPEAT_INC                    = (OPCODE + MEMNUM);
         int REPEAT_INC_NG                 = (OPCODE + MEMNUM);
    +    int REPEAT_CAPTURE_CLEAR          = (OPCODE + MEMNUM);
    +    int REPEAT_CAPTURE_CLEAR_END      = (OPCODE + MEMNUM);
         int PUSH_POS                      = (OPCODE + RELADDR);
         int PUSH_POS_NOT                  = (OPCODE + RELADDR);
         int POP_POS                       = OPCODE;
    @@ -90,6 +92,7 @@ public interface OPSize {
         int WIDE_SCALAR                  = (OPCODE + 2);
         int WIDE_SCALAR_CLASS            = (OPCODE + INDEX);
         int PUSH_BRANCH                  = (OPCODE + RELADDR);
    +    int SCRIPT_RUN                   = OPCODE;
     
         // #ifdef USE_COMBINATION_EXPLOSION_CHECK
         int STATE_CHECK                   = (OPCODE + STATE_CHECK_NUM);
    diff --git a/third_party/joni/src/org/joni/constants/internal/StackType.java b/third_party/joni/src/org/joni/constants/internal/StackType.java
    index 467bbb5ab9..13e0f8a4a3 100644
    --- a/third_party/joni/src/org/joni/constants/internal/StackType.java
    +++ b/third_party/joni/src/org/joni/constants/internal/StackType.java
    @@ -48,6 +48,9 @@ public interface StackType {
         int CALLOUT                       = 0x0d00;  /* match-time callback unwind token */
         int CONTROL_MARK                  = 0x0e00;  /* Perl (*MARK:name) backtrack state */
         int PHYSICAL_NAMED_CAPTURE        = 0x0f00;  /* physical named-group span */
    +    int REPEAT_CAPTURE_BEGIN          = 0x1100;  /* repeat capture-lifetime scope */
    +    int REPEAT_CAPTURE_SNAPSHOT       = 0x1200;  /* capture state at body entry */
    +    int REPEAT_CAPTURE_CLEAR          = 0x1300;  /* cleared stale capture rollback */
         int DYNAMIC_ALT                   = 0x0004;  /* resumable nested-program alternative */
         int BRANCH_ALT                    = 0x0005;  /* syntactic alternation continuation */
     
    diff --git a/third_party/joni/src/org/joni/exception/ErrorMessages.java b/third_party/joni/src/org/joni/exception/ErrorMessages.java
    index a9833c1f96..06d84b80a5 100644
    --- a/third_party/joni/src/org/joni/exception/ErrorMessages.java
    +++ b/third_party/joni/src/org/joni/exception/ErrorMessages.java
    @@ -37,6 +37,7 @@ public interface ErrorMessages extends org.jcodings.exception.ErrorMessages {
         String END_PATTERN_AT_LEFT_BRACKET = "end pattern at left bracket";
         String EMPTY_CHAR_CLASS = "empty char-class";
         String PERL_UNMATCHED_OPEN_BRACKET = "Unmatched [";
    +    String PERL_UNMATCHED_OPEN_PARENTHESIS = "Unmatched (";
         String PREMATURE_END_OF_CHAR_CLASS = "premature end of char-class";
         String END_PATTERN_AT_ESCAPE = "end pattern at escape";
         String END_PATTERN_AT_META = "end pattern at meta";
    @@ -55,8 +56,25 @@ public interface ErrorMessages extends org.jcodings.exception.ErrorMessages {
         String UNMATCHED_CLOSE_PARENTHESIS = "unmatched close parenthesis";
         String END_PATTERN_WITH_UNMATCHED_PARENTHESIS = "end pattern with unmatched parenthesis";
         String END_PATTERN_IN_GROUP = "end pattern in group";
    +    String PERL_OPTION_GROUP_NOT_TERMINATED = "Sequence (?... not terminated";
    +    String PERL_COMMENT_GROUP_NOT_TERMINATED = "Sequence (?#... not terminated";
    +    String PERL_POSITIVE_LOOKBEHIND_NOT_TERMINATED = "Sequence (?<=... not terminated";
    +    String PERL_NEGATIVE_LOOKBEHIND_NOT_TERMINATED = "Sequence (?";
         String MULTIPLEX_DEFINITION_NAME_CALL = "multiplex definition name <%n> call";
         String PROPERTY_NAME_NEVER_TERMINATED = "property name never terminated \\p{%n";
    +    String PERL_MISSING_RIGHT_BRACE_ON_CHARACTER_PROPERTY =
    +            "Missing right brace on \\%n{}";
    +    String PERL_CONTROL_ARGUMENT_MUST_BE_PRINTABLE_ASCII =
    +            "Character following \"\\c\" must be printable ASCII";
         String NEVER_ENDING_RECURSION = "never ending recursion";
         String GROUP_NUMBER_OVER_FOR_CAPTURE_HISTORY = "group number is too big for capture history";
         String NOT_SUPPORTED_ENCODING_COMBINATION = "not supported encoding combination";
    diff --git a/third_party/joni/src/org/joni/exception/SyntaxException.java b/third_party/joni/src/org/joni/exception/SyntaxException.java
    index 8112768700..8d36f10d9a 100644
    --- a/third_party/joni/src/org/joni/exception/SyntaxException.java
    +++ b/third_party/joni/src/org/joni/exception/SyntaxException.java
    @@ -24,14 +24,20 @@ public class SyntaxException extends JOniException{
         public static final int UNKNOWN_PATTERN_POSITION = -1;
     
         private final int patternPosition;
    +    private final String diagnosticMessage;
     
         public SyntaxException(String message) {
             this(message, UNKNOWN_PATTERN_POSITION);
         }
     
         public SyntaxException(String message, int patternPosition) {
    +        this(message, patternPosition, message);
    +    }
    +
    +    public SyntaxException(String message, int patternPosition, String diagnosticMessage) {
             super(message);
             this.patternPosition = patternPosition;
    +        this.diagnosticMessage = diagnosticMessage;
         }
     
         /**
    @@ -42,4 +48,12 @@ public SyntaxException(String message, int patternPosition) {
         public int getPatternPosition() {
             return patternPosition;
         }
    +
    +    /**
    +     * Returns the source-aware diagnostic when the parser retained one, while
    +     * {@link #getMessage()} remains the stable engine-level error contract.
    +     */
    +    public String getDiagnosticMessage() {
    +        return diagnosticMessage;
    +    }
     }
    diff --git a/third_party/joni/test/org/joni/TestBeginPositionSearchStart.java b/third_party/joni/test/org/joni/TestBeginPositionSearchStart.java
    new file mode 100644
    index 0000000000..6c63f9f51f
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/TestBeginPositionSearchStart.java
    @@ -0,0 +1,87 @@
    +/*
    + * 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.
    + */
    +package org.joni;
    +
    +import static org.junit.Assert.assertEquals;
    +import static org.junit.Assert.assertTrue;
    +
    +import java.nio.charset.StandardCharsets;
    +import java.util.ArrayList;
    +import java.util.List;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.constants.internal.AnchorType;
    +import org.junit.Test;
    +
    +public class TestBeginPositionSearchStart {
    +    private static Regex compile(String pattern) {
    +        byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        return new Regex(bytes, 0, bytes.length, Option.NONE,
    +                UTF8Encoding.INSTANCE, Syntax.Perl);
    +    }
    +
    +    private static final class CountingMatcher extends Matcher {
    +        private final List attemptedStarts = new ArrayList<>();
    +
    +        CountingMatcher(Regex regex, byte[] bytes) {
    +            super(regex, null, bytes, 0, bytes.length);
    +        }
    +
    +        @Override
    +        protected int matchAt(int range, int start, int previous, boolean interrupt) {
    +            attemptedStarts.add(start);
    +            return FAILED;
    +        }
    +
    +        @Override protected void stateCheckBuffInit(int length, int offset, int states) { }
    +        @Override protected void stateCheckBuffClear() { }
    +        @Override public void interrupt() { }
    +    }
    +
    +    private static void assertAttempts(int gpos, int start, int range,
    +                                       Integer... expectedStarts) {
    +        Regex regex = compile("\\G.");
    +        byte[] subject = "abcdef".getBytes(StandardCharsets.UTF_8);
    +        CountingMatcher matcher = new CountingMatcher(regex, subject);
    +        assertEquals(Matcher.FAILED, matcher.search(gpos, start, range, Option.NONE));
    +        assertEquals(List.of(expectedStarts), matcher.attemptedStarts);
    +    }
    +
    +    @Test
    +    public void mandatoryBeginPositionTriesOnlyGposAcrossForwardRange() {
    +        Regex regex = compile("\\G.");
    +        assertTrue((regex.anchor & AnchorType.BEGIN_POSITION) != 0);
    +
    +        assertAttempts(2, 2, 6, 2);
    +        assertAttempts(4, 2, 6, 4);
    +        assertAttempts(6, 2, 6, 6);
    +        assertAttempts(1, 2, 6);
    +        assertAttempts(7, 2, 6);
    +    }
    +
    +    @Test
    +    public void mandatoryBeginPositionTriesOnlyGposAcrossReverseRange() {
    +        assertAttempts(6, 6, 2, 6);
    +        assertAttempts(4, 6, 2, 4);
    +        assertAttempts(2, 6, 2, 2);
    +        assertAttempts(1, 6, 2);
    +        assertAttempts(7, 6, 2);
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/TestLazyAnyCharStarAnchor.java b/third_party/joni/test/org/joni/TestLazyAnyCharStarAnchor.java
    new file mode 100644
    index 0000000000..57207e8096
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/TestLazyAnyCharStarAnchor.java
    @@ -0,0 +1,107 @@
    +/*
    + * 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.
    + */
    +package org.joni;
    +
    +import static org.junit.Assert.assertEquals;
    +import static org.junit.Assert.assertFalse;
    +import static org.junit.Assert.assertTrue;
    +
    +import java.nio.charset.StandardCharsets;
    +import java.util.ArrayList;
    +import java.util.List;
    +import java.util.concurrent.Callable;
    +import java.util.concurrent.ExecutorService;
    +import java.util.concurrent.Executors;
    +import java.util.concurrent.Future;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.constants.internal.AnchorType;
    +import org.junit.Test;
    +
    +public class TestLazyAnyCharStarAnchor {
    +    private static Regex compile(String source, int options) {
    +        byte[] pattern = source.getBytes(StandardCharsets.UTF_8);
    +        return new Regex(pattern, 0, pattern.length, options,
    +                UTF8Encoding.INSTANCE, Syntax.Perl);
    +    }
    +
    +    private static Matcher matcher(Regex regex, String subject) {
    +        byte[] bytes = subject.getBytes(StandardCharsets.UTF_8);
    +        return regex.matcher(bytes, 0, bytes.length);
    +    }
    +
    +    @Test
    +    public void lazyLeadingDotStarUsesTheSameImplicitAnchorAsGreedy() {
    +        Regex lazy = compile(".*?x", Option.NONE);
    +
    +        assertTrue((lazy.anchor & AnchorType.ANYCHAR_STAR) != 0);
    +    }
    +
    +    @Test
    +    public void lazyMatchExtentAndLineStartSemanticsRemainUnchanged() {
    +        Regex lazy = compile(".*?x", Option.NONE);
    +
    +        Matcher first = matcher(lazy, "abxx");
    +        assertEquals(0, first.search(0, 4, Option.NONE));
    +        assertEquals(0, first.getBegin());
    +        assertEquals(3, first.getEnd());
    +
    +        Matcher afterNewline = matcher(lazy, "before\nx");
    +        assertEquals(7, afterNewline.search(0, 8, Option.NONE));
    +        assertEquals(7, afterNewline.getBegin());
    +        assertEquals(8, afterNewline.getEnd());
    +    }
    +
    +    @Test
    +    public void alternativesDoNotAcquireAnUnsafeImplicitAnchor() {
    +        Regex alternative = compile("a|.*?x", Option.NONE);
    +        assertFalse((alternative.anchor & AnchorType.ANYCHAR_STAR_MASK) != 0);
    +
    +        Matcher matcher = matcher(alternative, "ba");
    +        assertEquals(1, matcher.search(0, 2, Option.NONE));
    +        assertEquals(1, matcher.getBegin());
    +        assertEquals(2, matcher.getEnd());
    +    }
    +
    +    @Test
    +    public void compiledLazyAnchorIsReusableAcrossThreads() throws Exception {
    +        Regex lazy = compile(".*?x", Option.NONE);
    +        ExecutorService executor = Executors.newFixedThreadPool(2);
    +        try {
    +            List> tasks = new ArrayList<>();
    +            for (int task = 0; task < 2; task++) {
    +                tasks.add(() -> {
    +                    for (int iteration = 0; iteration < 250; iteration++) {
    +                        Matcher matcher = matcher(lazy, "before\nx");
    +                        if (matcher.search(0, 8, Option.NONE) != 7
    +                                || matcher.getBegin() != 7
    +                                || matcher.getEnd() != 8) return false;
    +                    }
    +                    return true;
    +                });
    +            }
    +            for (Future result : executor.invokeAll(tasks)) {
    +                assertTrue(result.get());
    +            }
    +        } finally {
    +            executor.shutdownNow();
    +        }
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/TestNullableEndAnchorSearch.java b/third_party/joni/test/org/joni/TestNullableEndAnchorSearch.java
    new file mode 100644
    index 0000000000..b8ab8b1b65
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/TestNullableEndAnchorSearch.java
    @@ -0,0 +1,70 @@
    +/*
    + * 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.
    + */
    +package org.joni;
    +
    +import static org.junit.Assert.assertEquals;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.junit.Test;
    +
    +public class TestNullableEndAnchorSearch {
    +    private static Regex compile(String pattern) {
    +        byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        return new Regex(bytes, 0, bytes.length, Option.NONE,
    +                UTF8Encoding.INSTANCE, Syntax.Perl);
    +    }
    +
    +    private static int search(String pattern, String input) {
    +        byte[] bytes = input.getBytes(StandardCharsets.UTF_8);
    +        return compile(pattern).matcher(bytes).search(0, bytes.length, Option.NONE);
    +    }
    +
    +    private static int reverseSearch(String pattern, String input) {
    +        byte[] bytes = input.getBytes(StandardCharsets.UTF_8);
    +        return compile(pattern).matcher(bytes).search(bytes.length, 0, Option.NONE);
    +    }
    +
    +    @Test
    +    public void nullableSemiEndAnchorRetainsTheEndCandidate() {
    +        assertEquals(2, search("a?$", "\u0131"));
    +        assertEquals(4, search("a?$", "\uD83D\uDE00"));
    +        assertEquals(1, search("a?$", "x"));
    +    }
    +
    +    @Test
    +    public void nullableAbsoluteEndAnchorRetainsTheEndCandidate() {
    +        assertEquals(2, search("a?\\z", "\u0131"));
    +        assertEquals(4, search("a?\\z", "\uD83D\uDE00"));
    +    }
    +
    +    @Test
    +    public void nonNullableEndAnchorDoesNotGainAnEmptyMatch() {
    +        assertEquals(Matcher.FAILED, search("a$", "\u0131"));
    +        assertEquals(Matcher.FAILED, search("a\\z", "\u0131"));
    +    }
    +
    +    @Test
    +    public void reverseSearchRetainsNullableEndCandidates() {
    +        assertEquals(2, reverseSearch("a?$", "\u0131"));
    +        assertEquals(2, reverseSearch("a?\\z", "\u0131"));
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/TestOptimizationIntrospection.java b/third_party/joni/test/org/joni/TestOptimizationIntrospection.java
    new file mode 100644
    index 0000000000..d188ef872a
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/TestOptimizationIntrospection.java
    @@ -0,0 +1,68 @@
    +/*
    + * 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.
    + */
    +package org.joni;
    +
    +import static org.junit.Assert.assertEquals;
    +import static org.junit.Assert.assertFalse;
    +import static org.junit.Assert.assertNotEquals;
    +import static org.junit.Assert.assertNull;
    +import static org.junit.Assert.assertTrue;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.junit.Test;
    +
    +public class TestOptimizationIntrospection {
    +    private static Regex compile(String source) {
    +        byte[] pattern = source.getBytes(StandardCharsets.UTF_8);
    +        return new Regex(pattern, 0, pattern.length, Option.NONE,
    +                UTF8Encoding.INSTANCE, Syntax.Perl);
    +    }
    +
    +    @Test
    +    public void exposesSelectedExactSearchFacts() {
    +        Regex.OptimizationInfo exact = compile("abc").getOptimizationInfo();
    +        assertEquals(3, exact.minimumLength());
    +        assertEquals("abc", exact.exact());
    +        assertEquals(0, exact.minimumOffset());
    +        assertEquals(Integer.valueOf(0), exact.maximumOffset());
    +        assertTrue(exact.exactReachEnd());
    +        assertNotEquals("NONE", exact.searchAlgorithm());
    +        assertFalse(exact.characterMap());
    +        assertFalse(exact.hasCaptures());
    +
    +        assertTrue(compile("a()bc").getOptimizationInfo().hasCaptures());
    +
    +        Regex.OptimizationInfo floating = compile("x?abc").getOptimizationInfo();
    +        assertEquals(3, floating.minimumLength());
    +        assertEquals("abc", floating.exact());
    +        assertEquals(0, floating.minimumOffset());
    +        assertEquals(Integer.valueOf(1), floating.maximumOffset());
    +    }
    +
    +    @Test
    +    public void reportsNoExactSearchForEmptyPattern() {
    +        Regex.OptimizationInfo empty = compile("").getOptimizationInfo();
    +        assertEquals(0, empty.minimumLength());
    +        assertNull(empty.exact());
    +        assertEquals("NONE", empty.searchAlgorithm());
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/TestOptimizerAnchorMetadata.java b/third_party/joni/test/org/joni/TestOptimizerAnchorMetadata.java
    new file mode 100644
    index 0000000000..e4d7ebb3f9
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/TestOptimizerAnchorMetadata.java
    @@ -0,0 +1,76 @@
    +/*
    + * 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.
    + */
    +package org.joni;
    +
    +import static org.junit.Assert.assertEquals;
    +
    +import java.nio.charset.StandardCharsets;
    +import java.util.ArrayList;
    +import java.util.List;
    +import java.util.concurrent.Callable;
    +import java.util.concurrent.ExecutorService;
    +import java.util.concurrent.Executors;
    +import java.util.concurrent.Future;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.constants.internal.AnchorType;
    +import org.junit.Test;
    +
    +public class TestOptimizerAnchorMetadata {
    +    private static Regex compile(String source, int options) {
    +        byte[] pattern = source.getBytes(StandardCharsets.UTF_8);
    +        return new Regex(pattern, 0, pattern.length, options,
    +                UTF8Encoding.INSTANCE, Syntax.Perl);
    +    }
    +
    +    @Test
    +    public void exposesImplicitLineAnchorKinds() {
    +        assertEquals(AnchorType.ANYCHAR_STAR,
    +                compile(".*?x", Option.NONE).getAnchor() & AnchorType.ANYCHAR_STAR_MASK);
    +        assertEquals(AnchorType.ANYCHAR_STAR_ML,
    +                compile(".*?x", Option.MULTILINE).getAnchor()
    +                        & AnchorType.ANYCHAR_STAR_MASK);
    +        assertEquals(0, compile("a|.*?x", Option.NONE).getAnchor()
    +                & AnchorType.ANYCHAR_STAR_MASK);
    +    }
    +
    +    @Test
    +    public void compiledMetadataIsStableAcrossThreads() throws Exception {
    +        Regex regex = compile(".*?x", Option.NONE);
    +        ExecutorService executor = Executors.newFixedThreadPool(2);
    +        try {
    +            List> tasks = new ArrayList<>();
    +            for (int task = 0; task < 2; task++) {
    +                tasks.add(() -> {
    +                    for (int iteration = 0; iteration < 1_000; iteration++) {
    +                        if ((regex.getAnchor() & AnchorType.ANYCHAR_STAR_MASK)
    +                                != AnchorType.ANYCHAR_STAR) return false;
    +                    }
    +                    return true;
    +                });
    +            }
    +            for (Future result : executor.invokeAll(tasks)) {
    +                assertEquals(true, result.get());
    +            }
    +        } finally {
    +            executor.shutdownNow();
    +        }
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/TestPerlBackreferenceFoldExpansion.java b/third_party/joni/test/org/joni/TestPerlBackreferenceFoldExpansion.java
    new file mode 100644
    index 0000000000..e323717cc4
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/TestPerlBackreferenceFoldExpansion.java
    @@ -0,0 +1,82 @@
    +/*
    + * 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.
    + */
    +package org.joni;
    +
    +import static org.junit.Assert.assertEquals;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.Encoding;
    +import org.jcodings.specific.ISO8859_1Encoding;
    +import org.jcodings.specific.UTF8Encoding;
    +import org.junit.Test;
    +
    +public class TestPerlBackreferenceFoldExpansion {
    +    private static Regex compile(String pattern, Encoding encoding, int options) {
    +        byte[] bytes = encoding == UTF8Encoding.INSTANCE
    +                ? pattern.getBytes(StandardCharsets.UTF_8)
    +                : pattern.getBytes(StandardCharsets.ISO_8859_1);
    +        return new Regex(bytes, 0, bytes.length, options,
    +                encoding, Syntax.Perl);
    +    }
    +
    +    private static int search(String pattern, String input, Encoding encoding,
    +                              int options, boolean reverse) {
    +        byte[] bytes = encoding == UTF8Encoding.INSTANCE
    +                ? input.getBytes(StandardCharsets.UTF_8)
    +                : input.getBytes(StandardCharsets.ISO_8859_1);
    +        Matcher matcher = compile(pattern, encoding, options).matcher(bytes);
    +        return reverse
    +                ? matcher.search(bytes.length, 0, Option.NONE)
    +                : matcher.search(0, bytes.length, Option.NONE);
    +    }
    +
    +    @Test
    +    public void streamsFullFoldsAcrossBackreferenceCharacterBoundaries() {
    +        int options = Option.IGNORECASE;
    +        assertEquals(0, search("(ß)\\1", "ßss",
    +                UTF8Encoding.INSTANCE, options, false));
    +        assertEquals(0, search("(ss)\\1", "ssß",
    +                UTF8Encoding.INSTANCE, options, false));
    +        assertEquals(0, search("([ß])\\1", "ßss",
    +                UTF8Encoding.INSTANCE, options, false));
    +        assertEquals(0, search("(ß)\\1", "ßss",
    +                UTF8Encoding.INSTANCE, options, true));
    +    }
    +
    +    @Test
    +    public void bytePatternBackreferencesOnlyFoldAscii() {
    +        int options = Option.IGNORECASE | Option.PERL_BYTE_PATTERN;
    +        assertEquals(Matcher.FAILED, search("(à)\\1", "àÀ",
    +                ISO8859_1Encoding.INSTANCE, options, false));
    +        assertEquals(0, search("(à)\\1", "àà",
    +                ISO8859_1Encoding.INSTANCE, options, false));
    +        assertEquals(0, search("(a)\\1", "aA",
    +                ISO8859_1Encoding.INSTANCE, options, false));
    +        assertEquals(Matcher.FAILED, search("(à)\\1", "àÀ",
    +                ISO8859_1Encoding.INSTANCE, options, true));
    +    }
    +
    +    @Test
    +    public void unicodeBackreferencesRetainSimpleLatinFolds() {
    +        assertEquals(0, search("(à)\\1", "àÀ",
    +                UTF8Encoding.INSTANCE, Option.IGNORECASE, false));
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/TestPerlCalledGroupLookBehind.java b/third_party/joni/test/org/joni/TestPerlCalledGroupLookBehind.java
    new file mode 100644
    index 0000000000..8c9bf72eab
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/TestPerlCalledGroupLookBehind.java
    @@ -0,0 +1,79 @@
    +/*
    + * 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.
    + */
    +package org.joni;
    +
    +import static org.joni.constants.SyntaxProperties.ALLOW_MULTIPLEX_DEFINITION_NAME_CALL;
    +import static org.joni.constants.SyntaxProperties.OP2_OPTION_PERL;
    +import static org.joni.constants.SyntaxProperties.OP2_OPTION_RUBY;
    +import static org.junit.Assert.assertEquals;
    +import static org.junit.Assert.assertThrows;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.exception.SyntaxException;
    +import org.junit.Test;
    +
    +public class TestPerlCalledGroupLookBehind {
    +    private static final Syntax PERLONJAVA = new Syntax(
    +            "PERLONJAVA", Syntax.RUBY.op,
    +            (Syntax.RUBY.op2 & ~OP2_OPTION_RUBY) | OP2_OPTION_PERL,
    +            Syntax.RUBY.op3,
    +            Syntax.RUBY.behavior | ALLOW_MULTIPLEX_DEFINITION_NAME_CALL,
    +            Syntax.RUBY.options, Syntax.RUBY.metaCharTable);
    +
    +    private static Matcher matcher(String pattern, String input) {
    +        byte[] source = pattern.getBytes(StandardCharsets.UTF_8);
    +        Regex regex = new Regex(source, 0, source.length, Option.NONE,
    +                UTF8Encoding.INSTANCE, PERLONJAVA);
    +        return regex.matcher(input.getBytes(StandardCharsets.UTF_8));
    +    }
    +
    +    @Test
    +    public void finiteCalledGroupContributesItsLookbehindWidth() {
    +        Matcher repeated = matcher(
    +                "(?a)(?(?=\\g)(?<=\\g))\\g", "aa");
    +        assertEquals(0, repeated.search(0, 2, Option.NONE));
    +        assertEquals(0, repeated.getBegin());
    +        assertEquals(1, repeated.getEnd());
    +
    +        Matcher defined = matcher(
    +                "(?(DEFINE)(?a\\K))(?<=\\g)", "a");
    +        assertEquals(1, defined.search(0, 1, Option.NONE));
    +        assertEquals(1, defined.getBegin());
    +        assertEquals(1, defined.getEnd());
    +    }
    +
    +    @Test
    +    public void calledGroupWorksInsideNegativeLookbehind() {
    +        assertEquals(0, matcher(
    +                "(?(DEFINE)(?a\\K))(?)", "a")
    +                .search(0, 1, Option.NONE));
    +        assertEquals(0, matcher(
    +                "(?(DEFINE)(?a\\K))(?)", "b")
    +                .search(0, 1, Option.NONE));
    +    }
    +
    +    @Test
    +    public void trulyRecursiveWidthRemainsRejected() {
    +        assertThrows(SyntaxException.class, () -> matcher(
    +                "(?(DEFINE)(?a\\g?))(?<=\\g)", "a"));
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/TestPerlCalledKeepLookaround.java b/third_party/joni/test/org/joni/TestPerlCalledKeepLookaround.java
    new file mode 100644
    index 0000000000..85846c2e28
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/TestPerlCalledKeepLookaround.java
    @@ -0,0 +1,105 @@
    +/*
    + * 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.
    + */
    +package org.joni;
    +
    +import static org.joni.constants.SyntaxProperties.ALLOW_MULTIPLEX_DEFINITION_NAME_CALL;
    +import static org.joni.constants.SyntaxProperties.OP2_OPTION_PERL;
    +import static org.joni.constants.SyntaxProperties.OP2_OPTION_RUBY;
    +import static org.junit.Assert.assertEquals;
    +
    +import java.nio.charset.StandardCharsets;
    +import java.util.ArrayList;
    +import java.util.List;
    +import java.util.concurrent.Callable;
    +import java.util.concurrent.ExecutorService;
    +import java.util.concurrent.Executors;
    +import java.util.concurrent.Future;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.junit.Test;
    +
    +public class TestPerlCalledKeepLookaround {
    +    private static final Syntax PERLONJAVA = new Syntax(
    +            "PERLONJAVA", Syntax.RUBY.op,
    +            (Syntax.RUBY.op2 & ~OP2_OPTION_RUBY) | OP2_OPTION_PERL,
    +            Syntax.RUBY.op3,
    +            Syntax.RUBY.behavior | ALLOW_MULTIPLEX_DEFINITION_NAME_CALL,
    +            Syntax.RUBY.options, Syntax.RUBY.metaCharTable);
    +
    +    private static Regex compile(String pattern) {
    +        byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        return new Regex(bytes, 0, bytes.length, Option.NONE,
    +                UTF8Encoding.INSTANCE, PERLONJAVA);
    +    }
    +
    +    private static void assertInvertedKeep(Regex regex, boolean reverse) {
    +        byte[] input = "aa".getBytes(StandardCharsets.UTF_8);
    +        Matcher matcher = regex.matcher(input);
    +        assertEquals(0, reverse
    +                ? matcher.search(input.length, 0, Option.NONE)
    +                : matcher.search(0, input.length, Option.NONE));
    +        assertEquals(2, matcher.getBegin());
    +        assertEquals(1, matcher.getEnd());
    +    }
    +
    +    @Test
    +    public void calledKeepInsidePositiveLookaheadPublishesPerlRegion() {
    +        Regex regex = compile("(?a\\K)(?=\\g)");
    +        assertInvertedKeep(regex, false);
    +        assertInvertedKeep(regex, true);
    +    }
    +
    +    @Test
    +    public void definedCalledKeepCanMovePastZeroWidthEnd() {
    +        byte[] input = "a".getBytes(StandardCharsets.UTF_8);
    +        Matcher matcher = compile(
    +                "(?(DEFINE)(?a\\K))(?=\\g)").matcher(input);
    +        assertEquals(0, matcher.search(0, input.length, Option.NONE));
    +        assertEquals(1, matcher.getBegin());
    +        assertEquals(0, matcher.getEnd());
    +    }
    +
    +    @Test
    +    public void matcherInstancesKeepCalledAssertionStateIsolated() throws Exception {
    +        Regex regex = compile("(?a\\K)(?=\\g)");
    +        ExecutorService pool = Executors.newFixedThreadPool(2);
    +        try {
    +            List> tasks = new ArrayList<>();
    +            for (int worker = 0; worker < 2; worker++) {
    +                tasks.add(() -> {
    +                    for (int iteration = 0; iteration < 250; iteration++) {
    +                        byte[] input = "aa".getBytes(StandardCharsets.UTF_8);
    +                        Matcher matcher = regex.matcher(input);
    +                        if (matcher.search(0, input.length, Option.NONE) != 0
    +                                || matcher.getBegin() != 2 || matcher.getEnd() != 1) {
    +                            return false;
    +                        }
    +                    }
    +                    return true;
    +                });
    +            }
    +            for (Future result : pool.invokeAll(tasks)) {
    +                assertEquals(Boolean.TRUE, result.get());
    +            }
    +        } finally {
    +            pool.shutdownNow();
    +        }
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/TestPerlFoldOptimizerLength.java b/third_party/joni/test/org/joni/TestPerlFoldOptimizerLength.java
    new file mode 100644
    index 0000000000..e2cedbb6c6
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/TestPerlFoldOptimizerLength.java
    @@ -0,0 +1,65 @@
    +/*
    + * 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.
    + */
    +package org.joni;
    +
    +import static org.junit.Assert.assertEquals;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.junit.Test;
    +
    +public class TestPerlFoldOptimizerLength {
    +    private static int search(String pattern, String input, boolean reverse) {
    +        byte[] source = pattern.getBytes(StandardCharsets.UTF_8);
    +        Regex regex = new Regex(source, 0, source.length, Option.IGNORECASE,
    +                UTF8Encoding.INSTANCE, Syntax.Perl);
    +        byte[] target = input.getBytes(StandardCharsets.UTF_8);
    +        Matcher matcher = regex.matcher(target);
    +        return reverse
    +                ? matcher.search(target.length, 0, Option.NONE)
    +                : matcher.search(0, target.length, Option.NONE);
    +    }
    +
    +    private static void assertBothDirections(String pattern, String input) {
    +        assertEquals(0, search(pattern, input, false));
    +        assertEquals(0, search(pattern, input, true));
    +    }
    +
    +    @Test
    +    public void groupedHighAlternativeLiteralKeepsFollowingCandidateReachable() {
    +        assertBothDirections("(?u:(\u1f80)_$)", "\u1f88_");
    +        assertBothDirections("(?u:(\u1f80,?){1,3}_$)", "\u1f88_");
    +    }
    +
    +    @Test
    +    public void groupedHighAlternativeClassKeepsFollowingCandidateReachable() {
    +        assertBothDirections("(?u:([\u1f80])_$)", "\u1f88_");
    +        assertBothDirections("(?u:([\u1f80],?){1,3}_$)", "\u1f88_");
    +    }
    +
    +    @Test
    +    public void highAlternativeFoldRetainsItsLookbehindWidthRange() {
    +        assertEquals(3, search("(?u:(?<=\u1f80)X)", "\u1f88X", false));
    +        assertEquals(3, search("(?u:(?<=\u1f80)X)", "\u1f88X", true));
    +        assertEquals(3, search("(?u:(?<=\u1f88)X)", "\u1f80X", false));
    +        assertEquals(3, search("(?u:(?<=\u1f88)X)", "\u1f80X", true));
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestCalloutSearchOrder.java b/third_party/joni/test/org/joni/test/TestCalloutSearchOrder.java
    new file mode 100644
    index 0000000000..0fe0f6617c
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestCalloutSearchOrder.java
    @@ -0,0 +1,65 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +
    +import java.nio.charset.StandardCharsets;
    +import java.util.ArrayList;
    +import java.util.Arrays;
    +import java.util.List;
    +
    +import org.jcodings.specific.ASCIIEncoding;
    +import org.joni.CalloutHandler;
    +import org.joni.CalloutResult;
    +import org.joni.MatchView;
    +import org.joni.Matcher;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.junit.Test;
    +
    +public class TestCalloutSearchOrder {
    +    @Test
    +    public void searchVisitsCalloutCandidatesInSourceOrder() {
    +        String pattern = "([ace]).(?{=CALL:1})([ce])(?{=CALL:2})";
    +        byte[] patternBytes = pattern.getBytes(StandardCharsets.US_ASCII);
    +        Regex regex = new Regex(patternBytes, 0, patternBytes.length, Option.NONE,
    +                ASCIIEncoding.INSTANCE, Syntax.RUBY);
    +        byte[] input = "abcde|abcde".getBytes(StandardCharsets.US_ASCII);
    +        List positions = new ArrayList<>();
    +        Matcher matcher = regex.matcher(input);
    +        matcher.setCalloutHandler(new CalloutHandler() {
    +            @Override
    +            public CalloutResult execute(int id, MatchView match) {
    +                positions.add(match.currentBytePosition());
    +                return CalloutResult.CONTINUE;
    +            }
    +
    +            @Override
    +            public void unwind(Object token) {
    +            }
    +        });
    +
    +        assertEquals(0, matcher.search(0, input.length, Option.NONE));
    +        assertEquals(6, matcher.search(matcher.getEnd(), input.length, Option.NONE));
    +        assertEquals(Arrays.asList(2, 3, 6, 8, 9), positions);
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerl.java b/third_party/joni/test/org/joni/test/TestPerl.java
    index 708ab071d9..51802eff4a 100755
    --- a/third_party/joni/test/org/joni/test/TestPerl.java
    +++ b/third_party/joni/test/org/joni/test/TestPerl.java
    @@ -74,6 +74,14 @@ public void test() throws Exception {
             xerrs("(?PXfoo)", "Sequence (?PX...) not recognized");
             xerrs("(?P)]", "z");
             x2s("\\(\\?P", "(?P", 0, 6);
             x2s("a(*pla:b)b", "ab", 0, 2);
    diff --git a/third_party/joni/test/org/joni/test/TestPerlAdapterRetirement.java b/third_party/joni/test/org/joni/test/TestPerlAdapterRetirement.java
    new file mode 100644
    index 0000000000..9ab41b663e
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlAdapterRetirement.java
    @@ -0,0 +1,101 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.joni.constants.SyntaxProperties.OP2_OPTION_PERL;
    +import static org.joni.constants.SyntaxProperties.OP2_OPTION_RUBY;
    +import static org.joni.constants.SyntaxProperties.OP3_PERL_LITERAL_OPEN_IN_CC;
    +import static org.joni.constants.SyntaxProperties.OP_POSIX_BRACKET;
    +import static org.junit.Assert.assertEquals;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.ASCIIEncoding;
    +import org.joni.Matcher;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.junit.Test;
    +
    +public class TestPerlAdapterRetirement {
    +    private static final Syntax PERL_LITERAL_CLASS = new Syntax(
    +            "PerlLiteralClass", Syntax.RUBY.op | OP_POSIX_BRACKET,
    +            (Syntax.RUBY.op2 & ~OP2_OPTION_RUBY) | OP2_OPTION_PERL,
    +            Syntax.RUBY.op3 | OP3_PERL_LITERAL_OPEN_IN_CC,
    +            Syntax.RUBY.behavior, Syntax.RUBY.options,
    +            Syntax.RUBY.metaCharTable);
    +
    +    private static Matcher matcher(String pattern, String input, int options) {
    +        return matcher(pattern, input, options, PERL_LITERAL_CLASS);
    +    }
    +
    +    private static Matcher matcher(String pattern, String input, int options, Syntax syntax) {
    +        byte[] patternBytes = pattern.getBytes(StandardCharsets.US_ASCII);
    +        byte[] inputBytes = input.getBytes(StandardCharsets.US_ASCII);
    +        Regex regex = new Regex(patternBytes, 0, patternBytes.length, options,
    +                ASCIIEncoding.INSTANCE, syntax);
    +        return regex.matcher(inputBytes);
    +    }
    +
    +    private static int search(String pattern, String input, int options) {
    +        return matcher(pattern, input, options).search(0, input.length(), Option.NONE);
    +    }
    +
    +    @Test
    +    public void abbreviatedMarkPublishesItsName() {
    +        Matcher matcher = matcher("(*:seen)a", "a", Option.NONE);
    +        assertEquals(0, matcher.search(0, 1, Option.NONE));
    +        assertEquals("seen", matcher.getControlMark());
    +    }
    +
    +    @Test
    +    public void ordinaryPerlClassTreatsNestedOpenBracketAsLiteral() {
    +        assertEquals(0, search("[a[]", "[", Option.NONE));
    +        assertEquals(0, search("[a[]", "a", Option.NONE));
    +        assertEquals(0, search("[[:]+", "[", Option.NONE));
    +        assertEquals(0, search("[a[:]b[:c]", "abc", Option.NONE));
    +        assertEquals(0, search("[[:alpha:]]", "a", Option.NONE));
    +        assertEquals(0, search("[[:dgit:foo]]", "d]", Option.NONE));
    +        assertEquals(-1, search("[[:dgit:foo]]", "a]", Option.NONE));
    +    }
    +
    +    @Test
    +    public void rubyClassSetSemanticsRemainAvailable() {
    +        assertEquals(0, matcher("[[a]b]", "a", Option.NONE, Syntax.RUBY)
    +                .search(0, 1, Option.NONE));
    +        assertEquals(0, matcher("[[a]b]", "b", Option.NONE, Syntax.RUBY)
    +                .search(0, 1, Option.NONE));
    +    }
    +
    +    @Test
    +    public void extendMoreClassWhitespaceIsNativeAndScoped() {
    +        int xx = Option.EXTEND | Option.PERL_EXTEND_MORE;
    +        assertEquals(-1, search("[a b]", " ", xx));
    +        assertEquals(0, search("[a\\ b]", " ", xx));
    +        assertEquals(-1, search("(?xx:[a b])", " ", Option.NONE));
    +        assertEquals(0, search("(?x:[a b])", " ", Option.NONE));
    +        assertEquals(0, search("(?-x:[a b])", " ", xx));
    +    }
    +
    +    @Test
    +    public void emptyPerlGroupIsZeroWidth() {
    +        assertEquals(0, search("(?)a", "a", Option.NONE));
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlAdjacentMultiFold.java b/third_party/joni/test/org/joni/test/TestPerlAdjacentMultiFold.java
    index f88d45cc97..46a91d9b2a 100644
    --- a/third_party/joni/test/org/joni/test/TestPerlAdjacentMultiFold.java
    +++ b/third_party/joni/test/org/joni/test/TestPerlAdjacentMultiFold.java
    @@ -44,4 +44,9 @@ public void repartitionsAdjacentSharpSFolds() {
             assertEquals(0, search("\u00dfs", "s\u00df"));
             assertEquals(-1, search("s\u00df", "\u00dfx"));
         }
    +
    +    @Test
    +    public void foldsVariableWidthPerlBackreferences() {
    +        assertEquals(0, search("^(?\u212a)\\k$", "\u212aK"));
    +    }
     }
    diff --git a/third_party/joni/test/org/joni/test/TestPerlBoundaryPolicy.java b/third_party/joni/test/org/joni/test/TestPerlBoundaryPolicy.java
    new file mode 100644
    index 0000000000..d8b7b27b5b
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlBoundaryPolicy.java
    @@ -0,0 +1,76 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +
    +import java.nio.charset.StandardCharsets;
    +import java.util.ArrayList;
    +import java.util.Arrays;
    +import java.util.List;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.joni.WarnCallback;
    +import org.junit.Test;
    +
    +public class TestPerlBoundaryPolicy {
    +    private record Warning(String message, int position) {}
    +
    +    private static List warnings(String pattern, int option) {
    +        byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        List warnings = new ArrayList<>();
    +        new Regex(bytes, 0, bytes.length, option, UTF8Encoding.INSTANCE,
    +                Syntax.PerlNG, new WarnCallback() {
    +                    @Override
    +                    public void warn(String message) {
    +                        warnings.add(new Warning(message, -1));
    +                    }
    +
    +                    @Override
    +                    public void warn(String message, int bytePosition) {
    +                        warnings.add(new Warning(message, bytePosition));
    +                    }
    +
    +                    @Override
    +                    public boolean supportsPositions() {
    +                        return true;
    +                    }
    +                });
    +        return warnings;
    +    }
    +
    +    @Test
    +    public void acceptsTheShortGraphemeBoundaryAlias() {
    +        assertEquals(List.of(), warnings("\\b{g}", Option.NONE));
    +    }
    +
    +    @Test
    +    public void warnsWhenUnicodeBoundariesOverrideAsciiMode() {
    +        assertEquals(Arrays.asList(new Warning(
    +                "Using /u for '\\b{g}' instead of /a", 5)),
    +                warnings("\\b{g}", Option.ASCII_RANGE | Option.PERL_EXPLICIT_ASCII));
    +        assertEquals(Arrays.asList(new Warning(
    +                "Using /u for '\\B{gcb}' instead of /a", 7)),
    +                warnings("\\B{gcb}", Option.ASCII_RANGE | Option.PERL_EXPLICIT_ASCII));
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlBranchResetNamedCall.java b/third_party/joni/test/org/joni/test/TestPerlBranchResetNamedCall.java
    index 102c490a87..a36a2a2f93 100644
    --- a/third_party/joni/test/org/joni/test/TestPerlBranchResetNamedCall.java
    +++ b/third_party/joni/test/org/joni/test/TestPerlBranchResetNamedCall.java
    @@ -70,6 +70,20 @@ public void namedBranchResetCallTargetsLeftmostPhysicalGroup() {
             assertDoesNotMatch(pattern, "22");
         }
     
    +    @Test
    +    public void distinctNamedBranchResetCallsUseTheirOwnPhysicalDefinitions() {
    +        String pattern = "(?|(?a)|(?b))\\1\\g\\g";
    +        assertMatches(pattern, "bbab");
    +    }
    +
    +    @Test
    +    public void distinctNamedBranchResetConditionsUsePhysicalDefinitions() {
    +        String pattern = "(?|(?a)|(?b))(?()x|y)\\1";
    +        assertMatches(pattern, "byb");
    +        assertDoesNotMatch(pattern, "bxb");
    +        assertMatches(pattern, "axa");
    +    }
    +
         @Test
         public void numericBranchResetCallTargetsLeftmostPhysicalGroup() {
             String pattern = "(?|(1)|(2))\\g<1>";
    diff --git a/third_party/joni/test/org/joni/test/TestPerlByteClassFoldPolicy.java b/third_party/joni/test/org/joni/test/TestPerlByteClassFoldPolicy.java
    new file mode 100644
    index 0000000000..e835e8c4ba
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlByteClassFoldPolicy.java
    @@ -0,0 +1,120 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.ISO8859_1Encoding;
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.CharacterPropertyResolver;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.junit.Test;
    +
    +public class TestPerlByteClassFoldPolicy {
    +    private static final int[] LOWERCASE_RANGES = {
    +        3, 'a', 'z', 0xdf, 0xdf, 0xe0, 0xe0
    +    };
    +    private static final int[] UPPERCASE_RANGES = {
    +        2, 'A', 'Z', 0xc0, 0xc0
    +    };
    +    private static final int[] HEX_RANGES = {
    +        3, '0', '9', 'A', 'F', 'a', 'f'
    +    };
    +
    +    private static final CharacterPropertyResolver PROPERTY_RESOLVER =
    +            (bytes, p, end, encoding, inCharacterClass) -> {
    +                String name = new String(bytes, p, end - p,
    +                        StandardCharsets.ISO_8859_1);
    +                if ("Lowercase".equals(name)) {
    +                    return new CharacterPropertyResolver.Result(
    +                            LOWERCASE_RANGES, true);
    +                }
    +                if ("Uppercase".equals(name)) {
    +                    return new CharacterPropertyResolver.Result(
    +                            UPPERCASE_RANGES, true);
    +                }
    +                if ("Hex_Digit".equals(name)) {
    +                    return new CharacterPropertyResolver.Result(
    +                            HEX_RANGES, true);
    +                }
    +                return null;
    +            };
    +
    +    private static final Syntax PERL_SYNTAX = new Syntax(
    +            "PerlByteClassFoldPolicy", Syntax.PerlNG.op, Syntax.PerlNG.op2,
    +            Syntax.PerlNG.op3, Syntax.PerlNG.behavior, Syntax.PerlNG.options,
    +            Syntax.PerlNG.metaCharTable, null, PROPERTY_RESOLVER);
    +
    +    private static int searchByte(String pattern, String input) {
    +        byte[] patternBytes = pattern.getBytes(StandardCharsets.ISO_8859_1);
    +        byte[] inputBytes = input.getBytes(StandardCharsets.ISO_8859_1);
    +        Regex regex = new Regex(patternBytes, 0, patternBytes.length,
    +                Option.IGNORECASE | Option.PERL_BYTE_PATTERN,
    +                ISO8859_1Encoding.INSTANCE, PERL_SYNTAX);
    +        return regex.matcher(inputBytes).search(0, inputBytes.length, Option.NONE);
    +    }
    +
    +    private static int searchUnicode(String pattern, String input) {
    +        byte[] patternBytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        byte[] inputBytes = input.getBytes(StandardCharsets.UTF_8);
    +        Regex regex = new Regex(patternBytes, 0, patternBytes.length,
    +                Option.IGNORECASE, UTF8Encoding.INSTANCE, PERL_SYNTAX);
    +        return regex.matcher(inputBytes).search(0, inputBytes.length, Option.NONE);
    +    }
    +
    +    @Test
    +    public void byteClassesFoldAsciiButNotLatinOne() {
    +        assertEquals(-1, searchByte("^[\u00e0_]$", "\u00c0"));
    +        assertEquals(0, searchByte("^[^\u00e0]$", "\u00c0"));
    +        assertEquals(0, searchByte("^[a_]$", "A"));
    +        assertEquals(-1, searchByte("^[\u00df_]$", "ss"));
    +        assertEquals(0, searchByte("^\\p{Lowercase}$", "\u00c0"));
    +        assertEquals(0, searchByte("^[\\p{Lowercase}_]$", "\u00c0"));
    +        assertEquals(-1, searchByte("^[^\\p{Lowercase}]$", "\u00c0"));
    +        assertEquals(-1, searchByte("^\\P{Lowercase}$", "\u00c0"));
    +        assertEquals(-1, searchByte("^[\\P{Lowercase}_]$", "\u00c0"));
    +        assertEquals(0, searchByte("^\\p{Lowercase}$", "ss"));
    +        assertEquals(0, searchByte(
    +                "^(?[ \\p{Lowercase} & [\u00e0] ])$", "\u00c0"));
    +        assertEquals(0, searchByte(
    +                "^(?[ \\p{Lowercase} - [a] ])$", "\u00c0"));
    +        assertEquals(-1, searchByte(
    +                "^(?[ [\u00e0] - \\p{Uppercase} ])$", "\u00c0"));
    +        assertEquals(0, searchByte(
    +                "^(?[ ([\u00e0] + \\p{Hex_Digit})"
    +                        + " - \\p{Hex_Digit} ])$", "\u00e0"));
    +        assertEquals(0, searchByte(
    +                "^(?[ ([\u00e0] + \\p{Hex_Digit})"
    +                        + " - \\p{Hex_Digit} ])$", "\u00c0"));
    +    }
    +
    +    @Test
    +    public void unicodeClassesRetainLatinOneAndAboveByteFolds() {
    +        assertEquals(0, searchUnicode("^[\u00e0_]$", "\u00c0"));
    +        assertEquals(-1, searchUnicode("^[^\u00e0]$", "\u00c0"));
    +        assertEquals(0, searchUnicode("^[\u00df_]$", "ss"));
    +        assertEquals(0, searchUnicode("^[\u0178_]$", "\u00ff"));
    +        assertEquals(0, searchUnicode("^[\u212a_]$", "K"));
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlBytePatternCaseFold.java b/third_party/joni/test/org/joni/test/TestPerlBytePatternCaseFold.java
    index b3886985f9..289f0f258c 100644
    --- a/third_party/joni/test/org/joni/test/TestPerlBytePatternCaseFold.java
    +++ b/third_party/joni/test/org/joni/test/TestPerlBytePatternCaseFold.java
    @@ -63,4 +63,19 @@ public void asciiStrictPropertyClosureRetainsUnicodePropertyMembership() {
                     UTF8Encoding.INSTANCE, Syntax.PerlNG);
             assertEquals(0, regex.matcher(kelvin).search(0, kelvin.length, Option.NONE));
         }
    +
    +    @Test
    +    public void scopedCharsetCaseFoldUsesTheUtf8Variant() {
    +        byte[] pattern = "(?u:\\xC0)".getBytes(StandardCharsets.UTF_8);
    +        byte[] lower = "\u00e0".getBytes(StandardCharsets.UTF_8);
    +        Regex regex = new Regex(pattern, 0, pattern.length, Option.IGNORECASE,
    +                UTF8Encoding.INSTANCE, Syntax.PerlNG);
    +
    +        assertEquals(0, regex.matcher(lower).search(0, lower.length, Option.NONE));
    +
    +        pattern = "(?aa:\\xC0)".getBytes(StandardCharsets.UTF_8);
    +        regex = new Regex(pattern, 0, pattern.length, Option.IGNORECASE,
    +                UTF8Encoding.INSTANCE, Syntax.PerlNG);
    +        assertEquals(0, regex.matcher(lower).search(0, lower.length, Option.NONE));
    +    }
     }
    diff --git a/third_party/joni/test/org/joni/test/TestPerlBytePosixClass.java b/third_party/joni/test/org/joni/test/TestPerlBytePosixClass.java
    new file mode 100644
    index 0000000000..b25ed7488c
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlBytePosixClass.java
    @@ -0,0 +1,56 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.ISO8859_1Encoding;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.junit.Test;
    +
    +public class TestPerlBytePosixClass {
    +    private static int search(String pattern, int input) {
    +        byte[] patternBytes = pattern.getBytes(StandardCharsets.ISO_8859_1);
    +        byte[] inputBytes = {(byte) input};
    +        Regex regex = new Regex(patternBytes, 0, patternBytes.length,
    +                Option.PERL_BYTE_PATTERN, ISO8859_1Encoding.INSTANCE,
    +                Syntax.PerlNG);
    +        return regex.matcher(inputBytes).search(
    +                0, inputBytes.length, Option.NONE);
    +    }
    +
    +    @Test
    +    public void negatedAsciiPosixClassIncludesHighBytes() {
    +        assertEquals(-1, search("[[:^ascii:]]", 0x7f));
    +        assertEquals(0, search("[[:^ascii:]]", 0x80));
    +        assertEquals(0, search("[[:^ascii:]]", 0xff));
    +    }
    +
    +    @Test
    +    public void positiveAsciiPosixClassExcludesHighBytes() {
    +        assertEquals(0, search("[[:ascii:]]", 0x7f));
    +        assertEquals(-1, search("[[:ascii:]]", 0x80));
    +        assertEquals(-1, search("[[:ascii:]]", 0xff));
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlCalloutCommittedCapture.java b/third_party/joni/test/org/joni/test/TestPerlCalloutCommittedCapture.java
    new file mode 100644
    index 0000000000..b1aab90dfe
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlCalloutCommittedCapture.java
    @@ -0,0 +1,73 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +import static org.junit.Assert.assertTrue;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.ASCIIEncoding;
    +import org.joni.CalloutHandler;
    +import org.joni.CalloutResult;
    +import org.joni.MatchView;
    +import org.joni.Matcher;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.junit.Test;
    +
    +public class TestPerlCalloutCommittedCapture {
    +    @Test
    +    public void committedCapturesSurviveSearchCandidateCallouts() {
    +        String source = "()([A-Za-z][A-Za-z ]*)(?{=CALL:1}), "
    +                + "(\\d+)(?{=CALL:2}) years old, secret number (\\d+)";
    +        byte[] pattern = source.getBytes(StandardCharsets.US_ASCII);
    +        Regex regex = new Regex(pattern, 0, pattern.length, Option.NONE,
    +                ASCIIEncoding.INSTANCE, Syntax.PerlNG);
    +        byte[] input = ("Jim Jones, 35 years old, secret wombat 007. "
    +                + "John Smith, 42 years old, secret number 36")
    +                .getBytes(StandardCharsets.US_ASCII);
    +        Matcher matcher = regex.matcher(input);
    +        matcher.setCalloutHandler(new CalloutHandler() {
    +            @Override
    +            public CalloutResult execute(int id, MatchView match) {
    +                return CalloutResult.CONTINUE;
    +            }
    +
    +            @Override
    +            public void unwind(Object token) {
    +            }
    +        });
    +
    +        int result = matcher.search(0, input.length, Option.NONE);
    +        assertTrue(result > 0);
    +        assertEquals(result, matcher.captureBegin(1));
    +        assertEquals(result, matcher.captureEnd(1));
    +        assertEquals("John Smith", capture(input, matcher, 2));
    +        assertEquals("42", capture(input, matcher, 3));
    +    }
    +
    +    private static String capture(byte[] input, Matcher matcher, int group) {
    +        int begin = matcher.captureBegin(group);
    +        int end = matcher.captureEnd(group);
    +        return new String(input, begin, end - begin, StandardCharsets.US_ASCII);
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlCalloutReentrantMatcher.java b/third_party/joni/test/org/joni/test/TestPerlCalloutReentrantMatcher.java
    new file mode 100644
    index 0000000000..2db49f56ba
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlCalloutReentrantMatcher.java
    @@ -0,0 +1,83 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +import static org.junit.Assert.assertTrue;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.ASCIIEncoding;
    +import org.joni.CalloutHandler;
    +import org.joni.CalloutResult;
    +import org.joni.MatchView;
    +import org.joni.Matcher;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.junit.Test;
    +
    +public class TestPerlCalloutReentrantMatcher {
    +    @Test
    +    public void nestedMatcherDoesNotOverwriteCallerCaptures() {
    +        Regex outer = regex("()([A-Za-z][A-Za-z ]*)(?{=CALL:1}), "
    +                + "(\\d+)(?{=CALL:2}) years old, secret number (\\d+)"
    +                + "(?{=CALL:3})");
    +        Regex nested = regex("(x)");
    +        byte[] input = ("Jim Jones, 35 years old, secret wombat 007. "
    +                + "John Smith, 42 years old, secret number 36")
    +                .getBytes(StandardCharsets.US_ASCII);
    +        Matcher matcher = outer.matcher(input);
    +        matcher.setCalloutHandler(new CalloutHandler() {
    +            @Override
    +            public CalloutResult execute(int id, MatchView match) {
    +                if (id == 3) {
    +                    byte[] nestedInput = "x".getBytes(StandardCharsets.US_ASCII);
    +                    assertEquals(0, nested.matcher(nestedInput)
    +                            .search(0, nestedInput.length, Option.NONE));
    +                }
    +                return CalloutResult.CONTINUE;
    +            }
    +
    +            @Override
    +            public void unwind(Object token) {
    +            }
    +        });
    +
    +        int result = matcher.search(0, input.length, Option.NONE);
    +        assertTrue(result > 0);
    +        assertEquals(result, matcher.captureBegin(1));
    +        assertEquals(result, matcher.captureEnd(1));
    +        assertEquals("John Smith", capture(input, matcher, 2));
    +        assertEquals("42", capture(input, matcher, 3));
    +    }
    +
    +    private static Regex regex(String source) {
    +        byte[] pattern = source.getBytes(StandardCharsets.US_ASCII);
    +        return new Regex(pattern, 0, pattern.length, Option.NONE,
    +                ASCIIEncoding.INSTANCE, Syntax.PerlNG);
    +    }
    +
    +    private static String capture(byte[] input, Matcher matcher, int group) {
    +        int begin = matcher.captureBegin(group);
    +        int end = matcher.captureEnd(group);
    +        return new String(input, begin, end - begin, StandardCharsets.US_ASCII);
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlCommentGroupDiagnostics.java b/third_party/joni/test/org/joni/test/TestPerlCommentGroupDiagnostics.java
    new file mode 100644
    index 0000000000..62c2dc3175
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlCommentGroupDiagnostics.java
    @@ -0,0 +1,53 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +import static org.junit.Assert.fail;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.joni.WarnCallback;
    +import org.joni.exception.SyntaxException;
    +import org.junit.Test;
    +
    +public class TestPerlCommentGroupDiagnostics {
    +    private static void assertUnterminated(String pattern) {
    +        byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        try {
    +            new Regex(bytes, 0, bytes.length, Option.NONE, UTF8Encoding.INSTANCE,
    +                    Syntax.PerlNG, WarnCallback.NONE);
    +            fail("expected unterminated Perl comment group for " + pattern);
    +        } catch (SyntaxException error) {
    +            assertEquals("Sequence (?#... not terminated", error.getMessage());
    +        }
    +    }
    +
    +    @Test
    +    public void reportsUnterminatedCommentGroups() {
    +        assertUnterminated("x(?#");
    +        assertUnterminated("x(?#:");
    +        assertUnterminated("(?#abc");
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlControlEscapeWarnings.java b/third_party/joni/test/org/joni/test/TestPerlControlEscapeWarnings.java
    new file mode 100644
    index 0000000000..f34c867cbf
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlControlEscapeWarnings.java
    @@ -0,0 +1,54 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +
    +import java.nio.charset.StandardCharsets;
    +import java.util.ArrayList;
    +import java.util.List;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.joni.WarnCallback;
    +import org.junit.Test;
    +
    +public class TestPerlControlEscapeWarnings {
    +    private static void assertEscape(String pattern, String input, String warning) {
    +        List warnings = new ArrayList<>();
    +        byte[] patternBytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        Regex regex = new Regex(patternBytes, 0, patternBytes.length, Option.NONE,
    +                UTF8Encoding.INSTANCE, Syntax.PerlNG, warnings::add);
    +        byte[] inputBytes = input.getBytes(StandardCharsets.UTF_8);
    +        assertEquals(0, regex.matcher(inputBytes)
    +                .search(0, inputBytes.length, Option.NONE));
    +        assertEquals(List.of(warning), warnings);
    +    }
    +
    +    @Test
    +    public void warnsForObscureControlSpellingsAndKeepsPerlValues() {
    +        assertEscape("\\c`", " ",
    +                "\"\\c`\" is more clearly written simply as \"\\ \"");
    +        assertEscape("\\c1", "q",
    +                "\"\\c1\" is more clearly written simply as \"q\"");
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlDynamicExecution.java b/third_party/joni/test/org/joni/test/TestPerlDynamicExecution.java
    new file mode 100644
    index 0000000000..acfd797242
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlDynamicExecution.java
    @@ -0,0 +1,188 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +
    +import java.nio.charset.StandardCharsets;
    +import java.util.ArrayList;
    +import java.util.Arrays;
    +import java.util.List;
    +
    +import org.jcodings.specific.ASCIIEncoding;
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.CalloutHandler;
    +import org.joni.CalloutResult;
    +import org.joni.DynamicPatternResult;
    +import org.joni.MatchView;
    +import org.joni.Matcher;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.junit.Test;
    +
    +public class TestPerlDynamicExecution {
    +    private static Regex regex(String pattern) {
    +        byte[] bytes = pattern.getBytes(StandardCharsets.US_ASCII);
    +        return new Regex(bytes, 0, bytes.length, Option.NONE,
    +                ASCIIEncoding.INSTANCE, Syntax.RUBY);
    +    }
    +
    +    @Test
    +    public void nestedAlternativesResolveTokensOnlyWhenTheOuterPathCommits() {
    +        List events = new ArrayList<>();
    +        Regex outer = regex("\\A(?{=DYNAMIC:1})b\\z");
    +        Regex nested = regex("ab(?{=CALL:2})|a(?{=CALL:3})");
    +        CalloutHandler nestedHandler = new CalloutHandler() {
    +            @Override
    +            public CalloutResult execute(int id, MatchView match) {
    +                events.add("nested-execute:" + id);
    +                return CalloutResult.continueWith("nested-" + id);
    +            }
    +
    +            @Override
    +            public void unwind(Object token) {
    +                events.add("nested-unwind:" + token);
    +            }
    +
    +            @Override
    +            public void complete(Object token) {
    +                events.add("nested-complete:" + token);
    +            }
    +
    +            @Override
    +            public void finish(boolean matched) {
    +                events.add("nested-finish:" + matched);
    +            }
    +        };
    +        CalloutHandler outerHandler = new CalloutHandler() {
    +            @Override
    +            public CalloutResult execute(int id, MatchView match) {
    +                throw new AssertionError("plain outer callout not expected");
    +            }
    +
    +            @Override
    +            public DynamicPatternResult executeDynamic(int id, MatchView match) {
    +                events.add("dynamic:" + id);
    +                return new DynamicPatternResult(nested, nestedHandler, "outer-dynamic");
    +            }
    +
    +            @Override
    +            public void unwind(Object token) {
    +                events.add("outer-unwind:" + token);
    +            }
    +
    +            @Override
    +            public void complete(Object token) {
    +                events.add("outer-complete:" + token);
    +            }
    +
    +        };
    +
    +        byte[] input = "ab".getBytes(StandardCharsets.US_ASCII);
    +        Matcher matcher = outer.matcher(input);
    +        matcher.setCalloutHandler(outerHandler);
    +
    +        assertEquals(0, matcher.search(0, input.length, Option.NONE));
    +        assertEquals(Arrays.asList(
    +                "dynamic:1",
    +                "nested-execute:2",
    +                "nested-unwind:nested-2",
    +                "nested-execute:3",
    +                "nested-complete:nested-3",
    +                "nested-finish:true",
    +                "outer-complete:outer-dynamic"), events);
    +    }
    +
    +    @Test
    +    public void nestedPatternRetainsAsciiStrictCaseFoldOption() {
    +        byte[] outerBytes = "\\A(?{=DYNAMIC:1})\\z".getBytes(StandardCharsets.UTF_8);
    +        Regex outer = new Regex(outerBytes, 0, outerBytes.length, Option.NONE,
    +                UTF8Encoding.INSTANCE, Syntax.RUBY);
    +        byte[] nestedBytes = "s".getBytes(StandardCharsets.UTF_8);
    +        Regex nested = new Regex(nestedBytes, 0, nestedBytes.length,
    +                Option.IGNORECASE | Option.PERL_ASCII_STRICT,
    +                UTF8Encoding.INSTANCE, Syntax.PerlNG);
    +        CalloutHandler handler = new CalloutHandler() {
    +            @Override
    +            public CalloutResult execute(int id, MatchView match) {
    +                throw new AssertionError("plain callout not expected");
    +            }
    +
    +            @Override
    +            public DynamicPatternResult executeDynamic(int id, MatchView match) {
    +                return new DynamicPatternResult(nested, null, null);
    +            }
    +
    +            @Override
    +            public void unwind(Object token) {
    +            }
    +        };
    +
    +        byte[] input = "\u017f".getBytes(StandardCharsets.UTF_8);
    +        Matcher matcher = outer.matcher(input);
    +        matcher.setCalloutHandler(handler);
    +        assertEquals(-1, matcher.search(0, input.length, Option.NONE));
    +    }
    +
    +    @Test
    +    public void destructiveControlsCommitCalloutsButMarkDoesNot() {
    +        String[] committing = {"FAIL", "PRUNE)(*FAIL", "SKIP)(*FAIL",
    +                "THEN)(*FAIL", "COMMIT)(*FAIL"};
    +        for (String control : committing) {
    +            List events = new ArrayList<>();
    +            Regex pattern = regex("a(?{=CALL:1})(*" + control + ")");
    +            assertEquals(-1, search(pattern, "a", recordingHandler(events)));
    +            assertEquals(control, Arrays.asList("execute:1", "complete:1"), events);
    +        }
    +
    +        List markEvents = new ArrayList<>();
    +        Regex mark = regex("a(?{=CALL:1})(*MARK:seen)b");
    +        assertEquals(-1, search(mark, "a", recordingHandler(markEvents)));
    +        assertEquals(Arrays.asList("execute:1", "unwind:1"), markEvents);
    +    }
    +
    +    private static int search(Regex regex, String input, CalloutHandler handler) {
    +        byte[] bytes = input.getBytes(StandardCharsets.US_ASCII);
    +        Matcher matcher = regex.matcher(bytes);
    +        matcher.setCalloutHandler(handler);
    +        return matcher.search(0, bytes.length, Option.NONE);
    +    }
    +
    +    private static CalloutHandler recordingHandler(List events) {
    +        return new CalloutHandler() {
    +            @Override
    +            public CalloutResult execute(int id, MatchView match) {
    +                events.add("execute:" + id);
    +                return CalloutResult.continueWith(id);
    +            }
    +
    +            @Override
    +            public void unwind(Object token) {
    +                events.add("unwind:" + token);
    +            }
    +
    +            @Override
    +            public void complete(Object token) {
    +                events.add("complete:" + token);
    +            }
    +        };
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlEmptyVerbDiagnostics.java b/third_party/joni/test/org/joni/test/TestPerlEmptyVerbDiagnostics.java
    new file mode 100644
    index 0000000000..f213d0a1b5
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlEmptyVerbDiagnostics.java
    @@ -0,0 +1,52 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +import static org.junit.Assert.fail;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.joni.WarnCallback;
    +import org.joni.exception.ValueException;
    +import org.junit.Test;
    +
    +public class TestPerlEmptyVerbDiagnostics {
    +    private static void assertEmptyVerb(String pattern) {
    +        byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        try {
    +            new Regex(bytes, 0, bytes.length, Option.NONE, UTF8Encoding.INSTANCE,
    +                    Syntax.PerlNG, WarnCallback.NONE);
    +            fail("expected empty Perl verb failure for " + pattern);
    +        } catch (ValueException error) {
    +            assertEquals("Unknown verb pattern ''", error.getMessage());
    +        }
    +    }
    +
    +    @Test
    +    public void reportsEmptyVerbPatterns() {
    +        assertEmptyVerb("(*)");
    +        assertEmptyVerb("(*)b");
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlExtendedCharacterClassLiteralBoundary.java b/third_party/joni/test/org/joni/test/TestPerlExtendedCharacterClassLiteralBoundary.java
    new file mode 100644
    index 0000000000..fb256ade76
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlExtendedCharacterClassLiteralBoundary.java
    @@ -0,0 +1,54 @@
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.junit.Test;
    +
    +import static org.joni.constants.SyntaxProperties.ALLOW_MULTIPLEX_DEFINITION_NAME_CALL;
    +import static org.joni.constants.SyntaxProperties.OP2_ESC_H_HORIZONTAL_WHITESPACE;
    +import static org.joni.constants.SyntaxProperties.OP2_OPTION_PERL;
    +import static org.joni.constants.SyntaxProperties.OP2_OPTION_RUBY;
    +import static org.joni.constants.SyntaxProperties.OP2_PLUS_POSSESSIVE_INTERVAL;
    +import static org.joni.constants.SyntaxProperties.OP_POSIX_BRACKET;
    +
    +public class TestPerlExtendedCharacterClassLiteralBoundary {
    +    private static final Syntax SYNTAX = new Syntax(
    +            "PerlExtendedCharacterClassLiteralBoundary", Syntax.RUBY.op | OP_POSIX_BRACKET,
    +            (Syntax.RUBY.op2 & ~OP2_OPTION_RUBY) | OP2_OPTION_PERL
    +                    | OP2_PLUS_POSSESSIVE_INTERVAL | OP2_ESC_H_HORIZONTAL_WHITESPACE,
    +            Syntax.RUBY.op3,
    +            Syntax.RUBY.behavior | ALLOW_MULTIPLEX_DEFINITION_NAME_CALL,
    +            Syntax.RUBY.options & ~(Option.ASCII_RANGE
    +                    | Option.POSIX_BRACKET_ALL_RANGE | Option.WORD_BOUND_ALL_RANGE),
    +            Syntax.RUBY.metaCharTable);
    +
    +    private static int search(String pattern, String input) {
    +        byte[] patternBytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        Regex regex = new Regex(patternBytes, 0, patternBytes.length, Option.NONE,
    +                UTF8Encoding.INSTANCE, SYNTAX);
    +        byte[] inputBytes = input.getBytes(StandardCharsets.UTF_8);
    +        return regex.matcher(inputBytes).search(0, inputBytes.length, Option.NONE);
    +    }
    +
    +    @Test
    +    public void acceptsLeadingLiteralCloseBracketInsideNestedClass() {
    +        String pattern = "(?[ [^][ \\\\ ] ])";
    +        assertEquals(0, search(pattern, "A"));
    +        assertEquals(-1, search(pattern, "]"));
    +        assertEquals(-1, search(pattern, "["));
    +        assertEquals(-1, search(pattern, "\\"));
    +        assertEquals(0, search("(?[ [a[] ])", "["));
    +        assertEquals(0, search("(?[ [[] ])", "["));
    +        assertEquals(0, search("(?[ [:ascii:] ])", "A"));
    +        assertEquals(0, search("(?[ [:graph:] ])", "A"));
    +        assertEquals(0, search("(?[ [:ascii:] & [:graph:] ])", "A"));
    +        assertEquals(0, search(
    +                "(?[ [:ascii:] & [:graph:] & [^][ \\\\ ] ])", "A"));
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlExtendedCharacterClassMissingOperatorDiagnostics.java b/third_party/joni/test/org/joni/test/TestPerlExtendedCharacterClassMissingOperatorDiagnostics.java
    new file mode 100644
    index 0000000000..943d644113
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlExtendedCharacterClassMissingOperatorDiagnostics.java
    @@ -0,0 +1,51 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +import static org.junit.Assert.assertThrows;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.joni.WarnCallback;
    +import org.joni.exception.SyntaxException;
    +import org.junit.Test;
    +
    +public class TestPerlExtendedCharacterClassMissingOperatorDiagnostics {
    +    private static SyntaxException error(String pattern) {
    +        byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        return assertThrows(SyntaxException.class,
    +                () -> new Regex(bytes, 0, bytes.length, Option.NONE,
    +                        UTF8Encoding.INSTANCE, Syntax.PerlNG, WarnCallback.NONE));
    +    }
    +
    +    @Test
    +    public void diagnosesOperandsAndParenthesesWithoutOperators() {
    +        assertEquals("Operand with no preceding operator",
    +                error("(?[ \\cK \\t ])").getMessage());
    +        assertEquals("Unexpected '(' with no preceding operator",
    +                error("(?[ \\cK ( \\t ) ])").getMessage());
    +        assertEquals("Unexpected ')'", error("(?[ \\cK + ) ])").getMessage());
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlExtendedCharacterClassOperatorDiagnostics.java b/third_party/joni/test/org/joni/test/TestPerlExtendedCharacterClassOperatorDiagnostics.java
    new file mode 100644
    index 0000000000..539f242a82
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlExtendedCharacterClassOperatorDiagnostics.java
    @@ -0,0 +1,46 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +import static org.junit.Assert.assertThrows;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.joni.WarnCallback;
    +import org.joni.exception.SyntaxException;
    +import org.junit.Test;
    +
    +public class TestPerlExtendedCharacterClassOperatorDiagnostics {
    +    @Test
    +    public void binaryOperatorWithoutLeftOperandUsesPerlDiagnostic() {
    +        byte[] bytes = "(?[ + \\t ])".getBytes(StandardCharsets.UTF_8);
    +        SyntaxException error = assertThrows(SyntaxException.class,
    +                () -> new Regex(bytes, 0, bytes.length, Option.NONE,
    +                        UTF8Encoding.INSTANCE, Syntax.PerlNG, WarnCallback.NONE));
    +        assertEquals("Unexpected binary operator '+' with no preceding operand",
    +                error.getMessage());
    +        assertEquals(5, error.getPatternPosition());
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlExtendedCharacterClassWhitespaceEscape.java b/third_party/joni/test/org/joni/test/TestPerlExtendedCharacterClassWhitespaceEscape.java
    new file mode 100644
    index 0000000000..44f7b78a1f
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlExtendedCharacterClassWhitespaceEscape.java
    @@ -0,0 +1,64 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.junit.Test;
    +
    +import static org.joni.constants.SyntaxProperties.ALLOW_MULTIPLEX_DEFINITION_NAME_CALL;
    +import static org.joni.constants.SyntaxProperties.OP2_ESC_H_HORIZONTAL_WHITESPACE;
    +import static org.joni.constants.SyntaxProperties.OP2_OPTION_PERL;
    +import static org.joni.constants.SyntaxProperties.OP2_OPTION_RUBY;
    +import static org.joni.constants.SyntaxProperties.OP2_PLUS_POSSESSIVE_INTERVAL;
    +import static org.joni.constants.SyntaxProperties.OP_POSIX_BRACKET;
    +
    +public class TestPerlExtendedCharacterClassWhitespaceEscape {
    +    private static final Syntax SYNTAX = new Syntax(
    +            "PerlExtendedCharacterClassWhitespaceEscape", Syntax.RUBY.op | OP_POSIX_BRACKET,
    +            (Syntax.RUBY.op2 & ~OP2_OPTION_RUBY) | OP2_OPTION_PERL
    +                    | OP2_PLUS_POSSESSIVE_INTERVAL | OP2_ESC_H_HORIZONTAL_WHITESPACE,
    +            Syntax.RUBY.op3,
    +            Syntax.RUBY.behavior | ALLOW_MULTIPLEX_DEFINITION_NAME_CALL,
    +            Syntax.RUBY.options & ~(Option.ASCII_RANGE
    +                    | Option.POSIX_BRACKET_ALL_RANGE | Option.WORD_BOUND_ALL_RANGE),
    +            Syntax.RUBY.metaCharTable);
    +
    +    private static int search(String pattern, String input) {
    +        byte[] patternBytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        Regex regex = new Regex(patternBytes, 0, patternBytes.length, Option.NONE,
    +                UTF8Encoding.INSTANCE, SYNTAX);
    +        byte[] inputBytes = input.getBytes(StandardCharsets.UTF_8);
    +        return regex.matcher(inputBytes).search(0, inputBytes.length, Option.NONE);
    +    }
    +
    +    @Test
    +    public void keepsHorizontalWhitespaceEscapeAsAStandardClassMember() {
    +        String pattern = "(?[ [:ascii:] & [:cntrl:] & [^ \\000 \\h \\r \\n ] ])";
    +        assertEquals(0, search(pattern, "\u0001"));
    +        assertEquals(-1, search(pattern, "\t"));
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlExtendedClassEscapeDiagnostics.java b/third_party/joni/test/org/joni/test/TestPerlExtendedClassEscapeDiagnostics.java
    new file mode 100644
    index 0000000000..cc55a1b8a9
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlExtendedClassEscapeDiagnostics.java
    @@ -0,0 +1,63 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +import static org.junit.Assert.assertThrows;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.joni.WarnCallback;
    +import org.joni.exception.SyntaxException;
    +import org.junit.Test;
    +
    +public class TestPerlExtendedClassEscapeDiagnostics {
    +    @Test
    +    public void rejectsUnrecognizedAlphanumericEscapesAtTheirEnd() {
    +        assertEscapeError("(?[ \\8 ])", "8", 6);
    +        assertEscapeError("(?[ \\y ])", "y", 6);
    +        assertEscapeError("(?[ \\z ])", "z", 6);
    +    }
    +
    +    @Test
    +    public void retainsRecognizedAndEscapedPunctuation() {
    +        compile("(?[ \\n ])");
    +        compile("(?[ [\\]] ])");
    +    }
    +
    +    private static Regex compile(String pattern) {
    +        byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        return new Regex(bytes, 0, bytes.length, Option.CAPTURE_GROUP,
    +                UTF8Encoding.INSTANCE, Syntax.PerlNG, WarnCallback.NONE);
    +    }
    +
    +    private static void assertEscapeError(String pattern, String escape,
    +            int bytePosition) {
    +        SyntaxException error = assertThrows(SyntaxException.class,
    +                () -> compile(pattern));
    +        assertEquals("Unrecognized escape \\" + escape + " in character class",
    +                error.getMessage());
    +        assertEquals(bytePosition, error.getPatternPosition());
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlExtendedClassEscapedClose.java b/third_party/joni/test/org/joni/test/TestPerlExtendedClassEscapedClose.java
    new file mode 100644
    index 0000000000..6fa8815950
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlExtendedClassEscapedClose.java
    @@ -0,0 +1,47 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +import static org.junit.Assert.assertThrows;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.joni.WarnCallback;
    +import org.joni.exception.SyntaxException;
    +import org.junit.Test;
    +
    +public class TestPerlExtendedClassEscapedClose {
    +    @Test
    +    public void diagnosesEscapedCloseAfterCompletedOperand() {
    +        String pattern = "(?[ (?^:(?[\\x00])) \\] \\x00 ])";
    +        byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        SyntaxException error = assertThrows(SyntaxException.class,
    +                () -> new Regex(bytes, 0, bytes.length, Option.NONE,
    +                        UTF8Encoding.INSTANCE, Syntax.PerlNG, WarnCallback.NONE));
    +        assertEquals("Unexpected ']' with no following ')' in (?[...",
    +                error.getMessage());
    +        assertEquals(pattern.indexOf("\\]") + 2, error.getPatternPosition());
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlExtendedClassFailurePrecedence.java b/third_party/joni/test/org/joni/test/TestPerlExtendedClassFailurePrecedence.java
    new file mode 100644
    index 0000000000..f7b6182b8e
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlExtendedClassFailurePrecedence.java
    @@ -0,0 +1,59 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +import static org.junit.Assert.assertThrows;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.joni.WarnCallback;
    +import org.joni.exception.SyntaxException;
    +import org.junit.Test;
    +
    +public class TestPerlExtendedClassFailurePrecedence {
    +    @Test
    +    public void controlCloseGroupUsesOuterSyntaxFailure() {
    +        assertDiagnostic("/(?[(\\c]) /", "Syntax error in (?[...])", 11);
    +        assertDiagnostic("(?[(\\c])", "Syntax error in (?[...])", 8);
    +    }
    +
    +    @Test
    +    public void missingNestedCloseUsesUnmatchedOpenFailure() {
    +        assertDiagnostic("(?[ ! ! (\\w])",
    +                "Unmatched (", 11);
    +        assertDiagnostic("(?[ ! ( ! (\\w)])",
    +                "Unmatched (", 14);
    +    }
    +
    +    private static void assertDiagnostic(String pattern, String message,
    +            int position) {
    +        byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        SyntaxException error = assertThrows(SyntaxException.class,
    +                () -> new Regex(bytes, 0, bytes.length, Option.NONE,
    +                        UTF8Encoding.INSTANCE, Syntax.PerlNG, WarnCallback.NONE));
    +        assertEquals(message, error.getMessage());
    +        assertEquals(position, error.getPatternPosition());
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlExtendedClassLeafBoundary.java b/third_party/joni/test/org/joni/test/TestPerlExtendedClassLeafBoundary.java
    new file mode 100644
    index 0000000000..520b3d19f4
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlExtendedClassLeafBoundary.java
    @@ -0,0 +1,50 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +import static org.junit.Assert.assertThrows;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.joni.WarnCallback;
    +import org.joni.exception.SyntaxException;
    +import org.junit.Test;
    +
    +public class TestPerlExtendedClassLeafBoundary {
    +    @Test
    +    public void malformedStandardLeafMarksOuterPatternEnd() {
    +        assertDiagnostic("\u30cd(?[[[:\u30cd: ])\u30cd", 19);
    +        assertDiagnostic("\u00ef(?[[[:\u00ef: ])\u00ef", 16);
    +    }
    +
    +    private static void assertDiagnostic(String pattern, int bytePosition) {
    +        byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        SyntaxException error = assertThrows(SyntaxException.class,
    +                () -> new Regex(bytes, 0, bytes.length, Option.CAPTURE_GROUP,
    +                        UTF8Encoding.INSTANCE, Syntax.PerlNG, WarnCallback.NONE));
    +        assertEquals("Syntax error in (?[...])", error.getMessage());
    +        assertEquals(bytePosition, error.getPatternPosition());
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlExtendedEmptyPosixLeaf.java b/third_party/joni/test/org/joni/test/TestPerlExtendedEmptyPosixLeaf.java
    new file mode 100644
    index 0000000000..cf47ed68e3
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlExtendedEmptyPosixLeaf.java
    @@ -0,0 +1,73 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.joni.constants.SyntaxProperties.ALLOW_MULTIPLEX_DEFINITION_NAME_CALL;
    +import static org.joni.constants.SyntaxProperties.OP2_OPTION_PERL;
    +import static org.joni.constants.SyntaxProperties.OP2_OPTION_RUBY;
    +import static org.joni.constants.SyntaxProperties.OP_ESC_C_CONTROL;
    +import static org.junit.Assert.assertEquals;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.junit.Test;
    +
    +public class TestPerlExtendedEmptyPosixLeaf {
    +    private static final Syntax SYNTAX = new Syntax(
    +            "PerlExtendedEmptyPosixLeaf", Syntax.RUBY.op | OP_ESC_C_CONTROL,
    +            (Syntax.RUBY.op2 & ~OP2_OPTION_RUBY) | OP2_OPTION_PERL,
    +            Syntax.RUBY.op3,
    +            Syntax.RUBY.behavior | ALLOW_MULTIPLEX_DEFINITION_NAME_CALL,
    +            Syntax.RUBY.options & ~(Option.ASCII_RANGE
    +                    | Option.POSIX_BRACKET_ALL_RANGE | Option.WORD_BOUND_ALL_RANGE),
    +            Syntax.RUBY.metaCharTable);
    +
    +    private static int search(String patternSource, String input) {
    +        byte[] pattern = patternSource.getBytes(StandardCharsets.UTF_8);
    +        byte[] subject = input.getBytes(StandardCharsets.UTF_8);
    +        Regex regex = new Regex(pattern, 0, pattern.length, Option.NONE,
    +                UTF8Encoding.INSTANCE, SYNTAX);
    +        return regex.matcher(subject).search(0, subject.length, Option.NONE);
    +    }
    +
    +    @Test
    +    public void treatsEmptyPosixLookingLeafAsOrdinaryClass() {
    +        assertEquals(0, search("(?[ [:] ])", ":"));
    +        assertEquals(-1, search("(?[ [:] ])", "a"));
    +    }
    +
    +    @Test
    +    public void ignoresParenthesizedCommentsBetweenOperands() {
    +        assertEquals(0, search("(?[ (?# comment) [a] ])", "a"));
    +        assertEquals(-1, search("(?[ (?# comment) [a] ])", "b"));
    +    }
    +
    +    @Test
    +    public void acceptsControlEscapesAsSingleOperands() {
    +        assertEquals(0, search("(?[\\c#])", "c"));
    +        assertEquals(0, search("(?[\\c[])", "\u001b"));
    +        assertEquals(0, search("(?[\\c\\])", "\u001c"));
    +        assertEquals(0, search("(?[\\c]])", "\u001d"));
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlExtendedScopedInterpolation.java b/third_party/joni/test/org/joni/test/TestPerlExtendedScopedInterpolation.java
    new file mode 100644
    index 0000000000..1779472296
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlExtendedScopedInterpolation.java
    @@ -0,0 +1,63 @@
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +import static org.junit.Assert.fail;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.joni.WarnCallback;
    +import org.joni.exception.JOniException;
    +import org.junit.Test;
    +
    +public class TestPerlExtendedScopedInterpolation {
    +    private static Regex compile(String pattern) {
    +        byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        return new Regex(bytes, 0, bytes.length, Option.NONE,
    +                UTF8Encoding.INSTANCE, Syntax.PerlNG, WarnCallback.NONE);
    +    }
    +
    +    private static int search(String pattern, String input) {
    +        byte[] bytes = input.getBytes(StandardCharsets.UTF_8);
    +        return compile(pattern).matcher(bytes).search(0, bytes.length, Option.NONE);
    +    }
    +
    +    private static void assertMatches(String pattern, String yes, String no) {
    +        assertEquals(pattern + " should match " + yes, 0, search(pattern, yes));
    +        assertEquals(pattern + " should not match " + no, -1, search(pattern, no));
    +    }
    +
    +    private static void assertSyntaxError(String pattern, String fragment) {
    +        try {
    +            compile(pattern);
    +            fail("expected syntax error for " + pattern);
    +        } catch (JOniException error) {
    +            if (!error.getMessage().contains(fragment)) {
    +                fail("expected '" + fragment + "' in '" + error.getMessage() + "'");
    +            }
    +        }
    +    }
    +
    +    @Test
    +    public void acceptsRecursivelyScopedExtendedClassLeaves() {
    +        assertMatches("(?[ (?^:(?[ [x] ])) ])", "x", "y");
    +        assertMatches("(?[ (?^:(?x:(?[ [x] ]))) ])", "x", "y");
    +        assertMatches("(?[ (?^:(?x:(?i:(?[ [x] ])))) ])", "X", "y");
    +    }
    +
    +    @Test
    +    public void restoresOptionsAfterNestedScopedInterpolation() {
    +        assertMatches("(?[ (?^:(?i:(?[ [a] ]))) - [A] ])", "a", "A");
    +    }
    +
    +    @Test
    +    public void stillRequiresAnExtendedClassLeaf() {
    +        String expected = "Expecting interpolated extended charclass";
    +        assertSyntaxError("(?[ (?^:(?x:[x])) ])", expected);
    +        assertSyntaxError("(?[ (?^:(?x:([x]))) ])", expected);
    +        assertSyntaxError("(?[ (?^:(?x:(?i:[x]))) ])", expected);
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlForwardNamedBackreference.java b/third_party/joni/test/org/joni/test/TestPerlForwardNamedBackreference.java
    new file mode 100644
    index 0000000000..cdb435cfb1
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlForwardNamedBackreference.java
    @@ -0,0 +1,62 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +import static org.junit.Assert.fail;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.joni.WarnCallback;
    +import org.joni.exception.SyntaxException;
    +import org.junit.Test;
    +
    +public class TestPerlForwardNamedBackreference {
    +    private static int search(String pattern, String input) {
    +        byte[] patternBytes = ("\\A(?:" + pattern + ")\\z")
    +                .getBytes(StandardCharsets.UTF_8);
    +        byte[] inputBytes = input.getBytes(StandardCharsets.UTF_8);
    +        Regex regex = new Regex(patternBytes, 0, patternBytes.length, Option.NONE,
    +                UTF8Encoding.INSTANCE, Syntax.PerlNG, WarnCallback.NONE);
    +        return regex.matcher(inputBytes).search(0, inputBytes.length, Option.NONE);
    +    }
    +
    +    @Test
    +    public void resolvesNamedBackreferencesAfterTheCompleteParse() {
    +        assertEquals(-1, search("(?\\g{later})(?x)(?&before)", "xx"));
    +        assertEquals(-1, search("(?\\k)(?x)(?&before)", "xx"));
    +    }
    +
    +    @Test
    +    public void retainsTheOriginalMissingNamePosition() {
    +        String pattern = "foo \\k";
    +        try {
    +            search(pattern, "foo");
    +            fail("expected a missing named-group diagnostic");
    +        } catch (SyntaxException error) {
    +            assertEquals("Reference to nonexistent named group", error.getMessage());
    +            assertEquals(13, error.getPatternPosition());
    +        }
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlGrammarDiagnosticPositions.java b/third_party/joni/test/org/joni/test/TestPerlGrammarDiagnosticPositions.java
    new file mode 100644
    index 0000000000..79cb15ca98
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlGrammarDiagnosticPositions.java
    @@ -0,0 +1,91 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.joni.constants.SyntaxProperties.OP2_OPTION_PERL;
    +import static org.joni.constants.SyntaxProperties.OP2_OPTION_RUBY;
    +import static org.junit.Assert.assertEquals;
    +import static org.junit.Assert.assertThrows;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.joni.WarnCallback;
    +import org.joni.exception.SyntaxException;
    +import org.junit.Test;
    +
    +public class TestPerlGrammarDiagnosticPositions {
    +    private static final Syntax PERL_SYNTAX = new Syntax(
    +            "PerlGrammarDiagnostics", Syntax.RUBY.op,
    +            (Syntax.RUBY.op2 & ~OP2_OPTION_RUBY) | OP2_OPTION_PERL,
    +            Syntax.RUBY.op3, Syntax.RUBY.behavior, Syntax.RUBY.options,
    +            Syntax.RUBY.metaCharTable);
    +
    +    private static void assertDiagnostic(String pattern, String message,
    +                                         int bytePosition) {
    +        byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        SyntaxException error = assertThrows(SyntaxException.class,
    +                () -> new Regex(bytes, 0, bytes.length, Option.CAPTURE_GROUP,
    +                        UTF8Encoding.INSTANCE, PERL_SYNTAX, WarnCallback.NONE));
    +        assertEquals(message, error.getMessage());
    +        assertEquals(bytePosition, error.getPatternPosition());
    +    }
    +
    +    @Test
    +    public void positionsConditionalGrammarFailures() {
    +        assertDiagnostic("(?(1x))", "Switch condition not recognized", 5);
    +
    +        String branches = "(?(1)x|y|z)";
    +        assertDiagnostic(branches,
    +                "Switch (?(condition)... contains too many branches",
    +                branches.lastIndexOf('|') + 1);
    +
    +        String missingCondition = "\\x{100}(?(";
    +        assertDiagnostic(missingCondition, "Unknown switch condition (?(...))",
    +                missingCondition.length());
    +
    +        assertDiagnostic("(?(?{=DYNAMIC:0}))",
    +                "Unknown switch condition (?(...))", 4);
    +    }
    +
    +    @Test
    +    public void positionsExtendedClassGrammarFailures() {
    +        assertDiagnostic("(?[a])", "Unexpected character", 4);
    +
    +        String operand = "(?[ \\cK \\t ])";
    +        assertDiagnostic(operand, "Operand with no preceding operator",
    +                operand.indexOf("\\t") + 2);
    +
    +        String nestedCondition = "(?[ \\p{Digit} & (?(?[ \\p{Thai} | \\p{Lao} ]))])";
    +        assertDiagnostic(nestedCondition, "Unexpected character",
    +                nestedCondition.indexOf("(?(") + 2);
    +    }
    +
    +    @Test
    +    public void positionsUnterminatedNumericEscapeContent() {
    +        assertDiagnostic("\\x{ 1 ", "Missing right brace on \\x{}", 5);
    +        assertDiagnostic("[\\x{ A ]", "Missing right brace on \\x{}", 6);
    +        assertDiagnostic("\\o{ 1 ", "Missing right brace on \\o{}", 5);
    +        assertDiagnostic("[\\o{ 7 ]", "Missing right brace on \\o{}", 6);
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlGraphemeBoundary.java b/third_party/joni/test/org/joni/test/TestPerlGraphemeBoundary.java
    index 430934b4c5..711ccdc556 100644
    --- a/third_party/joni/test/org/joni/test/TestPerlGraphemeBoundary.java
    +++ b/third_party/joni/test/org/joni/test/TestPerlGraphemeBoundary.java
    @@ -23,6 +23,7 @@
     
     import java.nio.charset.StandardCharsets;
     
    +import org.jcodings.specific.ISO8859_1Encoding;
     import org.jcodings.specific.UTF8Encoding;
     import org.joni.Option;
     import org.joni.Regex;
    @@ -58,4 +59,19 @@ public void implementsUnicodeGraphemeBreakRules() {
             assertNoBoundary("🇦", "🇧");
             assertBoundary("🇦🇧", "🇨");
         }
    +
    +    @Test
    +    public void recognizesCrLfInBytePatterns() {
    +        byte[] input = "\r\n".getBytes(StandardCharsets.ISO_8859_1);
    +        byte[] pattern = "\\A\r\\B{gcb}\n\\z".getBytes(StandardCharsets.ISO_8859_1);
    +        Regex regex = new Regex(pattern, 0, pattern.length, Option.PERL_BYTE_PATTERN,
    +                ISO8859_1Encoding.INSTANCE, Syntax.PerlNG);
    +        assertEquals(0, regex.matcher(input).search(0, input.length, Option.NONE));
    +
    +        input = "AB".getBytes(StandardCharsets.ISO_8859_1);
    +        pattern = "\\AA\\b{gcb}B\\z".getBytes(StandardCharsets.ISO_8859_1);
    +        regex = new Regex(pattern, 0, pattern.length, Option.PERL_BYTE_PATTERN,
    +                ISO8859_1Encoding.INSTANCE, Syntax.PerlNG);
    +        assertEquals(0, regex.matcher(input).search(0, input.length, Option.NONE));
    +    }
     }
    diff --git a/third_party/joni/test/org/joni/test/TestPerlGroupEffectDiagnostics.java b/third_party/joni/test/org/joni/test/TestPerlGroupEffectDiagnostics.java
    new file mode 100644
    index 0000000000..bcd680a302
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlGroupEffectDiagnostics.java
    @@ -0,0 +1,52 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +import static org.junit.Assert.fail;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.joni.WarnCallback;
    +import org.joni.exception.SyntaxException;
    +import org.junit.Test;
    +
    +public class TestPerlGroupEffectDiagnostics {
    +    private static void assertIncomplete(String pattern) {
    +        byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        try {
    +            new Regex(bytes, 0, bytes.length, Option.NONE, UTF8Encoding.INSTANCE,
    +                    Syntax.PerlNG, WarnCallback.NONE);
    +            fail("expected incomplete Perl group effect for " + pattern);
    +        } catch (SyntaxException error) {
    +            assertEquals("Sequence (? incomplete", error.getMessage());
    +        }
    +    }
    +
    +    @Test
    +    public void reportsIncompleteGroupEffects() {
    +        assertIncomplete("(?");
    +        assertIncomplete("a(?");
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlGroupNameStartPolicy.java b/third_party/joni/test/org/joni/test/TestPerlGroupNameStartPolicy.java
    new file mode 100644
    index 0000000000..416d8b3e40
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlGroupNameStartPolicy.java
    @@ -0,0 +1,62 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +import static org.junit.Assert.assertThrows;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.joni.WarnCallback;
    +import org.joni.exception.SyntaxException;
    +import org.junit.Test;
    +
    +public class TestPerlGroupNameStartPolicy {
    +    @Test
    +    public void acceptsPerlLetterAndUnderscoreStarts() {
    +        compile("(?<_name>x)");
    +        compile("(?<\u00e9name>x)");
    +        compile("(?<\u2163name>x)");
    +    }
    +
    +    @Test
    +    public void rejectsWordCharactersThatAreNotPerlNameStarts() {
    +        assertStartError("(?<\u203fname>x)", 6);
    +        assertStartError("(?<\u0301name>x)", 5);
    +    }
    +
    +    private static Regex compile(String pattern) {
    +        byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        return new Regex(bytes, 0, bytes.length, Option.CAPTURE_GROUP,
    +                UTF8Encoding.INSTANCE, Syntax.PerlNG, WarnCallback.NONE);
    +    }
    +
    +    private static void assertStartError(String pattern, int bytePosition) {
    +        SyntaxException error = assertThrows(SyntaxException.class,
    +                () -> compile(pattern));
    +        assertEquals("Group name must start with a non-digit word character",
    +                error.getMessage());
    +        assertEquals(bytePosition, error.getPatternPosition());
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlInvalidRangeDiagnosticMetadata.java b/third_party/joni/test/org/joni/test/TestPerlInvalidRangeDiagnosticMetadata.java
    new file mode 100644
    index 0000000000..2556d8a1dc
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlInvalidRangeDiagnosticMetadata.java
    @@ -0,0 +1,52 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +import static org.junit.Assert.assertThrows;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.joni.WarnCallback;
    +import org.joni.exception.SyntaxException;
    +import org.junit.Test;
    +
    +public class TestPerlInvalidRangeDiagnosticMetadata {
    +    @Test
    +    public void retainsRangeSpellingWithoutChangingEngineMessage() {
    +        assertRange("[z-a]", "z-a", 4);
    +        assertRange("[\u30cd-a]\u30cd", "\u30cd-a", 6);
    +    }
    +
    +    private static void assertRange(String pattern, String range, int bytePosition) {
    +        byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        SyntaxException error = assertThrows(SyntaxException.class,
    +                () -> new Regex(bytes, 0, bytes.length, Option.CAPTURE_GROUP,
    +                        UTF8Encoding.INSTANCE, Syntax.PerlNG, WarnCallback.NONE));
    +        assertEquals("Invalid [] range", error.getMessage());
    +        assertEquals("Invalid [] range \"" + range + "\"",
    +                error.getDiagnosticMessage());
    +        assertEquals(bytePosition, error.getPatternPosition());
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlLineBreakByteNel.java b/third_party/joni/test/org/joni/test/TestPerlLineBreakByteNel.java
    new file mode 100644
    index 0000000000..442353f8cf
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlLineBreakByteNel.java
    @@ -0,0 +1,86 @@
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +import static org.joni.constants.SyntaxProperties.ALLOW_MULTIPLEX_DEFINITION_NAME_CALL;
    +import static org.joni.constants.SyntaxProperties.OP2_ESC_H_HORIZONTAL_WHITESPACE;
    +import static org.joni.constants.SyntaxProperties.OP2_ESC_V_VERTICAL_WHITESPACE;
    +import static org.joni.constants.SyntaxProperties.OP2_OPTION_PERL;
    +import static org.joni.constants.SyntaxProperties.OP2_OPTION_RUBY;
    +import static org.joni.constants.SyntaxProperties.OP2_PLUS_POSSESSIVE_INTERVAL;
    +import static org.joni.constants.SyntaxProperties.OP3_PERL_LITERAL_OPEN_IN_CC;
    +import static org.joni.constants.SyntaxProperties.OP_ESC_C_CONTROL;
    +import static org.joni.constants.SyntaxProperties.OP_POSIX_BRACKET;
    +
    +import java.nio.charset.Charset;
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.Encoding;
    +import org.jcodings.specific.ISO8859_1Encoding;
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.joni.WarnCallback;
    +import org.junit.Test;
    +
    +public class TestPerlLineBreakByteNel {
    +    private static final Syntax SYNTAX = new Syntax(
    +            "PerlLineBreakByteNel", Syntax.RUBY.op | OP_POSIX_BRACKET
    +                    | OP_ESC_C_CONTROL,
    +            (Syntax.RUBY.op2 & ~OP2_OPTION_RUBY) | OP2_OPTION_PERL
    +                    | OP2_PLUS_POSSESSIVE_INTERVAL
    +                    | OP2_ESC_H_HORIZONTAL_WHITESPACE
    +                    | OP2_ESC_V_VERTICAL_WHITESPACE,
    +            Syntax.RUBY.op3 | OP3_PERL_LITERAL_OPEN_IN_CC,
    +            Syntax.RUBY.behavior | ALLOW_MULTIPLEX_DEFINITION_NAME_CALL,
    +            Syntax.RUBY.options & ~(Option.ASCII_RANGE
    +                    | Option.POSIX_BRACKET_ALL_RANGE
    +                    | Option.WORD_BOUND_ALL_RANGE),
    +            Syntax.RUBY.metaCharTable, null);
    +
    +    private static int search(String pattern, byte[] input, Encoding encoding,
    +                              Charset charset, int options) {
    +        byte[] patternBytes = pattern.getBytes(charset);
    +        Regex regex = new Regex(patternBytes, 0, patternBytes.length, options,
    +                encoding, SYNTAX, WarnCallback.NONE);
    +        return regex.matcher(input).search(0, input.length, Option.NONE);
    +    }
    +
    +    private static void assertByteMatch(String pattern, byte[] input) {
    +        assertEquals(0, search(pattern, input,
    +                ISO8859_1Encoding.INSTANCE, StandardCharsets.ISO_8859_1,
    +                Option.PERL_BYTE_PATTERN));
    +    }
    +
    +    private static void assertByteNoMatch(String pattern, byte[] input) {
    +        assertEquals(-1, search(pattern, input,
    +                ISO8859_1Encoding.INSTANCE, StandardCharsets.ISO_8859_1,
    +                Option.PERL_BYTE_PATTERN));
    +    }
    +
    +    private static void assertUtf8Match(String pattern, String input) {
    +        assertEquals(0, search(pattern,
    +                input.getBytes(StandardCharsets.UTF_8), UTF8Encoding.INSTANCE,
    +                StandardCharsets.UTF_8, Option.NONE));
    +    }
    +
    +    @Test
    +    public void includesNelInSingleByteLineBreaks() {
    +        byte[] nel = {(byte) 0x85};
    +        assertByteMatch("\\R", nel);
    +        assertByteNoMatch("\\V", nel);
    +        assertByteMatch("\\V\\R", new byte[] {'o', (byte) 0x85});
    +        assertByteMatch("foo(\\R+)bar", new byte[] {'f', 'o', 'o', '\r', '\n',
    +                (byte) 0x85, '\r', '\n', '\n', 'b', 'a', 'r'});
    +    }
    +
    +    @Test
    +    public void preservesUnicodeAndCrLfLineBreaks() {
    +        assertUtf8Match("\\R", "\u0085");
    +        assertUtf8Match("\\R", "\u2028");
    +        assertUtf8Match("\\R", "\u2029");
    +        assertByteMatch("\\R", new byte[] {'\r', '\n'});
    +        assertByteMatch("\\R", new byte[] {'\r'});
    +        assertByteMatch("\\R", new byte[] {'\n'});
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlMalformedPosixWarnings.java b/third_party/joni/test/org/joni/test/TestPerlMalformedPosixWarnings.java
    new file mode 100644
    index 0000000000..1350a56067
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlMalformedPosixWarnings.java
    @@ -0,0 +1,93 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +
    +import java.nio.charset.StandardCharsets;
    +import java.util.ArrayList;
    +import java.util.List;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.joni.WarnCallback;
    +import org.junit.Test;
    +
    +public class TestPerlMalformedPosixWarnings {
    +    private record Warning(String message, int position) {}
    +
    +    private static List warnings(String pattern) {
    +        List warnings = new ArrayList<>();
    +        byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        WarnCallback callback = new WarnCallback() {
    +            @Override
    +            public void warn(String message) {
    +                throw new AssertionError("warning missing position: " + message);
    +            }
    +
    +            @Override
    +            public void warn(String message, int position) {
    +                warnings.add(new Warning(message, position));
    +            }
    +
    +            @Override
    +            public boolean supportsPositions() {
    +                return true;
    +            }
    +        };
    +        new Regex(bytes, 0, bytes.length, Option.NONE, UTF8Encoding.INSTANCE,
    +                Syntax.PerlNG, callback);
    +        return warnings;
    +    }
    +
    +    @Test
    +    public void warnsForMissingPosixDelimiters() {
    +        assertEquals(List.of(new Warning(
    +                "Assuming NOT a POSIX class since there is no terminating ':'", 8)),
    +                warnings("[[:digit]]"));
    +        assertEquals(List.of(
    +                new Warning("Assuming NOT a POSIX class since the name must be all lowercase letters", 8),
    +                new Warning("Assuming NOT a POSIX class since there is no terminating ':'", 8)),
    +                warnings("[[:DIGIT]]"));
    +        assertEquals(List.of(
    +                new Warning("Assuming NOT a POSIX class since the '^' must come after the colon", 3),
    +                new Warning("Assuming NOT a POSIX class since there must be a starting ':'", 3),
    +                new Warning("Assuming NOT a POSIX class since there is no terminating ':'", 7)),
    +                warnings("[[^word]"));
    +    }
    +
    +    @Test
    +    public void warnsForSemicolonsInPosixLikeClasses() {
    +        assertEquals(List.of(
    +                new Warning("Assuming NOT a POSIX class since it doesn't start with a '['", 4),
    +                new Warning("Assuming NOT a POSIX class since a semi-colon was found instead of a colon", 5),
    +                new Warning("Assuming NOT a POSIX class since a semi-colon was found instead of a colon", 12)),
    +                warnings("[foo;punct;]]"));
    +    }
    +
    +    @Test
    +    public void warnsForDirectExtendedClassLiteral() {
    +        assertEquals(List.of(new Warning(
    +                "Assuming NOT a POSIX class since there is no terminating ':'", 9)),
    +                warnings("(?[[:word]])"));
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlNamedCharacterDiagnostics.java b/third_party/joni/test/org/joni/test/TestPerlNamedCharacterDiagnostics.java
    new file mode 100644
    index 0000000000..6169227f02
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlNamedCharacterDiagnostics.java
    @@ -0,0 +1,71 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.joni.exception.ErrorMessages.PERL_MISSING_BRACES_ON_NAMED_CHARACTER_ESCAPE;
    +import static org.junit.Assert.assertEquals;
    +import static org.junit.Assert.fail;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.NamedCharacterResolver;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.joni.WarnCallback;
    +import org.joni.exception.SyntaxException;
    +import org.junit.Test;
    +
    +public class TestPerlNamedCharacterDiagnostics {
    +    private static final NamedCharacterResolver RESOLVER =
    +            (bytes, p, end, encoding) -> 'A';
    +    private static final Syntax SYNTAX = new Syntax(
    +            "PerlNamedCharacterDiagnostics", Syntax.PerlNG.op, Syntax.PerlNG.op2,
    +            Syntax.PerlNG.op3, Syntax.PerlNG.behavior, Syntax.PerlNG.options,
    +            Syntax.PerlNG.metaCharTable, RESOLVER);
    +
    +    private static void compile(String pattern) {
    +        byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        new Regex(bytes, 0, bytes.length, Option.NONE, UTF8Encoding.INSTANCE,
    +                SYNTAX, WarnCallback.NONE);
    +    }
    +
    +    private static void assertMissingBraces(String pattern) {
    +        try {
    +            compile(pattern);
    +            fail("expected missing named-character braces for " + pattern);
    +        } catch (SyntaxException error) {
    +            assertEquals(PERL_MISSING_BRACES_ON_NAMED_CHARACTER_ESCAPE,
    +                    error.getMessage());
    +        }
    +    }
    +
    +    @Test
    +    public void rejectsBracesSeparatedByExtendedWhitespace() {
    +        assertMissingBraces("(?x)\\N {U+41}");
    +        assertMissingBraces("(?x)\\N {SPACE}");
    +    }
    +
    +    @Test
    +    public void rejectsBracesSeparatedByACommentGroup() {
    +        assertMissingBraces("\\N(?#comment){SPACE}");
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlNamedCharacterSequenceWarnings.java b/third_party/joni/test/org/joni/test/TestPerlNamedCharacterSequenceWarnings.java
    new file mode 100644
    index 0000000000..4d0471cd1b
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlNamedCharacterSequenceWarnings.java
    @@ -0,0 +1,95 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +
    +import java.nio.charset.StandardCharsets;
    +import java.util.ArrayList;
    +import java.util.List;
    +
    +import org.jcodings.Encoding;
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.NamedCharacterResolver;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.joni.WarnCallback;
    +import org.junit.Test;
    +
    +public class TestPerlNamedCharacterSequenceWarnings {
    +    private static final String MESSAGE =
    +            "Using just the first character returned by \\N{} in character class";
    +
    +    private static final NamedCharacterResolver RESOLVER =
    +            new NamedCharacterResolver() {
    +                @Override
    +                public int resolve(byte[] bytes, int p, int end, Encoding encoding) {
    +                    throw new AssertionError("sequence resolver expected");
    +                }
    +
    +                @Override
    +                public int[] resolveSequence(
    +                        byte[] bytes, int p, int end, Encoding encoding) {
    +                    return new int[] {0x100, 0x300};
    +                }
    +            };
    +
    +    private static final Syntax SYNTAX = new Syntax(
    +            "PerlNamedCharacterSequenceWarnings", Syntax.PerlNG.op,
    +            Syntax.PerlNG.op2, Syntax.PerlNG.op3, Syntax.PerlNG.behavior,
    +            Syntax.PerlNG.options, Syntax.PerlNG.metaCharTable, RESOLVER);
    +
    +    private static List warnings(String pattern) {
    +        List warnings = new ArrayList<>();
    +        byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        WarnCallback callback = new WarnCallback() {
    +            @Override
    +            public void warn(String message) {
    +                warnings.add(message);
    +            }
    +
    +            @Override
    +            public void warn(String message, int position) {
    +                warnings.add(message);
    +            }
    +
    +            @Override
    +            public boolean supportsPositions() {
    +                return true;
    +            }
    +        };
    +        new Regex(bytes, 0, bytes.length, Option.NONE,
    +                UTF8Encoding.INSTANCE, SYNTAX, callback);
    +        return warnings;
    +    }
    +
    +    @Test
    +    public void warnsWhenNamedSequenceIsSingleCharacterContext() {
    +        assertEquals(List.of(MESSAGE), warnings("[^\\N{PAIR}]"));
    +        assertEquals(List.of(MESSAGE), warnings("[\\x03-\\N{PAIR}]"));
    +        assertEquals(List.of(MESSAGE), warnings("[\\N{PAIR}-\\x{10ffff}]"));
    +    }
    +
    +    @Test
    +    public void keepsOrdinaryPositiveSequenceClassWarningFree() {
    +        assertEquals(List.of(), warnings("[\\N{PAIR}]"));
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlNamedReferenceDiagnostics.java b/third_party/joni/test/org/joni/test/TestPerlNamedReferenceDiagnostics.java
    new file mode 100644
    index 0000000000..7d31fe4043
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlNamedReferenceDiagnostics.java
    @@ -0,0 +1,76 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.joni.exception.ErrorMessages.PERL_GROUP_NAME_MUST_START_WITH_WORD;
    +import static org.joni.exception.ErrorMessages.PERL_REFERENCE_TO_NONEXISTENT_NAMED_GROUP;
    +import static org.junit.Assert.assertEquals;
    +import static org.junit.Assert.fail;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.joni.WarnCallback;
    +import org.joni.exception.SyntaxException;
    +import org.junit.Test;
    +
    +public class TestPerlNamedReferenceDiagnostics {
    +    private static Regex compile(String pattern) {
    +        byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        return new Regex(bytes, 0, bytes.length, Option.NONE, UTF8Encoding.INSTANCE,
    +                Syntax.PerlNG, WarnCallback.NONE);
    +    }
    +
    +    private static void assertSyntaxError(String pattern, String expected) {
    +        try {
    +            compile(pattern);
    +            fail("expected syntax error for " + pattern);
    +        } catch (SyntaxException error) {
    +            assertEquals(expected, error.getMessage());
    +        }
    +    }
    +
    +    private static void assertMatch(String pattern, String input) {
    +        byte[] bytes = input.getBytes(StandardCharsets.UTF_8);
    +        assertEquals(0, compile(pattern).matcher(bytes)
    +                .search(0, bytes.length, Option.NONE));
    +    }
    +
    +    @Test
    +    public void reportsUnknownAndDigitLeadingNamesWithPerlDiagnostics() {
    +        assertSyntaxError("foo \\k'n'",
    +                PERL_REFERENCE_TO_NONEXISTENT_NAMED_GROUP);
    +        assertSyntaxError("foo \\k<_0_>",
    +                PERL_REFERENCE_TO_NONEXISTENT_NAMED_GROUP);
    +        assertSyntaxError("foo \\k'0'", PERL_GROUP_NAME_MUST_START_WITH_WORD);
    +        assertSyntaxError("foo \\k<1a>", PERL_GROUP_NAME_MUST_START_WITH_WORD);
    +    }
    +
    +    @Test
    +    public void trimsOnlyBraceDelimitedNamedReferences() {
    +        assertMatch("(?as) (\\w+) \\k{ as } (\\w+)", "as easy as pie");
    +        assertMatch("(?'n'foo) \\g{ n }", "foo foo");
    +        assertSyntaxError("(?as) \\k< as>",
    +                PERL_GROUP_NAME_MUST_START_WITH_WORD);
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlNativePolicyDiagnostics.java b/third_party/joni/test/org/joni/test/TestPerlNativePolicyDiagnostics.java
    new file mode 100644
    index 0000000000..430f0c769b
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlNativePolicyDiagnostics.java
    @@ -0,0 +1,91 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.joni.constants.SyntaxProperties.OP2_OPTION_PERL;
    +import static org.joni.constants.SyntaxProperties.OP2_OPTION_RUBY;
    +import static org.junit.Assert.assertEquals;
    +import static org.junit.Assert.assertThrows;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.joni.WarnCallback;
    +import org.joni.exception.SyntaxException;
    +import org.junit.Test;
    +
    +public class TestPerlNativePolicyDiagnostics {
    +    private static final Syntax PERL_SYNTAX = new Syntax(
    +            "PerlNativePolicyDiagnostics", Syntax.RUBY.op,
    +            (Syntax.RUBY.op2 & ~OP2_OPTION_RUBY) | OP2_OPTION_PERL,
    +            Syntax.RUBY.op3, Syntax.RUBY.behavior, Syntax.RUBY.options,
    +            Syntax.RUBY.metaCharTable);
    +
    +    private static void assertDiagnostic(String pattern, String message,
    +                                         int bytePosition) {
    +        byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        SyntaxException error = assertThrows(SyntaxException.class,
    +                () -> new Regex(bytes, 0, bytes.length, Option.CAPTURE_GROUP,
    +                        UTF8Encoding.INSTANCE, PERL_SYNTAX, WarnCallback.NONE));
    +        assertEquals(message, error.getMessage());
    +        assertEquals(bytePosition, error.getPatternPosition());
    +    }
    +
    +    @Test
    +    public void rejectsCommentSeparatedGroupIntroducers() {
    +        String comment = "(?# comment)";
    +        assertDiagnostic("(" + comment + "?:foo)",
    +                "In '(?...)', the '(' and '?' must be adjacent",
    +                comment.getBytes(StandardCharsets.UTF_8).length + 2);
    +        assertDiagnostic("(" + comment + "*FAIL)",
    +                "In '(*VERB...)', the '(' and '*' must be adjacent",
    +                comment.getBytes(StandardCharsets.UTF_8).length + 2);
    +        assertDiagnostic("(" + comment + "*script_run:foo)",
    +                "In '(*...)', the '(' and '*' must be adjacent",
    +                comment.getBytes(StandardCharsets.UTF_8).length + 2);
    +    }
    +
    +    @Test
    +    public void reportsUnrecognizedGroupSequences() {
    +        String nonAscii = "(?é)";
    +        assertDiagnostic(nonAscii, "Sequence (?é...) not recognized",
    +                "(?é".getBytes(StandardCharsets.UTF_8).length);
    +
    +        String caret = "(?[ \\p{Digit} & (?^(?[ \\p{Thai} | \\p{Lao} ]))])";
    +        assertDiagnostic(caret, "Sequence (?^(...) not recognized",
    +                caret.indexOf("(?^(") + 4);
    +    }
    +
    +    @Test
    +    public void enforcesExtendedClassHexPolicy() {
    +        String longHex = "(?[ \\xabcdef ])";
    +        assertDiagnostic(longHex,
    +                "Use \\x{...} for more than two hex characters",
    +                longHex.indexOf("\\xabc") + 5);
    +
    +        String emptyHex = "(?[ \\x{} ])";
    +        assertDiagnostic(emptyHex, "Empty \\x{}",
    +                emptyHex.indexOf("\\x{}") + 4);
    +    }
    +
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlNestedQuantifierPositions.java b/third_party/joni/test/org/joni/test/TestPerlNestedQuantifierPositions.java
    new file mode 100644
    index 0000000000..80e365d057
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlNestedQuantifierPositions.java
    @@ -0,0 +1,51 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +import static org.junit.Assert.assertThrows;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.joni.WarnCallback;
    +import org.joni.exception.SyntaxException;
    +import org.junit.Test;
    +
    +public class TestPerlNestedQuantifierPositions {
    +    @Test
    +    public void astDetectedNestedQuantifiersRetainEndPosition() {
    +        assertDiagnostic("x**", 3);
    +        assertDiagnostic("x{2}{3}", 7);
    +        assertDiagnostic("\u30cd**\u30cd", 5);
    +    }
    +
    +    private static void assertDiagnostic(String pattern, int bytePosition) {
    +        byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        SyntaxException error = assertThrows(SyntaxException.class,
    +                () -> new Regex(bytes, 0, bytes.length, Option.CAPTURE_GROUP,
    +                        UTF8Encoding.INSTANCE, Syntax.PerlNG, WarnCallback.NONE));
    +        assertEquals("Nested quantifiers", error.getMessage());
    +        assertEquals(bytePosition, error.getPatternPosition());
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlNumericBackreferenceBoundaries.java b/third_party/joni/test/org/joni/test/TestPerlNumericBackreferenceBoundaries.java
    new file mode 100644
    index 0000000000..62b0570189
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlNumericBackreferenceBoundaries.java
    @@ -0,0 +1,85 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.joni.exception.ErrorMessages.INVALID_BACKREF;
    +import static org.junit.Assert.assertEquals;
    +import static org.junit.Assert.assertThrows;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.ISO8859_1Encoding;
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.joni.WarnCallback;
    +import org.joni.exception.SyntaxException;
    +import org.junit.Test;
    +
    +public class TestPerlNumericBackreferenceBoundaries {
    +    private static Regex compile(String pattern) {
    +        byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        return new Regex(bytes, 0, bytes.length, Option.CAPTURE_GROUP,
    +                UTF8Encoding.INSTANCE, Syntax.PerlNG, WarnCallback.NONE);
    +    }
    +
    +    private static void assertInvalid(String pattern) {
    +        SyntaxException error = assertThrows(SyntaxException.class,
    +                () -> compile(pattern));
    +        assertEquals(INVALID_BACKREF, error.getMessage());
    +    }
    +
    +    @Test
    +    public void rejectsNonexistentAndOverflowingDecimalBackreferences() {
    +        assertInvalid("\\87");
    +        assertInvalid("a\\87");
    +        assertInvalid("a\\97");
    +        for (String digits : new String[] {"2147483648", "2147483649",
    +                "2147483650", "4294967296", "4294967297", "4294967298"}) {
    +            assertInvalid("(.)\\g" + digits + "}");
    +            assertInvalid("(.)\\g{" + digits + "}");
    +            assertInvalid("(.)\\g{ " + digits + " }");
    +            assertInvalid("a(.)\\g" + digits + "}");
    +            assertInvalid("a(.)\\g{" + digits + "}");
    +            assertInvalid("a(.)\\g{ " + digits + " }");
    +        }
    +    }
    +
    +    @Test
    +    public void longDecimalEscapesUseOnlyTheMaximalOctalPrefix() {
    +        for (String digits : new String[] {"2147483648", "2147483649",
    +                "2147483650", "4294967296", "4294967297", "4294967298"}) {
    +            int octalLength = 0;
    +            while (octalLength < 3 && octalLength < digits.length()
    +                    && digits.charAt(octalLength) <= '7') octalLength++;
    +            int octal = Integer.parseInt(digits.substring(0, octalLength), 8);
    +            String tail = digits.substring(octalLength);
    +            String pattern = "(.)\\" + digits;
    +            byte[] patternBytes = pattern.getBytes(StandardCharsets.ISO_8859_1);
    +            Regex regex = new Regex(patternBytes, 0, patternBytes.length,
    +                    Option.CAPTURE_GROUP, ISO8859_1Encoding.INSTANCE,
    +                    Syntax.PerlNG, WarnCallback.NONE);
    +            byte[] input = ("b" + (char)octal + tail)
    +                    .getBytes(StandardCharsets.ISO_8859_1);
    +            assertEquals(0, regex.matcher(input).search(0, input.length, Option.NONE));
    +        }
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlOptionGroupDiagnostics.java b/third_party/joni/test/org/joni/test/TestPerlOptionGroupDiagnostics.java
    new file mode 100644
    index 0000000000..1c9093cdb3
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlOptionGroupDiagnostics.java
    @@ -0,0 +1,53 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +import static org.junit.Assert.fail;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.joni.WarnCallback;
    +import org.joni.exception.SyntaxException;
    +import org.junit.Test;
    +
    +public class TestPerlOptionGroupDiagnostics {
    +    private static void assertUnterminated(String pattern) {
    +        byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        try {
    +            new Regex(bytes, 0, bytes.length, Option.NONE, UTF8Encoding.INSTANCE,
    +                    Syntax.PerlNG, WarnCallback.NONE);
    +            fail("expected unterminated Perl option group for " + pattern);
    +        } catch (SyntaxException error) {
    +            assertEquals("Sequence (?... not terminated", error.getMessage());
    +        }
    +    }
    +
    +    @Test
    +    public void reportsUnterminatedOptionGroups() {
    +        assertUnterminated("(?i");
    +        assertUnterminated("(?a-x");
    +        assertUnterminated("(?-");
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlPosixDiagnostics.java b/third_party/joni/test/org/joni/test/TestPerlPosixDiagnostics.java
    new file mode 100644
    index 0000000000..5e99dc92da
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlPosixDiagnostics.java
    @@ -0,0 +1,138 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +
    +import java.nio.charset.StandardCharsets;
    +import java.util.ArrayList;
    +import java.util.List;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.joni.WarnCallback;
    +import org.junit.Test;
    +
    +public class TestPerlPosixDiagnostics {
    +    private record Warning(String message, int position) {}
    +
    +    private static List compile(String pattern) {
    +        return compile(pattern, Option.NONE);
    +    }
    +
    +    private static List compile(String pattern, int options) {
    +        List warnings = new ArrayList<>();
    +        byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        WarnCallback callback = new WarnCallback() {
    +            @Override
    +            public void warn(String message) {
    +                throw new AssertionError("warning missing position: " + message);
    +            }
    +
    +            @Override
    +            public void warn(String message, int position) {
    +                warnings.add(new Warning(message, position));
    +            }
    +
    +            @Override
    +            public boolean supportsPositions() {
    +                return true;
    +            }
    +        };
    +        new Regex(bytes, 0, bytes.length, options, UTF8Encoding.INSTANCE,
    +                Syntax.PerlNG, callback);
    +        return warnings;
    +    }
    +
    +    @Test
    +    public void warnsForPosixSyntaxOutsideACharacterClass() {
    +        assertEquals(List.of(new Warning(
    +                "POSIX syntax [: :] belongs inside character classes", 9)),
    +                compile("[:alpha:]"));
    +        assertEquals(List.of(new Warning(
    +                "POSIX syntax [: :] belongs inside character classes "
    +                        + "(but this one isn't fully valid)", 7)),
    +                compile("[:zog:]"));
    +        assertEquals(List.of(new Warning(
    +                "POSIX syntax [: :] belongs inside character classes "
    +                        + "(but this one isn't fully valid)", 7)),
    +                compile("[:blank]"));
    +        assertEquals(List.of(new Warning(
    +                "POSIX syntax [. .] belongs inside character classes "
    +                        + "(but this one isn't implemented)", 7)),
    +                compile("[.zog.]"));
    +    }
    +
    +    @Test
    +    public void ordersNearMissWarningsAtPerlBytePositions() {
    +        assertEquals(List.of(new Warning(
    +                "Assuming NOT a POSIX class since there is no terminating ':'", 8)),
    +                compile("[[:digit]]"));
    +        assertEquals(List.of(new Warning(
    +                "Assuming NOT a POSIX class since there is no terminating ':'", 8)),
    +                compile("[[:ascii]]"));
    +        assertEquals(List.of(new Warning(
    +                "Assuming NOT a POSIX class since there is no terminating ']'", 9)),
    +                compile("[[:digit:foo]"));
    +        assertEquals(List.of(
    +                new Warning("Assuming NOT a POSIX class since the name must be all lowercase letters", 8),
    +                new Warning("Assuming NOT a POSIX class since there is no terminating ':'", 8)),
    +                compile("[[:DIGIT]]"));
    +        assertEquals(List.of(
    +                new Warning("Assuming NOT a POSIX class since the '^' must come after the colon", 3),
    +                new Warning("Assuming NOT a POSIX class since there must be a starting ':'", 3),
    +                new Warning("Assuming NOT a POSIX class since there is no terminating ':'", 7)),
    +                compile("[[^word]"));
    +    }
    +
    +    @Test
    +    public void recoversMalformedAndWidePosixCandidatesAsLiteralClassText() {
    +        assertEquals(1, compile("[[:digit:foo]").size());
    +        assertEquals(1, compile("(?[[:word]])").size());
    +        assertEquals(List.of(), compile("(?[[:w:]])"));
    +        assertEquals(List.of(), compile("ネ[[:ネ:]]ネ"));
    +        assertEquals(List.of(), compile("ネ(?[[:ネ:]])ネ"));
    +        assertEquals(List.of(), compile("[[:digit:]]"));
    +        assertEquals(List.of(), compile("(?[[:digit:]])"));
    +        assertEquals(false, compile("[a-[:digit:]]").stream()
    +                .anyMatch(warning -> warning.message().startsWith("POSIX syntax")));
    +    }
    +
    +    @Test
    +    public void diagnosesMissingDelimitersInSourceOrder() {
    +        assertEquals(List.of(new Warning(
    +                "Assuming NOT a POSIX class since it doesn't start with a '['", 4)),
    +                compile("[foo:lower:]]"));
    +        assertEquals(List.of(
    +                new Warning("Assuming NOT a POSIX class since a semi-colon was found instead of a colon", 3),
    +                new Warning("Assuming NOT a POSIX class since a semi-colon was found instead of a colon", 10)),
    +                compile("[[;upper;]]"));
    +        String spaced = "[[   ^   :   x d i g i t   :   ]   ]";
    +        assertEquals(List.of(
    +                new Warning("Assuming NOT a POSIX class since no blanks are allowed in one", 5),
    +                new Warning("Assuming NOT a POSIX class since the '^' must come after the colon", 6),
    +                new Warning("Assuming NOT a POSIX class since no blanks are allowed in one", 9),
    +                new Warning("Assuming NOT a POSIX class since no blanks are allowed in one", 13),
    +                new Warning("Assuming NOT a POSIX class since no blanks are allowed in one", 32)),
    +                compile(spaced));
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlPosixLiteralFallback.java b/third_party/joni/test/org/joni/test/TestPerlPosixLiteralFallback.java
    new file mode 100644
    index 0000000000..d08eaea914
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlPosixLiteralFallback.java
    @@ -0,0 +1,46 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.joni.WarnCallback;
    +import org.junit.Test;
    +
    +public class TestPerlPosixLiteralFallback {
    +    private static void compile(String pattern) {
    +        byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        new Regex(bytes, 0, bytes.length, Option.NONE, UTF8Encoding.INSTANCE,
    +                Syntax.PerlNG, WarnCallback.NONE);
    +    }
    +
    +    @Test
    +    public void treatsNonCandidatePosixSpellingsAsClassText() {
    +        compile("[[:w:]]");
    +        compile("[[:FOO:]]");
    +        compile("[[:ネ:]]");
    +        compile("(?[[:w:]])");
    +        compile("(?[[:ネ:]])");
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlPosixOutsideClassWarnings.java b/third_party/joni/test/org/joni/test/TestPerlPosixOutsideClassWarnings.java
    new file mode 100644
    index 0000000000..bff695bbeb
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlPosixOutsideClassWarnings.java
    @@ -0,0 +1,85 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +
    +import java.nio.charset.StandardCharsets;
    +import java.util.ArrayList;
    +import java.util.List;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.joni.WarnCallback;
    +import org.junit.Test;
    +
    +public class TestPerlPosixOutsideClassWarnings {
    +    private record Warning(String message, int position) {}
    +
    +    private static List warnings(String pattern) {
    +        List warnings = new ArrayList<>();
    +        byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        WarnCallback callback = new WarnCallback() {
    +            @Override
    +            public void warn(String message) {
    +                throw new AssertionError("warning missing position: " + message);
    +            }
    +
    +            @Override
    +            public void warn(String message, int position) {
    +                warnings.add(new Warning(message, position));
    +            }
    +
    +            @Override
    +            public boolean supportsPositions() {
    +                return true;
    +            }
    +        };
    +        new Regex(bytes, 0, bytes.length, Option.NONE, UTF8Encoding.INSTANCE,
    +                Syntax.PerlNG, callback);
    +        return warnings;
    +    }
    +
    +    @Test
    +    public void distinguishesValidInvalidAndUnimplementedSpellings() {
    +        assertEquals(List.of(new Warning(
    +                "POSIX syntax [: :] belongs inside character classes", 9)),
    +                warnings("[:alpha:]"));
    +        assertEquals(List.of(new Warning(
    +                "POSIX syntax [: :] belongs inside character classes "
    +                        + "(but this one isn't fully valid)", 7)),
    +                warnings("[:zog:]"));
    +        assertEquals(List.of(new Warning(
    +                "POSIX syntax [. .] belongs inside character classes "
    +                        + "(but this one isn't implemented)", 7)),
    +                warnings("[.zog.]"));
    +        assertEquals(List.of(new Warning(
    +                "POSIX syntax [= =] belongs inside character classes "
    +                        + "(but this one isn't implemented)", 7)),
    +                warnings("[=zog=]"));
    +    }
    +
    +    @Test
    +    public void doesNotWarnForNestedPosixClasses() {
    +        assertEquals(List.of(), warnings("[[:alpha:]]"));
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlPosixXDigit.java b/third_party/joni/test/org/joni/test/TestPerlPosixXDigit.java
    new file mode 100644
    index 0000000000..d0af89c827
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlPosixXDigit.java
    @@ -0,0 +1,58 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.CharacterPropertyResolver;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.junit.Test;
    +
    +public class TestPerlPosixXDigit {
    +    private static int search(String pattern, String input) {
    +        byte[] patternBytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        byte[] inputBytes = input.getBytes(StandardCharsets.UTF_8);
    +        CharacterPropertyResolver resolver =
    +                (bytes, p, end, encoding, inCharacterClass) ->
    +                        new CharacterPropertyResolver.Result(new int[] {
    +                                6, '0', '9', 'A', 'F', 'a', 'f',
    +                                0xFF10, 0xFF19, 0xFF21, 0xFF26,
    +                                0xFF41, 0xFF46
    +                        }, false);
    +        Syntax syntax = new Syntax("PerlPosixXDigit", Syntax.PerlNG.op,
    +                Syntax.PerlNG.op2, Syntax.PerlNG.op3,
    +                Syntax.PerlNG.behavior, Syntax.PerlNG.options,
    +                Syntax.PerlNG.metaCharTable, null, resolver);
    +        Regex regex = new Regex(patternBytes, 0, patternBytes.length,
    +                Option.NONE, UTF8Encoding.INSTANCE, syntax);
    +        return regex.matcher(inputBytes).search(0, inputBytes.length, Option.NONE);
    +    }
    +
    +    @Test
    +    public void includesPerlFullwidthHexDigits() {
    +        assertEquals(0, search("[[:xdigit:]]", "\uff15"));
    +        assertEquals(-1, search("[[:^xdigit:]]", "\uff15"));
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlQuantifierWarnings.java b/third_party/joni/test/org/joni/test/TestPerlQuantifierWarnings.java
    new file mode 100644
    index 0000000000..732b13e4e7
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlQuantifierWarnings.java
    @@ -0,0 +1,76 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +
    +import java.nio.charset.StandardCharsets;
    +import java.util.ArrayList;
    +import java.util.List;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.joni.WarnCallback;
    +import org.junit.Test;
    +
    +public class TestPerlQuantifierWarnings {
    +    private record Warning(String message, int position) {}
    +
    +    private static List warnings(String pattern) {
    +        byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        List warnings = new ArrayList<>();
    +        new Regex(bytes, 0, bytes.length, Option.NONE, UTF8Encoding.INSTANCE,
    +                Syntax.PerlNG, new WarnCallback() {
    +                    @Override
    +                    public void warn(String message) {
    +                        warnings.add(new Warning(message, -1));
    +                    }
    +
    +                    @Override
    +                    public void warn(String message, int bytePosition) {
    +                        warnings.add(new Warning(message, bytePosition));
    +                    }
    +
    +                    @Override
    +                    public boolean supportsPositions() {
    +                        return true;
    +                    }
    +                });
    +        return warnings;
    +    }
    +
    +    @Test
    +    public void locatesDescendingIntervalWarnings() {
    +        assertEquals(List.of(new Warning(
    +                "Quantifier {n,m} with n > m can't match", 6)),
    +                warnings("x{3,1}"));
    +    }
    +
    +    @Test
    +    public void locatesUselessNonGreedyFixedIntervals() {
    +        assertEquals(List.of(new Warning(
    +                "Useless use of greediness modifier '?'", 7)),
    +                warnings("a{1,1}?"));
    +        assertEquals(List.of(), warnings("a{1,2}?"));
    +        assertEquals(List.of(), warnings("a{1,1}+"));
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlRemainingNativeDiagnostics.java b/third_party/joni/test/org/joni/test/TestPerlRemainingNativeDiagnostics.java
    new file mode 100644
    index 0000000000..a1e58c216f
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlRemainingNativeDiagnostics.java
    @@ -0,0 +1,102 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +import static org.junit.Assert.assertThrows;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.joni.WarnCallback;
    +import org.joni.exception.SyntaxException;
    +import org.junit.Test;
    +
    +public class TestPerlRemainingNativeDiagnostics {
    +    private static SyntaxException error(String pattern) {
    +        byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        return assertThrows(SyntaxException.class,
    +                () -> new Regex(bytes, 0, bytes.length, Option.NONE,
    +                        UTF8Encoding.INSTANCE, Syntax.PerlNG, WarnCallback.NONE));
    +    }
    +
    +    private static void assertDiagnostic(String pattern, String message,
    +                                         int bytePosition) {
    +        SyntaxException error = error(pattern);
    +        assertEquals(message, error.getMessage());
    +        assertEquals(bytePosition, error.getPatternPosition());
    +    }
    +
    +    @Test
    +    public void positionsUnterminatedProperties() {
    +        assertDiagnostic("\\p{x", "Missing right brace on \\p{}", 3);
    +        assertDiagnostic("[\\P{x]", "Missing right brace on \\P{}", 4);
    +    }
    +
    +    @Test
    +    public void rejectsNonAsciiControlArgumentsAtTheArgumentEnd() {
    +        assertDiagnostic("\\cé",
    +                "Character following \"\\c\" must be printable ASCII", 4);
    +        assertDiagnostic("[\\cé]",
    +                "Character following \"\\c\" must be printable ASCII", 5);
    +    }
    +
    +    @Test
    +    public void reportsExtendedClassExpressionState() {
    +        String missingOperand = "(?[ \\cK + ])";
    +        assertDiagnostic(missingOperand, "Incomplete expression within '(?[ ])'",
    +                missingOperand.indexOf(']'));
    +
    +        String emptyParentheses = "(?[ ( ) ])";
    +        assertDiagnostic(emptyParentheses, "Incomplete expression within '(?[ ])'",
    +                emptyParentheses.indexOf(')') + 1);
    +
    +        String missingOuterParenthesis = "(?[ \\t ]";
    +        assertDiagnostic(missingOuterParenthesis,
    +                "Unexpected ']' with no following ')' in (?[...",
    +                missingOuterParenthesis.length());
    +
    +        String invalidPosix = "(?[[[:w:]]])";
    +        assertDiagnostic(invalidPosix,
    +                "Unexpected ']' with no following ')' in (?[...",
    +                invalidPosix.lastIndexOf("]]" ) + 1);
    +
    +        String standardLeafWithoutOuterClose = "(?[ [ \\t ]";
    +        assertDiagnostic(standardLeafWithoutOuterClose,
    +                "Syntax error in (?[...])", standardLeafWithoutOuterClose.length());
    +
    +        String commentConsumesClose = "(?[ \\t + \\e # comment ])";
    +        assertDiagnostic(commentConsumesClose, "Syntax error in (?[...])",
    +                commentConsumesClose.length());
    +    }
    +
    +    @Test
    +    public void positionsExtendedClassOctalWidthAfterTheEscape() {
    +        String tooShort = "(?[ \\05 ])";
    +        assertDiagnostic(tooShort, "Need exactly 3 octal digits",
    +                tooShort.indexOf(']'));
    +        String tooLong = "(?[ \\0004 ])";
    +        assertDiagnostic(tooLong, "Need exactly 3 octal digits",
    +                tooLong.indexOf(']'));
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlRepeatCaptureLifetime.java b/third_party/joni/test/org/joni/test/TestPerlRepeatCaptureLifetime.java
    new file mode 100644
    index 0000000000..884cc5c851
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlRepeatCaptureLifetime.java
    @@ -0,0 +1,95 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Matcher;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.junit.Test;
    +
    +public class TestPerlRepeatCaptureLifetime {
    +    private static Matcher match(String pattern, String input) {
    +        byte[] patternBytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        byte[] inputBytes = input.getBytes(StandardCharsets.UTF_8);
    +        Regex regex = new Regex(patternBytes, 0, patternBytes.length,
    +                Option.CAPTURE_GROUP, UTF8Encoding.INSTANCE, Syntax.RUBY);
    +        Matcher matcher = regex.matcher(inputBytes);
    +        assertEquals(pattern, 0, matcher.search(0, inputBytes.length, Option.NONE));
    +        return matcher;
    +    }
    +
    +    private static void assertLastAlternativeWins(Matcher matcher) {
    +        assertEquals(-1, matcher.getRegion().getBeg(1));
    +        assertEquals(-1, matcher.getRegion().getEnd(1));
    +        assertEquals(1, matcher.getRegion().getBeg(2));
    +        assertEquals(2, matcher.getRegion().getEnd(2));
    +    }
    +
    +    @Test
    +    public void clearsCapturesFromEarlierGreedyIterations() {
    +        assertLastAlternativeWins(match("^(?:(a)|(b))*$", "ab"));
    +    }
    +
    +    @Test
    +    public void restoresTheLastSuccessfulIterationAfterTheNextBodyFails() {
    +        assertLastAlternativeWins(match("^(?:(a)|(b))+$", "ab"));
    +    }
    +
    +    @Test
    +    public void clearsCapturesInExpandedFiniteRepeats() {
    +        assertLastAlternativeWins(match("^(?:(a)|(b)){2}$", "ab"));
    +    }
    +
    +    @Test
    +    public void exposesPreviousIterationToConditionInsideOpenCapture() {
    +        Matcher matcher = match("^((?(1)a|b))+$", "baaa");
    +        assertEquals(3, matcher.getRegion().getBeg(1));
    +        assertEquals(4, matcher.getRegion().getEnd(1));
    +    }
    +
    +    @Test
    +    public void exposesPreviousIterationToOptionalSelfBackref() {
    +        Matcher matcher = match("^(a\\1?){4}$", "aaaaaaaaaa");
    +        assertEquals(6, matcher.getRegion().getBeg(1));
    +        assertEquals(10, matcher.getRegion().getEnd(1));
    +    }
    +
    +    @Test
    +    public void exposesPreviousIterationToConditionalSelfBackref() {
    +        Matcher matcher = match("^(a(?(1)\\1)){4}$", "aaaaaaaaaa");
    +        assertEquals(6, matcher.getRegion().getBeg(1));
    +        assertEquals(10, matcher.getRegion().getEnd(1));
    +    }
    +
    +    @Test
    +    public void ordinaryAlternativeInvalidatesPreviousSelfCapture() {
    +        byte[] pattern = "^(xa|=?\\1a){2}$".getBytes(StandardCharsets.UTF_8);
    +        byte[] input = "xa=xaaa".getBytes(StandardCharsets.UTF_8);
    +        Regex regex = new Regex(pattern, 0, pattern.length,
    +                Option.CAPTURE_GROUP, UTF8Encoding.INSTANCE, Syntax.RUBY);
    +        assertEquals(-1, regex.matcher(input).search(0, input.length, Option.NONE));
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlScopedPropertyPolicy.java b/third_party/joni/test/org/joni/test/TestPerlScopedPropertyPolicy.java
    new file mode 100644
    index 0000000000..8010b320e6
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlScopedPropertyPolicy.java
    @@ -0,0 +1,100 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +
    +import java.nio.charset.StandardCharsets;
    +import java.util.ArrayList;
    +import java.util.List;
    +
    +import org.jcodings.Encoding;
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.CharacterPropertyResolver;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.junit.Test;
    +
    +public class TestPerlScopedPropertyPolicy {
    +    private static final CharacterPropertyResolver FOLD_POLICY_RESOLVER =
    +            (bytes, p, end, encoding, inCharacterClass) -> {
    +                String name = new String(bytes, p, end - p, StandardCharsets.UTF_8);
    +                return switch (name) {
    +                    case "Fold" -> new CharacterPropertyResolver.Result(
    +                            new int[] {1, 'B', 'B'}, true);
    +                    case "NoFold" -> new CharacterPropertyResolver.Result(
    +                            new int[] {1, 'A', 'A'}, false);
    +                    default -> null;
    +                };
    +            };
    +
    +    private static Syntax syntax(CharacterPropertyResolver resolver) {
    +        return new Syntax("PerlScopedPropertyPolicy", Syntax.PerlNG.op,
    +                Syntax.PerlNG.op2, Syntax.PerlNG.op3, Syntax.PerlNG.behavior,
    +                Syntax.PerlNG.options, Syntax.PerlNG.metaCharTable, null, resolver);
    +    }
    +
    +    private static Regex compile(String pattern, CharacterPropertyResolver resolver) {
    +        byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        return new Regex(bytes, 0, bytes.length, Option.NONE,
    +                UTF8Encoding.INSTANCE, syntax(resolver));
    +    }
    +
    +    private static int search(String pattern, String input) {
    +        byte[] bytes = input.getBytes(StandardCharsets.UTF_8);
    +        return compile(pattern, FOLD_POLICY_RESOLVER).matcher(bytes)
    +                .search(0, bytes.length, Option.NONE);
    +    }
    +
    +    @Test
    +    public void exposesLexicalOptionsToThePropertyResolver() {
    +        List modes = new ArrayList<>();
    +        CharacterPropertyResolver resolver = new CharacterPropertyResolver() {
    +            @Override
    +            public Result resolve(byte[] bytes, int p, int end, Encoding encoding,
    +                                  boolean inCharacterClass) {
    +                return null;
    +            }
    +
    +            @Override
    +            public Result resolve(byte[] bytes, int p, int end, Encoding encoding,
    +                                  boolean inCharacterClass, int option) {
    +                boolean ignoreCase = Option.isIgnoreCase(option);
    +                modes.add(ignoreCase);
    +                int member = ignoreCase ? 'B' : 'A';
    +                return new Result(new int[] {1, member, member}, false);
    +            }
    +        };
    +        Regex regex = compile("(?i:\\p{Mode})(?-i:\\p{Mode})", resolver);
    +        byte[] input = "BA".getBytes(StandardCharsets.UTF_8);
    +        assertEquals(0, regex.matcher(input).search(0, input.length, Option.NONE));
    +        assertEquals(List.of(true, false), modes);
    +    }
    +
    +    @Test
    +    public void preservesFoldPolicyInAStandardLeafOfAnExtendedClass() {
    +        String pattern = "(?i)(?[[\\p{NoFold}B]])";
    +        assertEquals(0, search(pattern, "A"));
    +        assertEquals(-1, search(pattern, "a"));
    +        assertEquals(0, search(pattern, "B"));
    +        assertEquals(0, search(pattern, "b"));
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlSimpleFoldClosure.java b/third_party/joni/test/org/joni/test/TestPerlSimpleFoldClosure.java
    new file mode 100644
    index 0000000000..9cda2ad749
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlSimpleFoldClosure.java
    @@ -0,0 +1,34 @@
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Matcher;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.junit.Test;
    +
    +public class TestPerlSimpleFoldClosure {
    +    private static int search(String pattern, String input) {
    +        byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        Regex regex = new Regex(bytes, 0, bytes.length, Option.IGNORECASE,
    +                UTF8Encoding.INSTANCE, Syntax.PerlNG);
    +        byte[] target = input.getBytes(StandardCharsets.UTF_8);
    +        Matcher matcher = regex.matcher(target);
    +        return matcher.search(0, target.length, Option.NONE);
    +    }
    +
    +    @Test
    +    public void foldsPinnedSimpleClassesWithoutBreakingScopedAsciiPolicy() {
    +        assertEquals(0, search("^(?d:k)$", "\u212a"));
    +        assertEquals(0, search("^(?u:\u00e5)$", "\u212b"));
    +        assertEquals(0, search("^(?a:kk)$", "\u212aK"));
    +        assertEquals(0, search("^(?d:[k])$", "\u212a"));
    +        assertEquals(-1, search("^(?aa:k)$", "\u212a"));
    +        assertEquals(0, search("^\u2c65$", "\u023a"));
    +        assertEquals(0, search("^\u2c66$", "\u023e"));
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlStrictLiteralWarnings.java b/third_party/joni/test/org/joni/test/TestPerlStrictLiteralWarnings.java
    new file mode 100644
    index 0000000000..ae048d715e
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlStrictLiteralWarnings.java
    @@ -0,0 +1,82 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +
    +import java.nio.charset.StandardCharsets;
    +import java.util.ArrayList;
    +import java.util.List;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.joni.WarnCallback;
    +import org.junit.Test;
    +
    +public class TestPerlStrictLiteralWarnings {
    +    private record Warning(String message, int position) {}
    +
    +    private static List warnings(String pattern, int option) {
    +        List warnings = new ArrayList<>();
    +        byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        WarnCallback callback = new WarnCallback() {
    +            @Override
    +            public void warn(String message) {
    +                throw new AssertionError("warning missing position: " + message);
    +            }
    +
    +            @Override
    +            public void warn(String message, int position) {
    +                warnings.add(new Warning(message, position));
    +            }
    +
    +            @Override
    +            public boolean supportsPositions() {
    +                return true;
    +            }
    +        };
    +        new Regex(bytes, 0, bytes.length, option, UTF8Encoding.INSTANCE,
    +                Syntax.PerlNG, callback);
    +        return warnings;
    +    }
    +
    +    @Test
    +    public void warnsForStrictUnescapedClosingDelimiters() {
    +        assertEquals(List.of(new Warning("Unescaped literal '}'", 7)),
    +                warnings("\\b new Regex(bytes, 0, bytes.length, options,
    +                        encoding, Syntax.PerlNG, WarnCallback.NONE));
    +    }
    +
    +    private static void assertError(String pattern, int options, String message,
    +                                    int bytePosition) {
    +        SyntaxException error = error(pattern, options);
    +        assertEquals(message, error.getMessage());
    +        assertEquals(bytePosition, error.getPatternPosition());
    +    }
    +
    +    private static List warnings(String pattern) {
    +        List warnings = new ArrayList<>();
    +        byte[] bytes = bytes(pattern);
    +        WarnCallback callback = new WarnCallback() {
    +            @Override
    +            public void warn(String message) {
    +                throw new AssertionError("warning missing position: " + message);
    +            }
    +
    +            @Override
    +            public void warn(String message, int position) {
    +                warnings.add(new Warning(message, position));
    +            }
    +
    +            @Override
    +            public boolean supportsPositions() {
    +                return true;
    +            }
    +        };
    +        new Regex(bytes, 0, bytes.length, Option.NONE,
    +                UTF8Encoding.INSTANCE, Syntax.PerlNG, callback);
    +        return warnings;
    +    }
    +
    +    @Test
    +    public void strictBracedEscapesAreFatalAtTheInvalidCharacter() {
    +        int strict = Option.PERL_RE_STRICT;
    +        assertError("\\o{789}", strict, "Non-octal character", 5);
    +        assertError("[\\o{789}]", strict, "Non-octal character", 6);
    +        assertError("\\x{defg}", strict, "Non-hex character", 7);
    +        assertError("\\o{ 1 20 }", strict, "Non-octal character", 6);
    +        assertError("\\x{}", strict, "Empty \\x{}", 4);
    +        assertError("[\\x{}]", strict, "Empty \\x{}", 5);
    +    }
    +
    +    @Test
    +    public void extendedClassBracedEscapesAreFatalWithoutStrictOption() {
    +        String octal = "(?[ \\o{1038} ])";
    +        assertError(octal, Option.NONE, "Non-octal character",
    +                bytes(octal.substring(0, octal.indexOf('8') + 1)).length);
    +        String hex = "(?[ \\x{defg} ])";
    +        assertError(hex, Option.NONE, "Non-hex character",
    +                bytes(hex.substring(0, hex.indexOf('g') + 1)).length);
    +        String unicode = "(?[ \\o{ネ} ])";
    +        assertError(unicode, Option.NONE, "Non-octal character",
    +                bytes(unicode.substring(0, unicode.indexOf('ネ') + 1)).length);
    +
    +        String bytePattern = "(?[ \\x{ï} ])";
    +        SyntaxException byteError = error(
    +                bytePattern, Option.NONE, ISO8859_1Encoding.INSTANCE);
    +        assertEquals("Non-hex character", byteError.getMessage());
    +        assertEquals(bytePattern.indexOf('ï') + 1, byteError.getPatternPosition());
    +    }
    +
    +    @Test
    +    public void strictUnbracedHexErrorsRetainTokenEndPositions() {
    +        int strict = Option.PERL_RE_STRICT;
    +        assertError("\\xABC", strict,
    +                "Use \\x{...} for more than two hex characters", 5);
    +        assertError("[\\xABC]", strict,
    +                "Use \\x{...} for more than two hex characters", 6);
    +        assertError("\\xAG", strict, "Non-hex character", 4);
    +        assertError("\\x", strict, "Empty \\x", 2);
    +    }
    +
    +    @Test
    +    public void strictClassLegacyOctalRequiresExactlyThreeDigits() {
    +        int strict = Option.PERL_RE_STRICT;
    +        assertError("[\\08]", strict, "Need exactly 3 octal digits", 4);
    +        assertError("[\\018]", strict, "Need exactly 3 octal digits", 5);
    +        assertError("[\\0]", strict, "Need exactly 3 octal digits", 4);
    +        assertError("[\\07]", strict, "Need exactly 3 octal digits", 5);
    +        assertError("[\\0005]", strict, "Need exactly 3 octal digits", 7);
    +        assertError("[\\_\\0]", strict, "Need exactly 3 octal digits", 6);
    +    }
    +
    +    @Test
    +    public void nonStrictWarningsRetainPerlTextAndPositions() {
    +        assertEquals(List.of(new Warning(
    +                "Non-octal character '8' terminates \\0 early.  Resolved as \"\\0008\"",
    +                3)), warnings("\\08"));
    +        assertEquals(List.of(new Warning(
    +                "Non-octal character '8' terminates \\0 early.  Resolved as \"\\0008\"",
    +                4)), warnings("[\\08]"));
    +        assertEquals(List.of(new Warning(
    +                "Non-hex character 'G' terminates \\x early.  Resolved as \"\\x0AG\"",
    +                3)), warnings("\\xAG"));
    +        assertEquals(List.of(new Warning(
    +                "Non-hex character 'g' terminates \\x early.  Resolved as \"\\x{ABC}\"",
    +                8)), warnings("\\x{ABCg}"));
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlStrictOrdinaryNamedRangeWarnings.java b/third_party/joni/test/org/joni/test/TestPerlStrictOrdinaryNamedRangeWarnings.java
    new file mode 100644
    index 0000000000..8f7d8780db
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlStrictOrdinaryNamedRangeWarnings.java
    @@ -0,0 +1,103 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.joni.constants.SyntaxProperties.ALLOW_MULTIPLEX_DEFINITION_NAME_CALL;
    +import static org.joni.constants.SyntaxProperties.OP2_OPTION_PERL;
    +import static org.joni.constants.SyntaxProperties.OP2_OPTION_RUBY;
    +import static org.junit.Assert.assertEquals;
    +
    +import java.nio.charset.StandardCharsets;
    +import java.util.ArrayList;
    +import java.util.List;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.NamedCharacterResolver;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.joni.WarnCallback;
    +import org.junit.Test;
    +
    +public class TestPerlStrictOrdinaryNamedRangeWarnings {
    +    private record Warning(String message, int position) {}
    +
    +    private static final NamedCharacterResolver NAMED =
    +            (bytes, p, end, encoding) -> {
    +                String name = new String(bytes, p, end - p, StandardCharsets.US_ASCII);
    +                return name.startsWith("U+")
    +                        ? Integer.parseInt(name.substring(2), 16) : 0;
    +            };
    +
    +    private static final Syntax SYNTAX = new Syntax(
    +            "PERLONJAVA", Syntax.RUBY.op,
    +            (Syntax.RUBY.op2 & ~OP2_OPTION_RUBY) | OP2_OPTION_PERL,
    +            Syntax.RUBY.op3,
    +            Syntax.RUBY.behavior | ALLOW_MULTIPLEX_DEFINITION_NAME_CALL,
    +            Syntax.RUBY.options & ~(Option.ASCII_RANGE
    +                    | Option.POSIX_BRACKET_ALL_RANGE | Option.WORD_BOUND_ALL_RANGE),
    +            Syntax.RUBY.metaCharTable, NAMED);
    +
    +    private static List warnings(String pattern) {
    +        List warnings = new ArrayList<>();
    +        byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        WarnCallback callback = new WarnCallback() {
    +            @Override
    +            public void warn(String message) {
    +                throw new AssertionError("warning missing position: " + message);
    +            }
    +
    +            @Override
    +            public void warn(String message, int position) {
    +                warnings.add(new Warning(message, position));
    +            }
    +
    +            @Override
    +            public boolean supportsPositions() {
    +                return true;
    +            }
    +        };
    +        new Regex(bytes, 0, bytes.length, Option.PERL_RE_STRICT,
    +                UTF8Encoding.INSTANCE, SYNTAX, callback);
    +        return warnings;
    +    }
    +
    +    @Test
    +    public void warnsForMixedNamedEndpointsInStrictOrdinaryClasses() {
    +        for (String pattern : List.of(
    +                "[\\N{U+00}-\\x01]",
    +                "[\\x00-\\N{U+01}]",
    +                "[\\N{U+7F}-\\o{377}]",
    +                "[\\o{0}-\\N{U+01}]",
    +                "[\\000-\\N{U+01}]",
    +                "[\\N{U+7F}-\\377]")) {
    +            assertEquals(List.of(new Warning(
    +                    "Both or neither range ends should be Unicode",
    +                    pattern.length() - 1)), warnings(pattern));
    +        }
    +
    +        for (String pattern : List.of(
    +                "[\\N{U+00}-\\a]",
    +                "[\\a-\\N{U+FF}]",
    +                "[\\N{U+100}-\\x{101}]")) {
    +            assertEquals(List.of(), warnings(pattern));
    +        }
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlStrictRangeWarnings.java b/third_party/joni/test/org/joni/test/TestPerlStrictRangeWarnings.java
    new file mode 100644
    index 0000000000..5a929031bf
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlStrictRangeWarnings.java
    @@ -0,0 +1,182 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.joni.constants.SyntaxProperties.ALLOW_MULTIPLEX_DEFINITION_NAME_CALL;
    +import static org.joni.constants.SyntaxProperties.OP2_OPTION_PERL;
    +import static org.joni.constants.SyntaxProperties.OP2_OPTION_RUBY;
    +import static org.junit.Assert.assertEquals;
    +import static org.junit.Assert.fail;
    +
    +import java.nio.charset.StandardCharsets;
    +import java.util.ArrayList;
    +import java.util.List;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.NamedCharacterResolver;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.joni.WarnCallback;
    +import org.joni.exception.SyntaxException;
    +import org.junit.Test;
    +
    +public class TestPerlStrictRangeWarnings {
    +    private record Warning(String message, int position) {}
    +
    +    private static final NamedCharacterResolver NAMED =
    +            (bytes, p, end, encoding) -> 0;
    +
    +    private static final Syntax SYNTAX = new Syntax(
    +            "PERLONJAVA", Syntax.RUBY.op,
    +            (Syntax.RUBY.op2 & ~OP2_OPTION_RUBY) | OP2_OPTION_PERL,
    +            Syntax.RUBY.op3,
    +            Syntax.RUBY.behavior | ALLOW_MULTIPLEX_DEFINITION_NAME_CALL,
    +            Syntax.RUBY.options & ~(Option.ASCII_RANGE
    +                    | Option.POSIX_BRACKET_ALL_RANGE | Option.WORD_BOUND_ALL_RANGE),
    +            Syntax.RUBY.metaCharTable, NAMED);
    +
    +    private static List warnings(String pattern) {
    +        return warnings(pattern, Option.NONE);
    +    }
    +
    +    private static List warnings(String pattern, int option) {
    +        List warnings = new ArrayList<>();
    +        byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        WarnCallback callback = new WarnCallback() {
    +            @Override
    +            public void warn(String message) {
    +                throw new AssertionError("warning missing position: " + message);
    +            }
    +
    +            @Override
    +            public void warn(String message, int position) {
    +                warnings.add(new Warning(message, position));
    +            }
    +
    +            @Override
    +            public boolean supportsPositions() {
    +                return true;
    +            }
    +        };
    +        new Regex(bytes, 0, bytes.length, option, UTF8Encoding.INSTANCE,
    +                SYNTAX, callback);
    +        return warnings;
    +    }
    +
    +    private static int endpointPosition(String pattern) {
    +        return pattern.substring(0, pattern.indexOf(" ]"))
    +                .getBytes(StandardCharsets.UTF_8).length + 1;
    +    }
    +
    +    private static void assertFalseRange(String pattern, String diagnostic,
    +                                         int position) {
    +        byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        try {
    +            new Regex(bytes, 0, bytes.length, Option.NONE, UTF8Encoding.INSTANCE,
    +                    SYNTAX, WarnCallback.NONE);
    +            fail("expected false range error for " + pattern);
    +        } catch (SyntaxException error) {
    +            assertEquals("False [] range", error.getMessage());
    +            assertEquals(diagnostic, error.getDiagnosticMessage());
    +            assertEquals(position, error.getPatternPosition());
    +        }
    +    }
    +
    +    @Test
    +    public void warnsForStrictAsciiAndDigitRanges() {
    +        String ascii = "(?[ [ A - a ] ])";
    +        assertEquals(List.of(new Warning(
    +                "Ranges of ASCII printables should be some subset of \"0-9\", "
    +                        + "\"A-Z\", or \"a-z\"", endpointPosition(ascii))),
    +                warnings(ascii));
    +
    +        String digits = "(?[ [ \u1a89 - \u1a90 ] ])";
    +        assertEquals(List.of(new Warning(
    +                "Ranges of digits should be from the same group of 10",
    +                endpointPosition(digits))), warnings(digits));
    +    }
    +
    +    @Test
    +    public void warnsForEquivalentDifferentlySpelledEndpoints() {
    +        String colon = "(?[ [ : - \\x3A ] ])";
    +        assertEquals(List.of(new Warning(
    +                "\": - \\x3A \" is more clearly written simply as \":\"",
    +                endpointPosition(colon))), warnings(colon));
    +
    +        String tab = "(?[ [ \\t - \\x09 ] ])";
    +        assertEquals(List.of(new Warning(
    +                "\"\\t - \\x09 \" is more clearly written simply as \"\\t\"",
    +                endpointPosition(tab))), warnings(tab));
    +    }
    +
    +    @Test
    +    public void warnsForRangesInStrictOrdinaryClasses() {
    +        assertEquals(List.of(new Warning(
    +                "Ranges of ASCII printables should be some subset of \"0-9\", "
    +                        + "\"A-Z\", or \"a-z\"", 4)),
    +                warnings("[A-a]", Option.PERL_RE_STRICT));
    +        assertEquals(List.of(new Warning(
    +                "\":-\\x3A\" is more clearly written simply as \":\"", 7)),
    +                warnings("[:-\\x3A]", Option.PERL_RE_STRICT));
    +    }
    +
    +    @Test
    +    public void treatsPosixClassesAsFalseRangeEndpoints() {
    +        assertEquals(List.of(new Warning("False [] range \"a-[:digit:]\"", 12)),
    +                warnings("[a-[:digit:]]"));
    +        assertEquals(List.of(new Warning("False [] range \"[:digit:]-\"", 11)),
    +                warnings("[[:digit:]-b]"));
    +    }
    +
    +    @Test
    +    public void preservesNamedEndpointProvenance() {
    +        String mixed = "(?[ [ \\N{ZERO} - \\x01 ] ])";
    +        assertEquals(List.of(new Warning(
    +                "Both or neither range ends should be Unicode",
    +                endpointPosition(mixed))), warnings(mixed));
    +    }
    +
    +    @Test
    +    public void rejectsCharacterClassRangeEndpointsInExtendedClasses() {
    +        String rightType = "(?[[a-\\d]])";
    +        assertFalseRange(rightType, "False [] range \"a-\\d\"",
    +                rightType.indexOf("\\d") + 2);
    +
    +        String leftType = "(?[[\\w-x]])";
    +        assertFalseRange(leftType, "False [] range \"\\w-\"",
    +                leftType.indexOf('-') + 1);
    +
    +        String rightProperty = "(?[[a-\\pM]])";
    +        assertFalseRange(rightProperty, "False [] range \"a-\\pM\"",
    +                rightProperty.indexOf("\\pM") + 3);
    +
    +        String leftProperty = "(?[[\\pM-x]])";
    +        assertFalseRange(leftProperty, "False [] range \"\\pM-\"",
    +                leftProperty.indexOf('-') + 1);
    +    }
    +
    +    @Test
    +    public void acceptsCanonicalRangesWithoutWarnings() {
    +        assertEquals(List.of(), warnings("(?[ [ A-Z ] ])"));
    +        assertEquals(List.of(), warnings("(?[ [ % - % ] ])"));
    +        assertEquals(List.of(), warnings("(?[ [ \u1a80-\u1a89 ] ])"));
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlStrictSpacedPosixWarnings.java b/third_party/joni/test/org/joni/test/TestPerlStrictSpacedPosixWarnings.java
    new file mode 100644
    index 0000000000..faa7313a1c
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlStrictSpacedPosixWarnings.java
    @@ -0,0 +1,71 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +
    +import java.nio.charset.StandardCharsets;
    +import java.util.ArrayList;
    +import java.util.List;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.joni.WarnCallback;
    +import org.junit.Test;
    +
    +public class TestPerlStrictSpacedPosixWarnings {
    +    private record Warning(String message, int position) {}
    +
    +    @Test
    +    public void retainsOneLexerOwnedClosingBracketWarning() {
    +        String pattern = "[[   ^   :   x d i g i t   :   ]   ]";
    +        byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        List warnings = new ArrayList<>();
    +        WarnCallback callback = new WarnCallback() {
    +            @Override
    +            public void warn(String message) {
    +                throw new AssertionError("warning missing position: " + message);
    +            }
    +
    +            @Override
    +            public void warn(String message, int position) {
    +                warnings.add(new Warning(message, position));
    +            }
    +
    +            @Override
    +            public boolean supportsPositions() {
    +                return true;
    +            }
    +        };
    +
    +        new Regex(bytes, 0, bytes.length, Option.PERL_RE_STRICT,
    +                UTF8Encoding.INSTANCE, Syntax.PerlNG, callback);
    +
    +        assertEquals(List.of(
    +                new Warning("Assuming NOT a POSIX class since no blanks are allowed in one", 5),
    +                new Warning("Assuming NOT a POSIX class since the '^' must come after the colon", 6),
    +                new Warning("Assuming NOT a POSIX class since no blanks are allowed in one", 9),
    +                new Warning("Assuming NOT a POSIX class since no blanks are allowed in one", 13),
    +                new Warning("Assuming NOT a POSIX class since no blanks are allowed in one", 32),
    +                new Warning("Unescaped literal ']'", 36)), warnings);
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlStrictVerticalSpace.java b/third_party/joni/test/org/joni/test/TestPerlStrictVerticalSpace.java
    new file mode 100644
    index 0000000000..fd9a438738
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlStrictVerticalSpace.java
    @@ -0,0 +1,56 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +import static org.junit.Assert.assertThrows;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.joni.WarnCallback;
    +import org.joni.exception.SyntaxException;
    +import org.junit.Test;
    +
    +public class TestPerlStrictVerticalSpace {
    +    private static void compile(String pattern, int option) {
    +        byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        new Regex(bytes, 0, bytes.length, option, UTF8Encoding.INSTANCE,
    +                Syntax.PerlNG, WarnCallback.NONE);
    +    }
    +
    +    @Test
    +    public void rejectsLiteralVerticalSpaceOutsideExtendedMoreClasses() {
    +        SyntaxException error = assertThrows(SyntaxException.class,
    +                () -> compile("[a\fb]", Option.PERL_RE_STRICT));
    +        assertEquals("Literal vertical space in [] is illegal except under /x",
    +                error.getMessage());
    +        assertEquals(3, error.getPatternPosition());
    +    }
    +
    +    @Test
    +    public void permitsLiteralVerticalSpaceUnderExtendedMore() {
    +        compile("[a\fb]", Option.PERL_RE_STRICT
    +                | Option.EXTEND | Option.PERL_EXTEND_MORE);
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlUtf8WordClassComplement.java b/third_party/joni/test/org/joni/test/TestPerlUtf8WordClassComplement.java
    new file mode 100644
    index 0000000000..b87c315697
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlUtf8WordClassComplement.java
    @@ -0,0 +1,79 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.ISO8859_1Encoding;
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.junit.Test;
    +
    +public class TestPerlUtf8WordClassComplement {
    +    private static int search(String pattern, String input) {
    +        byte[] patternBytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        byte[] inputBytes = input.getBytes(StandardCharsets.UTF_8);
    +        Regex regex = new Regex(patternBytes, 0, patternBytes.length,
    +                Option.NONE, UTF8Encoding.INSTANCE, Syntax.TEST);
    +        return regex.matcher(inputBytes).search(0, inputBytes.length, Option.NONE);
    +    }
    +
    +    private static int searchByte(String pattern, int input) {
    +        byte[] patternBytes = pattern.getBytes(StandardCharsets.ISO_8859_1);
    +        byte[] inputBytes = {(byte) input};
    +        Regex regex = new Regex(patternBytes, 0, patternBytes.length,
    +                Option.ASCII_RANGE, ISO8859_1Encoding.INSTANCE, Syntax.TEST);
    +        return regex.matcher(inputBytes).search(0, inputBytes.length, Option.NONE);
    +    }
    +
    +    @Test
    +    public void latin1SupplementBelongsToExactlyOneWordClass() {
    +        for (int codePoint = 0x80; codePoint <= 0xff; codePoint++) {
    +            String character = new String(Character.toChars(codePoint));
    +            int word = search("[\\w]", character);
    +            int notWord = search("[\\W]", character);
    +            assertEquals("U+" + Integer.toHexString(codePoint),
    +                    word < 0 ? 0 : 1, notWord < 0 ? 1 : 0);
    +        }
    +    }
    +
    +    @Test
    +    public void wordClassesRemainComplementaryAcrossEncodingBoundaries() {
    +        for (int codePoint : new int[] {0x7f, 0x80, 0xaa, 0xff, 0x100, 0x200c}) {
    +            String character = new String(Character.toChars(codePoint));
    +            int word = search("[\\w]", character);
    +            int notWord = search("[\\W]", character);
    +            assertEquals("U+" + Integer.toHexString(codePoint),
    +                    word < 0 ? 0 : 1, notWord < 0 ? 1 : 0);
    +        }
    +    }
    +
    +    @Test
    +    public void asciiRestrictedByteClassComplementIncludesHighBytes() {
    +        for (int value = 0x80; value <= 0xff; value++) {
    +            assertEquals("byte " + Integer.toHexString(value),
    +                    0, searchByte("[\\W]", value));
    +        }
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlVariableLookbehindWarnings.java b/third_party/joni/test/org/joni/test/TestPerlVariableLookbehindWarnings.java
    new file mode 100644
    index 0000000000..7554b296ed
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlVariableLookbehindWarnings.java
    @@ -0,0 +1,86 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +import static org.joni.constants.SyntaxProperties.ALLOW_MULTIPLEX_DEFINITION_NAME_CALL;
    +import static org.joni.constants.SyntaxProperties.OP2_OPTION_PERL;
    +import static org.joni.constants.SyntaxProperties.OP2_OPTION_RUBY;
    +
    +import java.nio.charset.StandardCharsets;
    +import java.util.ArrayList;
    +import java.util.List;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.joni.WarnCallback;
    +import org.junit.Test;
    +
    +public class TestPerlVariableLookbehindWarnings {
    +    private static final Syntax PERLONJAVA = new Syntax(
    +            "PERLONJAVA", Syntax.RUBY.op,
    +            (Syntax.RUBY.op2 & ~OP2_OPTION_RUBY) | OP2_OPTION_PERL,
    +            Syntax.RUBY.op3,
    +            Syntax.RUBY.behavior | ALLOW_MULTIPLEX_DEFINITION_NAME_CALL,
    +            Syntax.RUBY.options, Syntax.RUBY.metaCharTable);
    +
    +    private record Warning(String message, int position) {}
    +
    +    private static final class Warnings implements WarnCallback {
    +        final List messages = new ArrayList<>();
    +
    +        @Override
    +        public void warn(String message) {
    +            messages.add(new Warning(message, -1));
    +        }
    +
    +        @Override
    +        public void warn(String message, int position) {
    +            messages.add(new Warning(message, position));
    +        }
    +
    +        @Override
    +        public boolean supportsPositions() {
    +            return true;
    +        }
    +    }
    +
    +    private static void assertCaptureWarning(String pattern, String direction) {
    +        byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        Warnings warnings = new Warnings();
    +        new Regex(bytes, 0, bytes.length, Option.CAPTURE_GROUP | Option.EXTEND,
    +                UTF8Encoding.INSTANCE, PERLONJAVA, warnings);
    +        assertEquals(List.of(new Warning("Variable length " + direction
    +                + " lookbehind with capturing is experimental", bytes.length)),
    +                warnings.messages);
    +    }
    +
    +    @Test
    +    public void warnsForVariableLookbehindCaptures() {
    +        assertCaptureWarning("(?<=(p|qq|rrr))", "positive");
    +        assertCaptureWarning("(? warnings(String pattern) {
    +        List warnings = new ArrayList<>();
    +        byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        WarnCallback callback = new WarnCallback() {
    +            @Override
    +            public void warn(String message) {
    +                throw new AssertionError("warning missing position: " + message);
    +            }
    +
    +            @Override
    +            public void warn(String message, int position) {
    +                warnings.add(new Warning(message, position));
    +            }
    +
    +            @Override
    +            public boolean supportsPositions() {
    +                return true;
    +            }
    +        };
    +        new Regex(bytes, 0, bytes.length, Option.NONE, UTF8Encoding.INSTANCE,
    +                Syntax.PerlNG, callback);
    +        return warnings;
    +    }
    +
    +    @Test
    +    public void locatesEachUselessInlineModifier() {
    +        assertEquals(List.of(
    +                new Warning("Useless (?o)", 3),
    +                new Warning("Useless (?g)", 4),
    +                new Warning("Useless (?c)", 5)),
    +                warnings("(?ogc)"));
    +        assertEquals(List.of(
    +                new Warning("Useless (?-c)", 4),
    +                new Warning("Useless (?-o)", 6)),
    +                warnings("(?-cgo)"));
    +    }
    +
    +    @Test
    +    public void locatesUnboundedZeroWidthRepeats() {
    +        assertEquals(List.of(new Warning(
    +                "\\b* matches null string many times", 3)), warnings("\\b*"));
    +        assertEquals(List.of(new Warning(
    +                "(?=a)+ matches null string many times", 6)), warnings("(?=a)+"));
    +        assertEquals(List.of(), warnings("\\b?"));
    +    }
    +
    +    @Test
    +    public void locatesUnknownAlphabeticEscapesInCharacterClasses() {
    +        assertEquals(List.of(new Warning(
    +                "Unrecognized escape \\y in character class passed through", 3)),
    +                warnings("[\\y]"));
    +        assertEquals(List.of(new Warning(
    +                "Unrecognized escape \\z in character class passed through", 4)),
    +                warnings("[a\\zb]"));
    +    }
    +
    +    @Test
    +    public void locatesUnknownNumericEscapesInCharacterClasses() {
    +        assertEquals(List.of(
    +                new Warning("Unrecognized escape \\8 in character class passed through", 3),
    +                new Warning("Unrecognized escape \\9 in character class passed through", 5)),
    +                warnings("[\\8\\9]"));
    +    }
    +
    +    @Test
    +    public void locatesDeprecatedExtendedWhitespaceClassLiterals() {
    +        assertEquals(List.of(new Warning(
    +                "Use of unescaped '#' in [] is deprecated under /xx", 8)),
    +                warnings("(?xx:[a#b])"));
    +        assertEquals(List.of(new Warning(
    +                "Use of literal vertical space in [] is deprecated under /xx", 8)),
    +                warnings("(?xx:[a\nb])"));
    +        assertEquals(List.of(), warnings("(?xx:[a\\#b])"));
    +    }
    +
    +    @Test
    +    public void locatesUnknownAlphabeticEscapesOutsideCharacterClasses() {
    +        assertEquals(List.of(new Warning(
    +                "Unrecognized escape \\y passed through", 2)), warnings("\\y"));
    +        assertEquals(List.of(new Warning(
    +                "Unrecognized escape \\q passed through", 3)), warnings("a\\q"));
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlWordBoundaryIgnoredSequences.java b/third_party/joni/test/org/joni/test/TestPerlWordBoundaryIgnoredSequences.java
    new file mode 100644
    index 0000000000..45b9a05877
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlWordBoundaryIgnoredSequences.java
    @@ -0,0 +1,101 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.junit.Test;
    +
    +public class TestPerlWordBoundaryIgnoredSequences {
    +    private static int search(String pattern, String input) {
    +        byte[] patternBytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        byte[] inputBytes = input.getBytes(StandardCharsets.UTF_8);
    +        Regex regex = new Regex(patternBytes, 0, patternBytes.length, Option.NONE,
    +                UTF8Encoding.INSTANCE, Syntax.PerlNG);
    +        return regex.matcher(inputBytes).search(0, inputBytes.length, Option.NONE);
    +    }
    +
    +    private static void assertBoundary(String left, String right) {
    +        assertEquals(0, search("\\A" + left + "\\b{wb}" + right + "\\z", left + right));
    +    }
    +
    +    private static void assertNoBoundary(String left, String right) {
    +        assertEquals(0, search("\\A" + left + "\\B{wb}" + right + "\\z", left + right));
    +    }
    +
    +    @Test
    +    public void keepsPerlWordWhitespaceRunsTogether() {
    +        assertNoBoundary(" ", "\r");
    +        assertNoBoundary("\r", " ");
    +        assertNoBoundary(" ", "\n");
    +        assertNoBoundary("\n", " ");
    +        assertNoBoundary(" ", "\u000b");
    +        assertNoBoundary("\u000b", " ");
    +        assertEquals(0, search("\\A \\B{wb} \\B{wb}\\r\\z", "  \r"));
    +    }
    +
    +    @Test
    +    public void bindsWSegSpaceToExtendOrFormatSuccessors() {
    +        assertEquals(0, search("\\A \\B{wb} \\b{wb} \\B{wb}\\x{0308}\\z", "   \u0308"));
    +        assertEquals(0, search("\\A \\B{wb} \\b{wb} \\B{wb}\\x{00ad}\\z", "   \u00ad"));
    +        assertEquals(0, search("\\A \\B{wb} \\B{wb} \\B{wb}\\x{200d}\\z", "   \u200d"));
    +        assertEquals(0, search("\\A \\B{wb} \\B{wb}\\t\\B{wb}\\x{200d}\\z", "  \t\u200d"));
    +        assertEquals(0, search("\\A \\B{wb} \\b{wb}\\t\\B{wb}\\x{0308}\\z", "  \t\u0308"));
    +        assertEquals(0, search("\\A \\B{wb} \\B{wb}\\x{00a0}\\B{wb}\\x{200d}\\z",
    +                "  \u00a0\u200d"));
    +        assertEquals(0, search("\\A \\B{wb} \\B{wb}\\x{2007}\\B{wb}\\x{200d}\\z",
    +                "  \u2007\u200d"));
    +        assertEquals(0, search("\\A \\B{wb} \\b{wb}\\x{202f}\\B{wb}\\x{200d}\\z",
    +                "  \u202f\u200d"));
    +        assertEquals(0, search("\\A \\b{wb} \\B{wb}\\x{0308}\\z", "  \u0308"));
    +        assertEquals(0, search("\\A\\r\\B{wb} \\B{wb}\\x{0308}\\z", "\r \u0308"));
    +        assertEquals(0, search("\\A \\B{wb} \\b{wb}\\x{1680}\\B{wb}\\x{0308}\\z",
    +                "  \u1680\u0308"));
    +        assertNoBoundary("\u1680", "\r");
    +    }
    +
    +    @Test
    +    public void keepsNewlineAndIgnoredRulesOrdered() {
    +        assertBoundary("\r", "\u0308");
    +        assertBoundary("\n", "\u00ad");
    +        assertBoundary("\u000b", "\u200d");
    +        assertEquals(0, search("\\A\\r\\b{wb}\\x{0308}\\b{wb}\\n\\z", "\r\u0308\n"));
    +    }
    +
    +    @Test
    +    public void preservesIgnoredSequenceContext() {
    +        assertEquals(0, search("\\A\\x{1f469}\\B{wb}\\x{0308}\\B{wb}\\x{200d}"
    +                + "\\B{wb}\\x{1f680}\\z", "\uD83D\uDC69\u0308\u200d\uD83D\uDE80"));
    +        assertEquals(0, search("\\A\\x{1f1e6}\\B{wb}\\x{0308}\\B{wb}"
    +                + "\\x{1f1e7}\\z", "\uD83C\uDDE6\u0308\uD83C\uDDE7"));
    +        assertEquals(0, search("\\A\\x{1f1e6}\\B{wb}\\x{1f1e7}\\B{wb}\\x{0308}"
    +                + "\\b{wb}\\x{1f1e8}\\z",
    +                "\uD83C\uDDE6\uD83C\uDDE7\u0308\uD83C\uDDE8"));
    +        assertEquals(0, search("\\A\\b{wb}\\x{0308}\\b{wb}A\\b{wb}\\z", "\u0308A"));
    +        assertEquals(0, search("\\A\\b{wb}A\\B{wb}\\x{0308}\\b{wb}\\z", "A\u0308"));
    +        assertEquals(0, search("\\A(?: \\B{wb} X| \\B{wb} \\B{wb}\\r\\b{wb}A)\\z", "  \rA"));
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlWordBoundaryNewlineRuns.java b/third_party/joni/test/org/joni/test/TestPerlWordBoundaryNewlineRuns.java
    new file mode 100644
    index 0000000000..57157946e6
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlWordBoundaryNewlineRuns.java
    @@ -0,0 +1,71 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +
    +import java.nio.charset.StandardCharsets;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.junit.Test;
    +
    +public class TestPerlWordBoundaryNewlineRuns {
    +    private static int search(String pattern, String input) {
    +        byte[] patternBytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        byte[] inputBytes = input.getBytes(StandardCharsets.UTF_8);
    +        Regex regex = new Regex(patternBytes, 0, patternBytes.length, Option.NONE,
    +                UTF8Encoding.INSTANCE, Syntax.PerlNG);
    +        return regex.matcher(inputBytes).search(0, inputBytes.length, Option.NONE);
    +    }
    +
    +    private static void assertBoundary(String left, String right) {
    +        assertEquals(0, search("\\A" + left + "\\b{wb}" + right + "\\z", left + right));
    +    }
    +
    +    private static void assertNoBoundary(String left, String right) {
    +        assertEquals(0, search("\\A" + left + "\\B{wb}" + right + "\\z", left + right));
    +    }
    +
    +    @Test
    +    public void keepsRunsOfNewlinePropertiesTogether() {
    +        assertNoBoundary("\r", "\r");
    +        assertNoBoundary("\r", "\n");
    +        assertNoBoundary("\n", "\r");
    +        assertNoBoundary("\n", "\n");
    +        assertNoBoundary("\r", "\u000b");
    +        assertNoBoundary("\u000b", "\r");
    +        assertNoBoundary("\u000b", "\u000b");
    +        assertNoBoundary("\u0085", "\u2028");
    +        assertNoBoundary("\u2028", "\u2029");
    +    }
    +
    +    @Test
    +    public void stillBreaksAtNewlineRunEdges() {
    +        assertBoundary("\r", "A");
    +        assertBoundary("A", "\r");
    +        assertBoundary("\u000b", "_");
    +        assertEquals(0, search("\\A\\b{wb}\\r\\B{wb}\\r\\b{wb}A\\b{wb}\\z", "\r\rA"));
    +        assertEquals(-1, search("\\A\\B{wb}\\r\\r\\z", "\r\r"));
    +        assertEquals(-1, search("\\A\\r\\r\\B{wb}\\z", "\r\r"));
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestPerlZeroLengthQuantifierWarnings.java b/third_party/joni/test/org/joni/test/TestPerlZeroLengthQuantifierWarnings.java
    new file mode 100644
    index 0000000000..e29a79ce87
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestPerlZeroLengthQuantifierWarnings.java
    @@ -0,0 +1,59 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +
    +import java.nio.charset.StandardCharsets;
    +import java.util.ArrayList;
    +import java.util.List;
    +
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.joni.WarnCallback;
    +import org.junit.Test;
    +
    +public class TestPerlZeroLengthQuantifierWarnings {
    +    private static final class Warnings implements WarnCallback {
    +        final List messages = new ArrayList<>();
    +
    +        @Override
    +        public void warn(String message) {
    +            messages.add(message);
    +        }
    +    }
    +
    +    private static void assertZeroLengthWarning(String pattern) {
    +        byte[] bytes = pattern.getBytes(StandardCharsets.UTF_8);
    +        Warnings warnings = new Warnings();
    +        new Regex(bytes, 0, bytes.length, Option.NONE,
    +                UTF8Encoding.INSTANCE, Syntax.PerlNG, warnings);
    +        assertEquals(List.of("Quantifier unexpected on zero-length expression in regex m/"
    +                + pattern + "/"), warnings.messages);
    +    }
    +
    +    @Test
    +    public void warnsForLookaheadIntervals() {
    +        assertZeroLengthWarning("(?=a){1,3}\\x{100}");
    +        assertZeroLengthWarning("(a|b)(?=a){3}\\x{100}");
    +    }
    +}
    diff --git a/third_party/joni/test/org/joni/test/TestRawCharacterPropertyResolver.java b/third_party/joni/test/org/joni/test/TestRawCharacterPropertyResolver.java
    new file mode 100644
    index 0000000000..31eb516db3
    --- /dev/null
    +++ b/third_party/joni/test/org/joni/test/TestRawCharacterPropertyResolver.java
    @@ -0,0 +1,106 @@
    +/*
    + * 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.
    + */
    +package org.joni.test;
    +
    +import static org.junit.Assert.assertEquals;
    +import static org.junit.Assert.assertTrue;
    +
    +import java.nio.charset.Charset;
    +import java.nio.charset.StandardCharsets;
    +import java.util.ArrayList;
    +import java.util.List;
    +
    +import org.jcodings.Encoding;
    +import org.jcodings.specific.ISO8859_1Encoding;
    +import org.jcodings.specific.UTF8Encoding;
    +import org.joni.CharacterPropertyResolver;
    +import org.joni.Option;
    +import org.joni.Regex;
    +import org.joni.Syntax;
    +import org.junit.Test;
    +
    +public class TestRawCharacterPropertyResolver {
    +    private static Syntax syntax(CharacterPropertyResolver resolver) {
    +        return new Syntax("RawCharacterPropertyResolver", Syntax.PerlNG.op,
    +                Syntax.PerlNG.op2, Syntax.PerlNG.op3, Syntax.PerlNG.behavior,
    +                Syntax.PerlNG.options, Syntax.PerlNG.metaCharTable, null, resolver);
    +    }
    +
    +    private static int search(String pattern, String input, Encoding encoding,
    +                              Charset charset, int option,
    +                              CharacterPropertyResolver resolver) {
    +        byte[] patternBytes = pattern.getBytes(charset);
    +        byte[] inputBytes = input.getBytes(charset);
    +        Regex regex = new Regex(patternBytes, 0, patternBytes.length, option,
    +                encoding, syntax(resolver));
    +        return regex.matcher(inputBytes).search(0, inputBytes.length, Option.NONE);
    +    }
    +
    +    @Test
    +    public void exposesRawTokensContextsOptionsAndEncodings() {
    +        List calls = new ArrayList<>();
    +        CharacterPropertyResolver resolver = new CharacterPropertyResolver() {
    +            @Override
    +            public Result resolve(byte[] bytes, int p, int end, Encoding encoding,
    +                                  boolean inCharacterClass) {
    +                return null;
    +            }
    +
    +            @Override
    +            public Result resolve(byte[] bytes, int p, int end, Encoding encoding,
    +                                  boolean inCharacterClass, int option) {
    +                Charset charset = encoding == ISO8859_1Encoding.INSTANCE
    +                        ? StandardCharsets.ISO_8859_1 : StandardCharsets.UTF_8;
    +                String token = new String(bytes, p, end - p, charset);
    +                calls.add(token + "|" + encoding.getClass().getSimpleName()
    +                        + "|" + inCharacterClass + "|" + Option.isIgnoreCase(option));
    +                int member = switch (token) {
    +                    case "Script = Greek" -> 'A';
    +                    case "Script_Extensions=Hira" -> 'B';
    +                    case "Block:Greek" -> 'C';
    +                    case "Age=1.1" -> 'D';
    +                    case "Present_In=2.0" -> 'E';
    +                    case "PerlWord" -> 'F';
    +                    default -> -1;
    +                };
    +                return member < 0 ? null
    +                        : new Result(new int[] {1, member, member}, true);
    +            }
    +        };
    +
    +        assertEquals(0, search("\\p{Script = Greek}", "A", UTF8Encoding.INSTANCE,
    +                StandardCharsets.UTF_8, Option.NONE, resolver));
    +        assertEquals(0, search("[\\p{Script_Extensions=Hira}]", "B",
    +                UTF8Encoding.INSTANCE, StandardCharsets.UTF_8, Option.NONE, resolver));
    +        assertEquals(0, search("(?[ \\p{Block:Greek} | \\p{Age=1.1} ])", "D",
    +                UTF8Encoding.INSTANCE, StandardCharsets.UTF_8, Option.NONE, resolver));
    +        assertEquals(0, search("(?i)\\p{Present_In=2.0}", "e",
    +                UTF8Encoding.INSTANCE, StandardCharsets.UTF_8, Option.NONE, resolver));
    +        assertEquals(0, search("\\p{PerlWord}", "F", ISO8859_1Encoding.INSTANCE,
    +                StandardCharsets.ISO_8859_1, Option.PERL_BYTE_PATTERN, resolver));
    +
    +        assertTrue(calls.contains("Script = Greek|UTF8Encoding|false|false"));
    +        assertTrue(calls.contains("Script_Extensions=Hira|UTF8Encoding|true|false"));
    +        assertTrue(calls.contains("Block:Greek|UTF8Encoding|false|false"));
    +        assertTrue(calls.contains("Age=1.1|UTF8Encoding|false|false"));
    +        assertTrue(calls.contains("Present_In=2.0|UTF8Encoding|false|true"));
    +        assertTrue(calls.contains("PerlWord|ISO8859_1Encoding|false|false"));
    +    }
    +}