diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 11e8eda..094ffc2 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -21,6 +21,10 @@ jobs:
id: "custom_theme_overrides",
name: "Custom Theme Overrides",
}
+ - {
+ id: "git_sha_project_setting",
+ name: "Git SHA Project Setting",
+ }
- {
id: "glogging",
name: "GLogging",
@@ -38,8 +42,8 @@ jobs:
name: "Licenses",
}
- {
- id: "git_sha_project_setting",
- name: "Git SHA Project Setting",
+ id: "qr_code",
+ name: "QR Code",
}
- {
id: "texture_button_colored",
diff --git a/README.md b/README.md
index 57fd197..458807a 100644
--- a/README.md
+++ b/README.md
@@ -1,18 +1,46 @@
# Godot Addons
-- [AspectRatioResizeContainer](#aspectratioresizecontainer)
-- [Custom Theme Overrides](#custom-theme-overrides)
-- [Hide Private Properties](#hide-private-properties)
-- [Icons Patcher](#icons-patcher)
-- [License Manager](#license-manager)
-- [Logging](#logging)
-- [Metadata](#metadata)
-- [TextureButtonColored](#texturebuttoncolored)
+Download [here](https://github.com/kenyoni-software/godot-addons/releases/tag/latest).
+
+## License
+
+[MIT License](./LICENSE.md)
+
+## Overview
+
+### Nodes
+
+- [AspectRatioResizeContainer](#aspectratioresizecontainer)
+ Extension of `AspectRatioContainer` to update it's own size.
+- [TextureButtonColored](#texturebuttoncolored)
+ Extension of `TextureButton` with color options.
+- [Logging](#logging)
+ Simple logger.
+- [QR Code (beta)](#qr-code)
+ QRCodeRect and QR Code generation.
+
+### Tools
+
+- [Git SHA Project Setting](#git-sha-project-setting)
+ Add Git SHA as project setting.
+- [Hide Private Properties](#hide-private-properties)
+ Hide private properties of instantiated child scenes.
+- [Icons Patcher](#icons-patcher)
+ Patch Pictogrammers icons to white.
+- [License Manager](#license-manager)
+ Manage license and copyright for third party graphics, software or libraries.
+
+### Utility
+
+- [Custom Theme Overrides](#custom-theme-overrides)
+ Utility to provide custom theme overrides for any node.
+
+---
## AspectRatioResizeContainer
-The AspectRatioContainer allows his own size to be smaller than the children, which causes neighboring UI elements to be covered.
-This new node type will extend the existing AspectRatioContainer and update it's own minimum size based on the children.
+The `AspectRatioContainer` allows his own size to be smaller than the children, which causes neighboring UI elements to be covered.
+This new node type will extend the existing `AspectRatioContainer` and update it's own minimum size based on the children.
This works except for `STRETCH_MODE_COVER`.
You are also not able to use the property `custom_minimum_size` anymore as it is used to set the minimum size.
@@ -25,6 +53,8 @@ You are also not able to use the property `custom_minimum_size` anymore as it is
[examples/aspect_ratio_resize_container](./examples/aspect_ratio_resize_container)
+---
+
## Custom Theme Overrides
If you have a custom theme for your own nodes or just need custom theme overrides in your node, this plugin will give you some helping utility.
@@ -45,7 +75,6 @@ If everything is set up, your theme override variables can be handled like every
### Example
-
```gdscript
# declare the members
# DO NOT
@@ -61,29 +90,55 @@ var my_style_box: StyleBox
# declare the custom theme overrides, use the member name and the theme data type.
var _theme_overrides = CustomThemeOverrides.new([
- ["my_font_color", Theme.DATA_TYPE_COLOR],
- ["my_border_size", Theme.DATA_TYPE_CONSTANT],
- ["my_font", Theme.DATA_TYPE_FONT],
- ["my_font_size", Theme.DATA_TYPE_FONT_SIZE],
- ["my_icon", Theme.DATA_TYPE_ICON],
- ["my_style_box", Theme.DATA_TYPE_STYLEBOX]
+ ["my_font_color", Theme.DATA_TYPE_COLOR],
+ ["my_border_size", Theme.DATA_TYPE_CONSTANT],
+ ["my_font", Theme.DATA_TYPE_FONT],
+ ["my_font_size", Theme.DATA_TYPE_FONT_SIZE],
+ ["my_icon", Theme.DATA_TYPE_ICON],
+ ["my_style_box", Theme.DATA_TYPE_STYLEBOX]
])
# required, if you have other properties use append_array
func _get_property_list() -> Array[Dictionary]:
- return self._theme_overrides.theme_property_list(self)
+ return self._theme_overrides.theme_property_list(self)
# optional: if you want to use the revert function
func _property_can_revert(property: StringName) -> bool:
- return self._theme_overrides.can_revert(property)
+ return self._theme_overrides.can_revert(property)
# optional: if you want to use the revert function, return null
func _property_get_revert(_property: StringName) -> Variant:
- return null
+ return null
```
[examples/custom_theme_overrides](./examples/custom_theme_overrides)
+---
+
+## Git SHA Project Setting
+
+Previously named `Metadata`.
+
+Adds the project setting `application/config/git_sha`, which contains the current Git SHA.
+This one is automatically set and updated when you run any scene or on exporting the project. The git_sha will **not** be kept in `project.godot` to not clutter any version control system. It will be removed from the settings on closing the Godot Editor.
+
+### Compatibility
+
+- Godot 4.1
+
+### Example
+
+[examples/metadata](./examples/metadata)
+
+### Changelog
+
+#### 2.0.0
+
+Added an initial Git SHA load on opening the project.
+Removed `application/config/version`, there was no need that this was part of the addon. The value can still be added manually.
+
+---
+
## Hide Private Properties
Private members (names starting with an underscore) should not be exposed.
@@ -98,6 +153,8 @@ This plugin will hide exported private properties in the inspector for instantia
[examples/hide_private_properties](./examples/hide_private_properties)
+---
+
## Icons Patcher
If you use Material Design icons from [Pictogrammers](https://pictogrammers.com/library/mdi/), they come without any fill color, automatically rendered black. This is not a convenient color as it makes it impossible to modulate the color. The icon patcher provides a utility to automatically patch the icons to white color.
@@ -116,6 +173,8 @@ Then use `Project` -> `Tools` -> `Icons Patcher` to patch the icons.
- Added automatic file reimporting.
+---
+
## License Manager
Manage license and copyright for third party graphics, software or libraries.
@@ -151,6 +210,8 @@ Component class, data wrapper for all information regarding one license item.
License class.
+---
+
## Logging
Simple logger. An autoload `GLogging` will be created at installation.
@@ -185,50 +246,161 @@ Logging into a file is not supported yet. The output will be always done via pri
Logging base class. Provides helper methods.
-- `root_logger` - root logger object
-- `debug(message: Variant, values: Array[Variant] = [])` - log with root logger at debug level
-- `info(message: Variant, values: Array[Variant] = [])` - log with root logger at info level
-- `warning(message: Variant, values: Array[Variant] = [])` - log with root logger at warning level, will also display a debug warning
-- `error(message: Variant, values: Array[Variant] = [])` - log with root logger at error level, will also display a debug error
-- `critical(message: Variant, values: Array[Variant] = [])` - log with root logger at critical level
-- `log(level: int, message: Variant, values: Array[Variant] = [])` - log at custom level
+- `root_logger: Logger`
+ root logger object
+- `debug(message: Variant, values: Array[Variant] = []) -> void`
+ log with root logger at debug level
+- `info(message: Variant, values: Array[Variant] = []) -> void`
+ log with root logger at info level
+- `warning(message: Variant, values: Array[Variant] = []) -> void`
+ log with root logger at warning level, will also display a debug warning
+- `error(message: Variant, values: Array[Variant] = []) -> void`
+ log with root logger at error level, will also display a debug error
+- `critical(message: Variant, values: Array[Variant] = []) -> void`
+ log with root logger at critical level
+- `log(level: int, message: Variant, values: Array[Variant] = []) -> void`
+ log at custom level
**GLogging.Logger** - [`addons/glogging/glogging.gd`](./addons/glogging/glogging.gd)
Logger class.
If not log level is set, the log level of the parent logger will be used.
-- `create_child(module_name: String, log_level: int = LEVEL_NOTSET)` - create a child logger
-- `set_log_level(level: int)` - set the log level
-- `log_level() -> int` - get log level
-- `debug(message: Variant, values: Array[Variant] = [])` - log at debug level
-- `info(message: Variant, values: Array[Variant] = [])` - log at info level
-- `warning(message: Variant, values: Array[Variant] = [])` - log at warning level, will also display a debug warning
-- `error(message: Variant, values: Array[Variant] = [])` - log at error level, will also display a debug error
-- `critical(message: Variant, values: Array[Variant] = [])` - log at critical level
-- `log(level: int, message: Variant, values: Array[Variant] = [])` - log at custom level
+- `create_child(module_name: String, log_level: int = LEVEL_NOTSET) -> Logger`
+ create a child logger
+- `set_log_level(level: int) -> void`
+ set the log level
+- `log_level() -> int`
+ get log level
+- `debug(message: Variant, values: Array[Variant] = []) -> void`
+ log at debug level
+- `info(message: Variant, values: Array[Variant] = []) -> void`
+ log at info level
+- `warning(message: Variant, values: Array[Variant] = []) -> void`
+ log at warning level, will also display a debug warning
+- `error(message: Variant, values: Array[Variant] = []) -> void`
+ log at error level, will also display a debug error
+- `critical(message: Variant, values: Array[Variant] = []) -> void`
+ log at critical level
+- `log(level: int, message: Variant, values: Array[Variant] = []) -> void`
+ log at custom level
-## Git SHA Project Setting
-Previously named `Metadata`.
+---
-Adds the project setting `application/config/git_sha`, which contains the current Git SHA.
-This one is automatically set and updated when you run any scene or on exporting the project. The git_sha will **not** be kept in `project.godot` to not clutter any version control system. It will be removed from the settings on closing the Godot Editor.
+## QR Code
+
+> *This addon might change it's interface and available functions.
+> Please test and report any issues.*
+
+QR Code generation either with the included `QRCodeRect` node or use the encoding result of the `QRCode` class.
### Compatibility
- Godot 4.1
-### Example
+### Screenshot
-[examples/metadata](./examples/metadata)
+![QRCodeRect node inspector screenshot](./doc/qr_code.png "QRCodeRect in inspector")
-### Changelog
+### Example
-#### 2.0.0
+[examples/qr_code](./examples/qr_code)
-Added an initial Git SHA load on opening the project.
-Removed `application/config/version`, there was no need that this was part of the addon. The value can still be added manually.
+### Classes & Functions
+
+**QRCodeRect** - [`addons/qr_code/qr_code_rect.gd`](./addons/qr_code/qr_code_rect.gd)
+
+`TextureRect` like node. The texture is updated by itself.
+
+#### Properties
+
+- `mode: QRCode.Mode`
+- `error_correction: QRCode.ErrorCorrection`
+- `eci_value: int`
+ Extended Channel Interpretation (ECI) Value
+- `data: Variant`
+ Type varies based on the encoding mode.
+- `auto_version: bool`
+ Use automatically the smallest QR Code version.
+- `version: int`
+- `auto_mask_pattern: bool`
+ Use automatically the best mask pattern.
+- `mask_pattern: int`
+- `light_module_color: Color`
+- `dark_module_color: Color`
+- `auto_module_px_size: bool`
+ Automatically set the module pixel size based on the size.
+ Do not use expand mode KEEP_SIZE when using it.
+ Turn this off when the QR Code changes or is resized often, as it impacts the performance quite heavily.
+- `module_px_size: int`
+ Use that many pixel for one module.
+
+**QRCode** - [`addons/qr_code/qr_code.gd`](./addons/qr_code/qr_code.gd)
+
+QRCode class to generate QR Codes.
+
+#### Enums
+
+- `Mode`
+ Encoding mode enum.
+ - `NUMERIC = 1`
+ - `ALPHANUMERIC = 2`
+ - `BYTE = 4`
+ - `KANJI = 8`
+- `ErrorCorrection`
+ Error correction enum.
+ - `LOW = 1`
+ - `MEDIUM = 0`
+ - `QUARTILE = 3`
+ - `HIGH = 2`
+- `ECI`
+ Extended Channel Interpretation enum. Provides some values by name.
+
+#### Properties
+
+- `mode: Mode`
+- `error_correction: ErrorCorrection`
+- `eci_value: int`
+ Extended Channel Interpretation (ECI) Value
+- `auto_version: bool`
+ Use automatically the smallest QR Code version.
+- `version: int`
+- `auto_mask_pattern: bool`
+ Use automatically the best mask pattern.
+- `mask_pattern: int`
+
+#### Methods
+
+- `get_module_count() -> int`
+ Get the module count per side.
+- `calc_min_version() -> int`
+ Get the minimal version required to encode the data.
+- `generate_image(module_px_size: int = 1, light_module_color: Color = Color.WHITE, dark_module_color: Color = Color.BLACK) -> Image`
+ Generate an image. This method can be called repeatedly, as encoding will only happens once and be cached.
+- `put_numeric(number: String) -> void`
+ Put a numeric text as data. Invalid characters are removed. Will change the encoding mode to `Mode.NUMERIC`.
+- `put_alphanumeric(text: String) -> void`
+ Put a alphanumeric text as data. Invalid characters are removed. Will change the encoding mode to `Mode.ALPHANUMERIC`.
+- `put_byte(data: PackedByteArray) -> void`
+ Put a byte data. Will change the encoding mode to `Mode.BYTE`.
+- `put_numeric(number: String) -> void`
+ Put a numeric text as data. Invalid characters are removed. Will change the encoding mode to `Mode.KANJI`.
+- `encode() -> PackedByteArray`
+ Get the QR Code row by row in one array. To get the row size use `get_module_count`.
+
+**ShiftJIS** - [`addons/qr_code/shift_jis.gd`](./addons/qr_code/shift_jis.gd)
+
+Shift JIS encoding utility.
+
+### Functions
+
+- `static func to_shift_jis_2004_buffer(text: String) -> PackedByteArray`
+- `static func get_string_from_jis_2004(arr: PackedByteArray) -> String`
+- `static func to_jis_8_buffer(text: String) -> PackedByteArray`
+- `static func get_string_from_jis_8(arr: PackedByteArray) -> String`
+
+---
## TextureButtonColored
@@ -241,8 +413,3 @@ Let you apply the icon color theme properties for the texture button. Uses `self
### Example
[examples/texture_button_colored](./examples/texture_button_colored)
-
-
-## License
-
-[MIT License](./LICENSE.md)
diff --git a/addons/git_sha_project_setting/plugin.cfg b/addons/git_sha_project_setting/plugin.cfg
index d694d35..a9a6c03 100644
--- a/addons/git_sha_project_setting/plugin.cfg
+++ b/addons/git_sha_project_setting/plugin.cfg
@@ -1,7 +1,7 @@
[plugin]
name="Git SHA Project Setting"
-description="Adds Git SHA as prohect setting at application/config/git_sha"
+description="Adds Git SHA as prohect setting at application/config/git_sha - MIT License"
author="Iceflower S"
version="2.0.0"
script="plugin.gd"
diff --git a/addons/qr_code/bit_stream.gd b/addons/qr_code/bit_stream.gd
new file mode 100644
index 0000000..ac422c1
--- /dev/null
+++ b/addons/qr_code/bit_stream.gd
@@ -0,0 +1,84 @@
+extends RefCounted
+
+var _data: PackedByteArray = []
+
+func duplicate():
+ var dup = new()
+ dup._data = self._data.duplicate()
+ return dup
+
+func resize(size: int) -> void:
+ self._data.resize(size)
+
+func size() -> int:
+ return self._data.size()
+
+func clear() -> void:
+ return self._data.clear()
+
+func get_array() -> PackedByteArray:
+ return self._data
+
+func to_byte_array() -> PackedByteArray:
+ var byte_arr: PackedByteArray = []
+
+ var cur_byte: int = 0
+ for idx in range(self._data.size()):
+ var byte_idx: int = 7 - idx % 8
+ if self._data[idx]:
+ cur_byte = _set_state(cur_byte, byte_idx)
+ if (idx != 0 && byte_idx == 0) || idx == self._data.size() - 1:
+ byte_arr.append(cur_byte)
+ cur_byte = 0
+ return byte_arr
+
+func prepend_bit(bit: bool) -> void:
+ self._data.insert(0, int(bit))
+
+func append_bit(bit: bool) -> void:
+ self._data.append(int(bit))
+
+func append_stream(stream) -> void:
+ self._data.append_array(stream.get_array())
+
+func append_byte_array(arr: PackedByteArray) -> void:
+ for val in arr:
+ self.append(val, 8)
+
+func prepend(value: int, total_bits: int) -> void:
+ for idx in range(total_bits - 1, -1, -1):
+ self._data.insert(0, int(get_state(value, idx)))
+
+func append(value: int, total_bits: int) -> void:
+ for idx in range(total_bits - 1, -1, -1):
+ self._data.append(int(get_state(value, idx)))
+
+func set_bit(idx: int, bit: bool) -> void:
+ self._data[idx] = int(bit)
+
+func get_bit(idx: int) -> bool:
+ return bool(self._data[idx])
+
+func _to_string() -> String:
+ var val: String = ""
+ for idx in range(self._data.size()):
+ if (idx + 1) % 8 == 1:
+ val += "["
+ val += str(self._data[idx])
+ if (idx + 1) % 8 == 0:
+ val += "]"
+ if (idx + 1) % 4 == 0:
+ val += " "
+ val = val.strip_edges()
+ if val[-1] != "]":
+ val += "]"
+ return val
+
+static func _set_state(value: int, idx: int) -> int:
+ return value | (1 << idx)
+
+static func get_state(value: int, idx: int) -> bool:
+ return (value & (1 << idx))
+
+static func toggle_state(value: int, idx: int) -> int:
+ return value ^ (1 << idx)
diff --git a/addons/qr_code/plugin.cfg b/addons/qr_code/plugin.cfg
new file mode 100644
index 0000000..ec76922
--- /dev/null
+++ b/addons/qr_code/plugin.cfg
@@ -0,0 +1,7 @@
+[plugin]
+
+name="QR Code"
+description="QR Code generator. - MIT License"
+author="Iceflower S"
+version="0.1.0"
+script="plugin.gd"
diff --git a/addons/qr_code/plugin.gd b/addons/qr_code/plugin.gd
new file mode 100644
index 0000000..80be667
--- /dev/null
+++ b/addons/qr_code/plugin.gd
@@ -0,0 +1,9 @@
+@tool
+extends EditorPlugin
+
+func _enter_tree() -> void:
+ self.add_custom_type("QRCodeRect", "TextureRect", preload("qr_code_rect.gd"), preload("qr_code.svg"))
+
+func _exit_tree() -> void:
+ self.remove_custom_type("QRCodeRect")
+ self.get_editor_interface().get_inspector().property_toggled.disconnect(self._test)
diff --git a/addons/qr_code/qr_code.gd b/addons/qr_code/qr_code.gd
new file mode 100644
index 0000000..bd248b3
--- /dev/null
+++ b/addons/qr_code/qr_code.gd
@@ -0,0 +1,1470 @@
+extends RefCounted
+
+const BitStream := preload("bit_stream.gd")
+const ReedSolomon := preload("reed_solomon.gd")
+const ShiftJIS := preload("shift_jis.gd")
+
+## Encoding Mode
+enum Mode {
+ ## 0001
+ NUMERIC = 1,
+ ## 0010
+ ALPHANUMERIC = 2,
+ ## 0100
+ BYTE = 4,
+ ## 1000
+ KANJI = 8
+}
+
+## Error Correction
+enum ErrorCorrection {
+ LOW = 1,
+ MEDIUM = 0,
+ QUARTILE = 3,
+ HIGH = 2
+}
+
+## Extended Channel Interpretation
+enum ECI {
+ CODE_PAGE_437 = 2,
+ ISO_8859_1 = 3,
+ ISO_8859_2 = 4,
+ ISO_8859_3 = 5,
+ ISO_8859_4 = 6,
+ ISO_8859_5 = 7,
+ ISO_8859_6 = 8,
+ ISO_8859_7 = 9,
+ ISO_8859_8 = 10,
+ ISO_8859_9 = 11,
+ ISO_8859_10 = 12,
+ ISO_8859_11 = 13,
+ ISO_8859_12 = 14,
+ ISO_8859_13 = 15,
+ ISO_8859_14 = 16,
+ ISO_8859_15 = 17,
+ ISO_8859_16 = 18,
+ SHIFT_JIS = 20,
+ WINDOWS_1250 = 21,
+ WINDOWS_1251 = 22,
+ WINDOWS_1252 = 23,
+ WINDOWS_1256 = 24,
+ UTF_16 = 25,
+ UTF_8 = 26,
+ US_ASCII = 27,
+ BIG_5 = 28,
+ GB_18030 = 29,
+ EUC_KR = 30
+}
+
+const _DATA_CAPACITY: Array[Dictionary] = [
+ # 1
+ {
+ ErrorCorrection.LOW: { Mode.NUMERIC: 41, Mode.ALPHANUMERIC: 25, Mode.BYTE: 17, Mode.KANJI: 10 },
+ ErrorCorrection.MEDIUM: { Mode.NUMERIC: 34, Mode.ALPHANUMERIC: 20, Mode.BYTE: 14, Mode.KANJI: 8 },
+ ErrorCorrection.QUARTILE: { Mode.NUMERIC: 27, Mode.ALPHANUMERIC: 16, Mode.BYTE: 11, Mode.KANJI: 7 },
+ ErrorCorrection.HIGH: { Mode.NUMERIC: 17, Mode.ALPHANUMERIC: 10, Mode.BYTE: 7, Mode.KANJI: 4 },
+ },
+ # 2
+ {
+ ErrorCorrection.LOW: { Mode.NUMERIC: 77, Mode.ALPHANUMERIC: 47, Mode.BYTE: 32, Mode.KANJI: 20 },
+ ErrorCorrection.MEDIUM: { Mode.NUMERIC: 63, Mode.ALPHANUMERIC: 38, Mode.BYTE: 26, Mode.KANJI: 16 },
+ ErrorCorrection.QUARTILE: { Mode.NUMERIC: 48, Mode.ALPHANUMERIC: 29, Mode.BYTE: 20, Mode.KANJI: 12 },
+ ErrorCorrection.HIGH: { Mode.NUMERIC: 34, Mode.ALPHANUMERIC: 20, Mode.BYTE: 14, Mode.KANJI: 8 },
+ },
+ {
+ ErrorCorrection.LOW: { Mode.NUMERIC: 127, Mode.ALPHANUMERIC: 77, Mode.BYTE: 53, Mode.KANJI: 32 },
+ ErrorCorrection.MEDIUM: { Mode.NUMERIC: 101, Mode.ALPHANUMERIC: 61, Mode.BYTE: 42, Mode.KANJI: 26 },
+ ErrorCorrection.QUARTILE: { Mode.NUMERIC: 77, Mode.ALPHANUMERIC: 47, Mode.BYTE: 32, Mode.KANJI: 20 },
+ ErrorCorrection.HIGH: { Mode.NUMERIC: 58, Mode.ALPHANUMERIC: 35, Mode.BYTE: 24, Mode.KANJI: 15 },
+ },
+ {
+ ErrorCorrection.LOW: { Mode.NUMERIC: 187, Mode.ALPHANUMERIC: 114, Mode.BYTE: 78, Mode.KANJI: 48 },
+ ErrorCorrection.MEDIUM: { Mode.NUMERIC: 149, Mode.ALPHANUMERIC: 90, Mode.BYTE: 62, Mode.KANJI: 38 },
+ ErrorCorrection.QUARTILE: { Mode.NUMERIC: 111, Mode.ALPHANUMERIC: 67, Mode.BYTE: 46, Mode.KANJI: 28 },
+ ErrorCorrection.HIGH: { Mode.NUMERIC: 82, Mode.ALPHANUMERIC: 50, Mode.BYTE: 34, Mode.KANJI: 21 },
+ },
+ {
+ ErrorCorrection.LOW: { Mode.NUMERIC: 255, Mode.ALPHANUMERIC: 154, Mode.BYTE: 106, Mode.KANJI: 65 },
+ ErrorCorrection.MEDIUM: { Mode.NUMERIC: 202, Mode.ALPHANUMERIC: 122, Mode.BYTE: 84, Mode.KANJI: 52 },
+ ErrorCorrection.QUARTILE: { Mode.NUMERIC: 144, Mode.ALPHANUMERIC: 87, Mode.BYTE: 60, Mode.KANJI: 37 },
+ ErrorCorrection.HIGH: { Mode.NUMERIC: 106, Mode.ALPHANUMERIC: 64, Mode.BYTE: 44, Mode.KANJI: 27 },
+ },
+ {
+ ErrorCorrection.LOW: { Mode.NUMERIC: 322, Mode.ALPHANUMERIC: 195, Mode.BYTE: 134, Mode.KANJI: 82 },
+ ErrorCorrection.MEDIUM: { Mode.NUMERIC: 255, Mode.ALPHANUMERIC: 154, Mode.BYTE: 106, Mode.KANJI: 65 },
+ ErrorCorrection.QUARTILE: { Mode.NUMERIC: 178, Mode.ALPHANUMERIC: 108, Mode.BYTE: 74, Mode.KANJI: 45 },
+ ErrorCorrection.HIGH: { Mode.NUMERIC: 139, Mode.ALPHANUMERIC: 84, Mode.BYTE: 58, Mode.KANJI: 36 },
+ },
+ {
+ ErrorCorrection.LOW: { Mode.NUMERIC: 370, Mode.ALPHANUMERIC: 224, Mode.BYTE: 154, Mode.KANJI: 95 },
+ ErrorCorrection.MEDIUM: { Mode.NUMERIC: 293, Mode.ALPHANUMERIC: 178, Mode.BYTE: 122, Mode.KANJI: 75 },
+ ErrorCorrection.QUARTILE: { Mode.NUMERIC: 207, Mode.ALPHANUMERIC: 125, Mode.BYTE: 86, Mode.KANJI: 53 },
+ ErrorCorrection.HIGH: { Mode.NUMERIC: 154, Mode.ALPHANUMERIC: 93, Mode.BYTE: 64, Mode.KANJI: 39 },
+ },
+ {
+ ErrorCorrection.LOW: { Mode.NUMERIC: 461, Mode.ALPHANUMERIC: 279, Mode.BYTE: 192, Mode.KANJI: 118 },
+ ErrorCorrection.MEDIUM: { Mode.NUMERIC: 365, Mode.ALPHANUMERIC: 221, Mode.BYTE: 152, Mode.KANJI: 93 },
+ ErrorCorrection.QUARTILE: { Mode.NUMERIC: 259, Mode.ALPHANUMERIC: 157, Mode.BYTE: 108, Mode.KANJI: 66 },
+ ErrorCorrection.HIGH: { Mode.NUMERIC: 202, Mode.ALPHANUMERIC: 122, Mode.BYTE: 84, Mode.KANJI: 52 },
+ },
+ {
+ ErrorCorrection.LOW: { Mode.NUMERIC: 552, Mode.ALPHANUMERIC: 335, Mode.BYTE: 230, Mode.KANJI: 141 },
+ ErrorCorrection.MEDIUM: { Mode.NUMERIC: 432, Mode.ALPHANUMERIC: 262, Mode.BYTE: 180, Mode.KANJI: 111 },
+ ErrorCorrection.QUARTILE: { Mode.NUMERIC: 312, Mode.ALPHANUMERIC: 189, Mode.BYTE: 130, Mode.KANJI: 80 },
+ ErrorCorrection.HIGH: { Mode.NUMERIC: 235, Mode.ALPHANUMERIC: 143, Mode.BYTE: 98, Mode.KANJI: 60 },
+ },
+ {
+ ErrorCorrection.LOW: { Mode.NUMERIC: 652, Mode.ALPHANUMERIC: 395, Mode.BYTE: 271, Mode.KANJI: 167 },
+ ErrorCorrection.MEDIUM: { Mode.NUMERIC: 513, Mode.ALPHANUMERIC: 311, Mode.BYTE: 213, Mode.KANJI: 131 },
+ ErrorCorrection.QUARTILE: { Mode.NUMERIC: 364, Mode.ALPHANUMERIC: 221, Mode.BYTE: 151, Mode.KANJI: 93 },
+ ErrorCorrection.HIGH: { Mode.NUMERIC: 288, Mode.ALPHANUMERIC: 174, Mode.BYTE: 119, Mode.KANJI: 74 },
+ },
+ {
+ ErrorCorrection.LOW: { Mode.NUMERIC: 772, Mode.ALPHANUMERIC: 468, Mode.BYTE: 321, Mode.KANJI: 198 },
+ ErrorCorrection.MEDIUM: { Mode.NUMERIC: 604, Mode.ALPHANUMERIC: 366, Mode.BYTE: 251, Mode.KANJI: 155 },
+ ErrorCorrection.QUARTILE: { Mode.NUMERIC: 427, Mode.ALPHANUMERIC: 259, Mode.BYTE: 177, Mode.KANJI: 109 },
+ ErrorCorrection.HIGH: { Mode.NUMERIC: 331, Mode.ALPHANUMERIC: 200, Mode.BYTE: 137, Mode.KANJI: 85 },
+ },
+ {
+ ErrorCorrection.LOW: { Mode.NUMERIC: 883, Mode.ALPHANUMERIC: 535, Mode.BYTE: 367, Mode.KANJI: 226 },
+ ErrorCorrection.MEDIUM: { Mode.NUMERIC: 691, Mode.ALPHANUMERIC: 419, Mode.BYTE: 287, Mode.KANJI: 177 },
+ ErrorCorrection.QUARTILE: { Mode.NUMERIC: 489, Mode.ALPHANUMERIC: 296, Mode.BYTE: 203, Mode.KANJI: 125 },
+ ErrorCorrection.HIGH: { Mode.NUMERIC: 374, Mode.ALPHANUMERIC: 227, Mode.BYTE: 155, Mode.KANJI: 96 },
+ },
+ {
+ ErrorCorrection.LOW: { Mode.NUMERIC: 1022, Mode.ALPHANUMERIC: 619, Mode.BYTE: 425, Mode.KANJI: 262 },
+ ErrorCorrection.MEDIUM: { Mode.NUMERIC: 796, Mode.ALPHANUMERIC: 483, Mode.BYTE: 331, Mode.KANJI: 204 },
+ ErrorCorrection.QUARTILE: { Mode.NUMERIC: 580, Mode.ALPHANUMERIC: 352, Mode.BYTE: 241, Mode.KANJI: 149 },
+ ErrorCorrection.HIGH: { Mode.NUMERIC: 427, Mode.ALPHANUMERIC: 259, Mode.BYTE: 177, Mode.KANJI: 109 },
+ },
+ {
+ ErrorCorrection.LOW: { Mode.NUMERIC: 1101, Mode.ALPHANUMERIC: 667, Mode.BYTE: 458, Mode.KANJI: 282 },
+ ErrorCorrection.MEDIUM: { Mode.NUMERIC: 871, Mode.ALPHANUMERIC: 528, Mode.BYTE: 362, Mode.KANJI: 223 },
+ ErrorCorrection.QUARTILE: { Mode.NUMERIC: 621, Mode.ALPHANUMERIC: 376, Mode.BYTE: 258, Mode.KANJI: 159 },
+ ErrorCorrection.HIGH: { Mode.NUMERIC: 468, Mode.ALPHANUMERIC: 283, Mode.BYTE: 194, Mode.KANJI: 120 },
+ },
+ {
+ ErrorCorrection.LOW: { Mode.NUMERIC: 1250, Mode.ALPHANUMERIC: 758, Mode.BYTE: 520, Mode.KANJI: 320 },
+ ErrorCorrection.MEDIUM: { Mode.NUMERIC: 991, Mode.ALPHANUMERIC: 600, Mode.BYTE: 412, Mode.KANJI: 254 },
+ ErrorCorrection.QUARTILE: { Mode.NUMERIC: 703, Mode.ALPHANUMERIC: 426, Mode.BYTE: 292, Mode.KANJI: 180 },
+ ErrorCorrection.HIGH: { Mode.NUMERIC: 530, Mode.ALPHANUMERIC: 321, Mode.BYTE: 220, Mode.KANJI: 136 },
+ },
+ {
+ ErrorCorrection.LOW: { Mode.NUMERIC: 1408, Mode.ALPHANUMERIC: 854, Mode.BYTE: 586, Mode.KANJI: 361 },
+ ErrorCorrection.MEDIUM: { Mode.NUMERIC: 1082, Mode.ALPHANUMERIC: 656, Mode.BYTE: 450, Mode.KANJI: 277 },
+ ErrorCorrection.QUARTILE: { Mode.NUMERIC: 775, Mode.ALPHANUMERIC: 470, Mode.BYTE: 322, Mode.KANJI: 198 },
+ ErrorCorrection.HIGH: { Mode.NUMERIC: 602, Mode.ALPHANUMERIC: 365, Mode.BYTE: 250, Mode.KANJI: 154 },
+ },
+ {
+ ErrorCorrection.LOW: { Mode.NUMERIC: 1548, Mode.ALPHANUMERIC: 938, Mode.BYTE: 644, Mode.KANJI: 397 },
+ ErrorCorrection.MEDIUM: { Mode.NUMERIC: 1212, Mode.ALPHANUMERIC: 734, Mode.BYTE: 504, Mode.KANJI: 310 },
+ ErrorCorrection.QUARTILE: { Mode.NUMERIC: 876, Mode.ALPHANUMERIC: 531, Mode.BYTE: 364, Mode.KANJI: 224 },
+ ErrorCorrection.HIGH: { Mode.NUMERIC: 674, Mode.ALPHANUMERIC: 408, Mode.BYTE: 280, Mode.KANJI: 173 },
+ },
+ {
+ ErrorCorrection.LOW: { Mode.NUMERIC: 1725, Mode.ALPHANUMERIC: 1046, Mode.BYTE: 718, Mode.KANJI: 442 },
+ ErrorCorrection.MEDIUM: { Mode.NUMERIC: 1346, Mode.ALPHANUMERIC: 816, Mode.BYTE: 560, Mode.KANJI: 345 },
+ ErrorCorrection.QUARTILE: { Mode.NUMERIC: 948, Mode.ALPHANUMERIC: 574, Mode.BYTE: 394, Mode.KANJI: 243 },
+ ErrorCorrection.HIGH: { Mode.NUMERIC: 746, Mode.ALPHANUMERIC: 452, Mode.BYTE: 310, Mode.KANJI: 191 },
+ },
+ {
+ ErrorCorrection.LOW: { Mode.NUMERIC: 1903, Mode.ALPHANUMERIC: 1153, Mode.BYTE: 792, Mode.KANJI: 488 },
+ ErrorCorrection.MEDIUM: { Mode.NUMERIC: 1500, Mode.ALPHANUMERIC: 909, Mode.BYTE: 624, Mode.KANJI: 384 },
+ ErrorCorrection.QUARTILE: { Mode.NUMERIC: 1063, Mode.ALPHANUMERIC: 644, Mode.BYTE: 442, Mode.KANJI: 272 },
+ ErrorCorrection.HIGH: { Mode.NUMERIC: 813, Mode.ALPHANUMERIC: 493, Mode.BYTE: 338, Mode.KANJI: 208 },
+ },
+ {
+ ErrorCorrection.LOW: { Mode.NUMERIC: 2061, Mode.ALPHANUMERIC: 1249, Mode.BYTE: 858, Mode.KANJI: 528 },
+ ErrorCorrection.MEDIUM: { Mode.NUMERIC: 1600, Mode.ALPHANUMERIC: 970, Mode.BYTE: 666, Mode.KANJI: 410 },
+ ErrorCorrection.QUARTILE: { Mode.NUMERIC: 1159, Mode.ALPHANUMERIC: 702, Mode.BYTE: 482, Mode.KANJI: 297 },
+ ErrorCorrection.HIGH: { Mode.NUMERIC: 919, Mode.ALPHANUMERIC: 557, Mode.BYTE: 382, Mode.KANJI: 235 },
+ },
+ {
+ ErrorCorrection.LOW: { Mode.NUMERIC: 2232, Mode.ALPHANUMERIC: 1352, Mode.BYTE: 929, Mode.KANJI: 572 },
+ ErrorCorrection.MEDIUM: { Mode.NUMERIC: 1708, Mode.ALPHANUMERIC: 1035, Mode.BYTE: 711, Mode.KANJI: 438 },
+ ErrorCorrection.QUARTILE: { Mode.NUMERIC: 1224, Mode.ALPHANUMERIC: 742, Mode.BYTE: 509, Mode.KANJI: 314 },
+ ErrorCorrection.HIGH: { Mode.NUMERIC: 969, Mode.ALPHANUMERIC: 587, Mode.BYTE: 403, Mode.KANJI: 248 },
+ },
+ {
+ ErrorCorrection.LOW: { Mode.NUMERIC: 2409, Mode.ALPHANUMERIC: 1460, Mode.BYTE: 1003, Mode.KANJI: 618 },
+ ErrorCorrection.MEDIUM: { Mode.NUMERIC: 1872, Mode.ALPHANUMERIC: 1134, Mode.BYTE: 779, Mode.KANJI: 480 },
+ ErrorCorrection.QUARTILE: { Mode.NUMERIC: 1358, Mode.ALPHANUMERIC: 823, Mode.BYTE: 565, Mode.KANJI: 348 },
+ ErrorCorrection.HIGH: { Mode.NUMERIC: 1056, Mode.ALPHANUMERIC: 640, Mode.BYTE: 439, Mode.KANJI: 270 },
+ },
+ {
+ ErrorCorrection.LOW: { Mode.NUMERIC: 2620, Mode.ALPHANUMERIC: 1588, Mode.BYTE: 1091, Mode.KANJI: 672 },
+ ErrorCorrection.MEDIUM: { Mode.NUMERIC: 2059, Mode.ALPHANUMERIC: 1248, Mode.BYTE: 857, Mode.KANJI: 528 },
+ ErrorCorrection.QUARTILE: { Mode.NUMERIC: 1468, Mode.ALPHANUMERIC: 890, Mode.BYTE: 611, Mode.KANJI: 376 },
+ ErrorCorrection.HIGH: { Mode.NUMERIC: 1108, Mode.ALPHANUMERIC: 672, Mode.BYTE: 461, Mode.KANJI: 284 },
+ },
+ {
+ ErrorCorrection.LOW: { Mode.NUMERIC: 2812, Mode.ALPHANUMERIC: 1704, Mode.BYTE: 1171, Mode.KANJI: 721 },
+ ErrorCorrection.MEDIUM: { Mode.NUMERIC: 2188, Mode.ALPHANUMERIC: 1326, Mode.BYTE: 911, Mode.KANJI: 561 },
+ ErrorCorrection.QUARTILE: { Mode.NUMERIC: 1588, Mode.ALPHANUMERIC: 963, Mode.BYTE: 661, Mode.KANJI: 407 },
+ ErrorCorrection.HIGH: { Mode.NUMERIC: 1228, Mode.ALPHANUMERIC: 744, Mode.BYTE: 511, Mode.KANJI: 315 },
+ },
+ {
+ ErrorCorrection.LOW: { Mode.NUMERIC: 3057, Mode.ALPHANUMERIC: 1853, Mode.BYTE: 1273, Mode.KANJI: 784 },
+ ErrorCorrection.MEDIUM: { Mode.NUMERIC: 2395, Mode.ALPHANUMERIC: 1451, Mode.BYTE: 997, Mode.KANJI: 614 },
+ ErrorCorrection.QUARTILE: { Mode.NUMERIC: 1718, Mode.ALPHANUMERIC: 1041, Mode.BYTE: 715, Mode.KANJI: 440 },
+ ErrorCorrection.HIGH: { Mode.NUMERIC: 1286, Mode.ALPHANUMERIC: 779, Mode.BYTE: 535, Mode.KANJI: 330 },
+ },
+ {
+ ErrorCorrection.LOW: { Mode.NUMERIC: 3283, Mode.ALPHANUMERIC: 1990, Mode.BYTE: 1367, Mode.KANJI: 842 },
+ ErrorCorrection.MEDIUM: { Mode.NUMERIC: 2544, Mode.ALPHANUMERIC: 1542, Mode.BYTE: 1059, Mode.KANJI: 652 },
+ ErrorCorrection.QUARTILE: { Mode.NUMERIC: 1804, Mode.ALPHANUMERIC: 1094, Mode.BYTE: 751, Mode.KANJI: 462 },
+ ErrorCorrection.HIGH: { Mode.NUMERIC: 1425, Mode.ALPHANUMERIC: 864, Mode.BYTE: 593, Mode.KANJI: 365 },
+ },
+ {
+ ErrorCorrection.LOW: { Mode.NUMERIC: 3514, Mode.ALPHANUMERIC: 2132, Mode.BYTE: 1465, Mode.KANJI: 902 },
+ ErrorCorrection.MEDIUM: { Mode.NUMERIC: 2701, Mode.ALPHANUMERIC: 1637, Mode.BYTE: 1125, Mode.KANJI: 692 },
+ ErrorCorrection.QUARTILE: { Mode.NUMERIC: 1933, Mode.ALPHANUMERIC: 1172, Mode.BYTE: 805, Mode.KANJI: 496 },
+ ErrorCorrection.HIGH: { Mode.NUMERIC: 1501, Mode.ALPHANUMERIC: 910, Mode.BYTE: 625, Mode.KANJI: 385 },
+ },
+ {
+ ErrorCorrection.LOW: { Mode.NUMERIC: 3669, Mode.ALPHANUMERIC: 2223, Mode.BYTE: 1528, Mode.KANJI: 940 },
+ ErrorCorrection.MEDIUM: { Mode.NUMERIC: 2857, Mode.ALPHANUMERIC: 1732, Mode.BYTE: 1190, Mode.KANJI: 732 },
+ ErrorCorrection.QUARTILE: { Mode.NUMERIC: 2085, Mode.ALPHANUMERIC: 1263, Mode.BYTE: 868, Mode.KANJI: 534 },
+ ErrorCorrection.HIGH: { Mode.NUMERIC: 1581, Mode.ALPHANUMERIC: 958, Mode.BYTE: 658, Mode.KANJI: 405 },
+ },
+ {
+ ErrorCorrection.LOW: { Mode.NUMERIC: 3909, Mode.ALPHANUMERIC: 2369, Mode.BYTE: 1628, Mode.KANJI: 1002 },
+ ErrorCorrection.MEDIUM: { Mode.NUMERIC: 3035, Mode.ALPHANUMERIC: 1839, Mode.BYTE: 1264, Mode.KANJI: 778 },
+ ErrorCorrection.QUARTILE: { Mode.NUMERIC: 2181, Mode.ALPHANUMERIC: 1322, Mode.BYTE: 908, Mode.KANJI: 559 },
+ ErrorCorrection.HIGH: { Mode.NUMERIC: 1677, Mode.ALPHANUMERIC: 1016, Mode.BYTE: 698, Mode.KANJI: 430 },
+ },
+ {
+ ErrorCorrection.LOW: { Mode.NUMERIC: 4158, Mode.ALPHANUMERIC: 2520, Mode.BYTE: 1732, Mode.KANJI: 1066 },
+ ErrorCorrection.MEDIUM: { Mode.NUMERIC: 3289, Mode.ALPHANUMERIC: 1994, Mode.BYTE: 1370, Mode.KANJI: 843 },
+ ErrorCorrection.QUARTILE: { Mode.NUMERIC: 2358, Mode.ALPHANUMERIC: 1429, Mode.BYTE: 982, Mode.KANJI: 604 },
+ ErrorCorrection.HIGH: { Mode.NUMERIC: 1782, Mode.ALPHANUMERIC: 1080, Mode.BYTE: 742, Mode.KANJI: 457 },
+ },
+ {
+ ErrorCorrection.LOW: { Mode.NUMERIC: 4417, Mode.ALPHANUMERIC: 2677, Mode.BYTE: 1840, Mode.KANJI: 1132 },
+ ErrorCorrection.MEDIUM: { Mode.NUMERIC: 3486, Mode.ALPHANUMERIC: 2113, Mode.BYTE: 1452, Mode.KANJI: 894 },
+ ErrorCorrection.QUARTILE: { Mode.NUMERIC: 2473, Mode.ALPHANUMERIC: 1499, Mode.BYTE: 1030, Mode.KANJI: 634 },
+ ErrorCorrection.HIGH: { Mode.NUMERIC: 1897, Mode.ALPHANUMERIC: 1150, Mode.BYTE: 790, Mode.KANJI: 486 },
+ },
+ {
+ ErrorCorrection.LOW: { Mode.NUMERIC: 4686, Mode.ALPHANUMERIC: 2840, Mode.BYTE: 1952, Mode.KANJI: 1201 },
+ ErrorCorrection.MEDIUM: { Mode.NUMERIC: 3693, Mode.ALPHANUMERIC: 2238, Mode.BYTE: 1538, Mode.KANJI: 947 },
+ ErrorCorrection.QUARTILE: { Mode.NUMERIC: 2670, Mode.ALPHANUMERIC: 1618, Mode.BYTE: 1112, Mode.KANJI: 684 },
+ ErrorCorrection.HIGH: { Mode.NUMERIC: 2022, Mode.ALPHANUMERIC: 1226, Mode.BYTE: 842, Mode.KANJI: 518 },
+ },
+ {
+ ErrorCorrection.LOW: { Mode.NUMERIC: 4965, Mode.ALPHANUMERIC: 3009, Mode.BYTE: 2068, Mode.KANJI: 1273 },
+ ErrorCorrection.MEDIUM: { Mode.NUMERIC: 3909, Mode.ALPHANUMERIC: 2369, Mode.BYTE: 1628, Mode.KANJI: 1002 },
+ ErrorCorrection.QUARTILE: { Mode.NUMERIC: 2805, Mode.ALPHANUMERIC: 1700, Mode.BYTE: 1168, Mode.KANJI: 719 },
+ ErrorCorrection.HIGH: { Mode.NUMERIC: 2157, Mode.ALPHANUMERIC: 1307, Mode.BYTE: 898, Mode.KANJI: 553 },
+ },
+ {
+ ErrorCorrection.LOW: { Mode.NUMERIC: 5253, Mode.ALPHANUMERIC: 3183, Mode.BYTE: 2188, Mode.KANJI: 1347 },
+ ErrorCorrection.MEDIUM: { Mode.NUMERIC: 4134, Mode.ALPHANUMERIC: 2506, Mode.BYTE: 1722, Mode.KANJI: 1060 },
+ ErrorCorrection.QUARTILE: { Mode.NUMERIC: 2949, Mode.ALPHANUMERIC: 1787, Mode.BYTE: 1228, Mode.KANJI: 756 },
+ ErrorCorrection.HIGH: { Mode.NUMERIC: 2301, Mode.ALPHANUMERIC: 1394, Mode.BYTE: 958, Mode.KANJI: 590 },
+ },
+ {
+ ErrorCorrection.LOW: { Mode.NUMERIC: 5529, Mode.ALPHANUMERIC: 3351, Mode.BYTE: 2303, Mode.KANJI: 1417 },
+ ErrorCorrection.MEDIUM: { Mode.NUMERIC: 4343, Mode.ALPHANUMERIC: 2632, Mode.BYTE: 1809, Mode.KANJI: 1113 },
+ ErrorCorrection.QUARTILE: { Mode.NUMERIC: 3081, Mode.ALPHANUMERIC: 1867, Mode.BYTE: 1283, Mode.KANJI: 790 },
+ ErrorCorrection.HIGH: { Mode.NUMERIC: 2361, Mode.ALPHANUMERIC: 1431, Mode.BYTE: 983, Mode.KANJI: 605 },
+ },
+ {
+ ErrorCorrection.LOW: { Mode.NUMERIC: 5836, Mode.ALPHANUMERIC: 3537, Mode.BYTE: 2431, Mode.KANJI: 1496 },
+ ErrorCorrection.MEDIUM: { Mode.NUMERIC: 4588, Mode.ALPHANUMERIC: 2780, Mode.BYTE: 1911, Mode.KANJI: 1176 },
+ ErrorCorrection.QUARTILE: { Mode.NUMERIC: 3244, Mode.ALPHANUMERIC: 1966, Mode.BYTE: 1351, Mode.KANJI: 832 },
+ ErrorCorrection.HIGH: { Mode.NUMERIC: 2524, Mode.ALPHANUMERIC: 1530, Mode.BYTE: 1051, Mode.KANJI: 647 },
+ },
+ {
+ ErrorCorrection.LOW: { Mode.NUMERIC: 6153, Mode.ALPHANUMERIC: 3729, Mode.BYTE: 2563, Mode.KANJI: 1577 },
+ ErrorCorrection.MEDIUM: { Mode.NUMERIC: 4775, Mode.ALPHANUMERIC: 2894, Mode.BYTE: 1989, Mode.KANJI: 1224 },
+ ErrorCorrection.QUARTILE: { Mode.NUMERIC: 3417, Mode.ALPHANUMERIC: 2071, Mode.BYTE: 1423, Mode.KANJI: 876 },
+ ErrorCorrection.HIGH: { Mode.NUMERIC: 2625, Mode.ALPHANUMERIC: 1591, Mode.BYTE: 1093, Mode.KANJI: 673 },
+ },
+ {
+ ErrorCorrection.LOW: { Mode.NUMERIC: 6479, Mode.ALPHANUMERIC: 3927, Mode.BYTE: 2699, Mode.KANJI: 1661 },
+ ErrorCorrection.MEDIUM: { Mode.NUMERIC: 5039, Mode.ALPHANUMERIC: 3054, Mode.BYTE: 2099, Mode.KANJI: 1292 },
+ ErrorCorrection.QUARTILE: { Mode.NUMERIC: 3599, Mode.ALPHANUMERIC: 2181, Mode.BYTE: 1499, Mode.KANJI: 923 },
+ ErrorCorrection.HIGH: { Mode.NUMERIC: 2735, Mode.ALPHANUMERIC: 1658, Mode.BYTE: 1139, Mode.KANJI: 701 },
+ },
+ {
+ ErrorCorrection.LOW: { Mode.NUMERIC: 6743, Mode.ALPHANUMERIC: 4087, Mode.BYTE: 2809, Mode.KANJI: 1729 },
+ ErrorCorrection.MEDIUM: { Mode.NUMERIC: 5313, Mode.ALPHANUMERIC: 3220, Mode.BYTE: 2213, Mode.KANJI: 1362 },
+ ErrorCorrection.QUARTILE: { Mode.NUMERIC: 3791, Mode.ALPHANUMERIC: 2298, Mode.BYTE: 1579, Mode.KANJI: 972 },
+ ErrorCorrection.HIGH: { Mode.NUMERIC: 2927, Mode.ALPHANUMERIC: 1774, Mode.BYTE: 1219, Mode.KANJI: 750 },
+ },
+ {
+ ErrorCorrection.LOW: { Mode.NUMERIC: 7089, Mode.ALPHANUMERIC: 4296, Mode.BYTE: 2953, Mode.KANJI: 1817 },
+ ErrorCorrection.MEDIUM: { Mode.NUMERIC: 5596, Mode.ALPHANUMERIC: 3391, Mode.BYTE: 2331, Mode.KANJI: 1435 },
+ ErrorCorrection.QUARTILE: { Mode.NUMERIC: 3993, Mode.ALPHANUMERIC: 2420, Mode.BYTE: 1663, Mode.KANJI: 1024 },
+ ErrorCorrection.HIGH: { Mode.NUMERIC: 3057, Mode.ALPHANUMERIC: 1852, Mode.BYTE: 1273, Mode.KANJI: 784 }
+ },
+]
+
+const _ALPHANUMERIC_CHARACTERS: Dictionary = {
+ "0" : 0,
+ "1" : 1,
+ "2" : 2,
+ "3" : 3,
+ "4" : 4,
+ "5" : 5,
+ "6" : 6,
+ "7" : 7,
+ "8" : 8,
+ "9" : 9,
+ "A" : 10,
+ "B" : 11,
+ "C" : 12,
+ "D" : 13,
+ "E" : 14,
+ "F" : 15,
+ "G" : 16,
+ "H" : 17,
+ "I" : 18,
+ "J" : 19,
+ "K" : 20,
+ "L" : 21,
+ "M" : 22,
+ "N" : 23,
+ "O" : 24,
+ "P" : 25,
+ "Q" : 26,
+ "R" : 27,
+ "S" : 28,
+ "T" : 29,
+ "U" : 30,
+ "V" : 31,
+ "W" : 32,
+ "X" : 33,
+ "Y" : 34,
+ "Z" : 35,
+ " " : 36,
+ "$" : 37,
+ "%" : 38,
+ "*" : 39,
+ "+" : 40,
+ "-" : 41,
+ "." : 42,
+ "/" : 43,
+ ":" : 44,
+}
+
+## https://www.thonky.com/qr-code-tutorial/error-correction-table
+## [total data codewords, EC codewords per block, number of blocks in group 1, number of data codewords in group 1 blocks, number of blocks in group 2, number of data codewords in group 2 blocks]
+const _ERROR_CORRECTION: Array = [
+ # 1
+ {
+ ErrorCorrection.LOW: [19, 7, 1, 19, 0, 0],
+ ErrorCorrection.MEDIUM: [16, 10, 1, 16, 0, 0],
+ ErrorCorrection.QUARTILE: [13, 13, 1, 13, 0, 0],
+ ErrorCorrection.HIGH: [9, 17, 1, 9, 0, 0],
+ },
+ # 2
+ {
+ ErrorCorrection.LOW: [34, 10, 1, 34, 0, 0],
+ ErrorCorrection.MEDIUM: [28, 16, 1, 28, 0, 0],
+ ErrorCorrection.QUARTILE: [22, 22, 1, 22, 0, 0],
+ ErrorCorrection.HIGH: [16, 28, 1, 16, 0, 0],
+ },
+ # 3
+ {
+ ErrorCorrection.LOW: [55, 15, 1, 55, 0, 0],
+ ErrorCorrection.MEDIUM: [44, 26, 1, 44, 0, 0],
+ ErrorCorrection.QUARTILE: [34, 18, 2, 17, 0, 0],
+ ErrorCorrection.HIGH: [26, 22, 2, 13, 0, 0],
+ },
+ # 4
+ {
+ ErrorCorrection.LOW: [80, 20, 1, 80, 0, 0],
+ ErrorCorrection.MEDIUM: [64, 18, 2, 32, 0, 0],
+ ErrorCorrection.QUARTILE: [48, 26, 2, 24, 0, 0],
+ ErrorCorrection.HIGH: [36, 16, 4, 9, 0, 0],
+ },
+ # 5
+ {
+ ErrorCorrection.LOW: [108, 26, 1, 108, 0, 0],
+ ErrorCorrection.MEDIUM: [86, 24, 2, 43, 0, 0],
+ ErrorCorrection.QUARTILE: [62, 18, 2, 15, 2, 16],
+ ErrorCorrection.HIGH: [46, 22, 2, 11, 2, 12],
+ },
+ # 6
+ {
+ ErrorCorrection.LOW: [136, 18, 2, 68, 0, 0],
+ ErrorCorrection.MEDIUM: [108, 16, 4, 27, 0, 0],
+ ErrorCorrection.QUARTILE: [76, 24, 4, 19, 0, 0],
+ ErrorCorrection.HIGH: [60, 28, 4, 15, 0, 0],
+ },
+ # 7
+ {
+ ErrorCorrection.LOW: [156, 20, 2, 78, 0, 0],
+ ErrorCorrection.MEDIUM: [124, 18, 4, 31, 0, 0],
+ ErrorCorrection.QUARTILE: [88, 18, 2, 14, 4, 15],
+ ErrorCorrection.HIGH: [66, 26, 4, 13, 1, 14],
+ },
+ # 8
+ {
+ ErrorCorrection.LOW: [194, 24, 2, 97, 0, 0],
+ ErrorCorrection.MEDIUM: [154, 22, 2, 38, 2, 39],
+ ErrorCorrection.QUARTILE: [110, 22, 4, 18, 2, 19],
+ ErrorCorrection.HIGH: [86, 26, 4, 14, 2, 15],
+ },
+ # 9
+ {
+ ErrorCorrection.LOW: [232, 30, 2, 116, 0, 0],
+ ErrorCorrection.MEDIUM: [182, 22, 3, 36, 2, 37],
+ ErrorCorrection.QUARTILE: [132, 20, 4, 16, 4, 17],
+ ErrorCorrection.HIGH: [100, 24, 4, 12, 4, 13],
+ },
+ # 10
+ {
+ ErrorCorrection.LOW: [274, 18, 2, 68, 2, 69],
+ ErrorCorrection.MEDIUM: [216, 26, 4, 43, 1, 44],
+ ErrorCorrection.QUARTILE: [154, 24, 6, 19, 2, 20],
+ ErrorCorrection.HIGH: [122, 28, 6, 15, 2, 16],
+ },
+ # 11
+ {
+ ErrorCorrection.LOW: [324, 20, 4, 81, 0, 0],
+ ErrorCorrection.MEDIUM: [254, 30, 1, 50, 4, 51],
+ ErrorCorrection.QUARTILE: [180, 28, 4, 22, 4, 23],
+ ErrorCorrection.HIGH: [140, 24, 3, 12, 8, 13],
+ },
+ # 12
+ {
+ ErrorCorrection.LOW: [370, 24, 2, 92, 2, 93],
+ ErrorCorrection.MEDIUM: [290, 22, 6, 36, 2, 37],
+ ErrorCorrection.QUARTILE: [206, 26, 4, 20, 6, 21],
+ ErrorCorrection.HIGH: [158, 28, 7, 14, 4, 15],
+ },
+ # 13
+ {
+ ErrorCorrection.LOW: [428, 26, 4, 107, 0, 0],
+ ErrorCorrection.MEDIUM: [334, 22, 8, 37, 1, 38],
+ ErrorCorrection.QUARTILE: [244, 24, 8, 20, 4, 21],
+ ErrorCorrection.HIGH: [180, 22, 12, 11, 4, 12],
+ },
+ # 14
+ {
+ ErrorCorrection.LOW: [461, 30, 3, 115, 1, 116],
+ ErrorCorrection.MEDIUM: [365, 24, 4, 40, 5, 41],
+ ErrorCorrection.QUARTILE: [261, 20, 11, 16, 5, 17],
+ ErrorCorrection.HIGH: [197, 24, 11, 12, 5, 13],
+ },
+ # 15
+ {
+ ErrorCorrection.LOW: [523, 22, 5, 87, 1, 88],
+ ErrorCorrection.MEDIUM: [415, 24, 5, 41, 5, 42],
+ ErrorCorrection.QUARTILE: [295, 30, 5, 24, 7, 25],
+ ErrorCorrection.HIGH: [223, 24, 11, 12, 7, 13],
+ },
+ # 16
+ {
+ ErrorCorrection.LOW: [589, 24, 5, 98, 1, 99],
+ ErrorCorrection.MEDIUM: [453, 28, 7, 45, 3, 46],
+ ErrorCorrection.QUARTILE: [325, 24, 15, 19, 2, 20],
+ ErrorCorrection.HIGH: [253, 30, 3, 15, 13, 16],
+ },
+ # 17
+ {
+ ErrorCorrection.LOW: [647, 28, 1, 107, 5, 108],
+ ErrorCorrection.MEDIUM: [507, 28, 10, 46, 1, 47],
+ ErrorCorrection.QUARTILE: [367, 28, 1, 22, 15, 23],
+ ErrorCorrection.HIGH: [283, 28, 2, 14, 17, 15],
+ },
+ # 18
+ {
+ ErrorCorrection.LOW: [721, 30, 5, 120, 1, 121],
+ ErrorCorrection.MEDIUM: [563, 26, 9, 43, 4, 44],
+ ErrorCorrection.QUARTILE: [397, 28, 17, 22, 1, 23],
+ ErrorCorrection.HIGH: [313, 28, 2, 14, 19, 15],
+ },
+ # 19
+ {
+ ErrorCorrection.LOW: [795, 28, 3, 113, 4, 114],
+ ErrorCorrection.MEDIUM: [627, 26, 3, 44, 11, 45],
+ ErrorCorrection.QUARTILE: [445, 26, 17, 21, 4, 22],
+ ErrorCorrection.HIGH: [341, 26, 9, 13, 16, 14],
+ },
+ # 20
+ {
+ ErrorCorrection.LOW: [861, 28, 3, 107, 5, 108],
+ ErrorCorrection.MEDIUM: [669, 26, 3, 41, 13, 42],
+ ErrorCorrection.QUARTILE: [485, 30, 15, 24, 5, 25],
+ ErrorCorrection.HIGH: [385, 28, 15, 15, 10, 16],
+ },
+ # 21
+ {
+ ErrorCorrection.LOW: [932, 28, 4, 116, 4, 117],
+ ErrorCorrection.MEDIUM: [714, 26, 17, 42, 0, 0],
+ ErrorCorrection.QUARTILE: [512, 28, 17, 22, 6, 23],
+ ErrorCorrection.HIGH: [406, 30, 19, 16, 6, 17],
+ },
+ # 22
+ {
+ ErrorCorrection.LOW: [1006, 28, 2, 111, 7, 112],
+ ErrorCorrection.MEDIUM: [782, 28, 17, 46, 0, 0],
+ ErrorCorrection.QUARTILE: [568, 30, 7, 24, 16, 25],
+ ErrorCorrection.HIGH: [442, 24, 34, 13, 0, 0],
+ },
+ # 23
+ {
+ ErrorCorrection.LOW: [1094, 30, 4, 121, 5, 122],
+ ErrorCorrection.MEDIUM: [860, 28, 4, 47, 14, 48],
+ ErrorCorrection.QUARTILE: [614, 30, 11, 24, 14, 25],
+ ErrorCorrection.HIGH: [464, 30, 16, 15, 14, 16],
+ },
+ # 24
+ {
+ ErrorCorrection.LOW: [1174, 30, 6, 117, 4, 118],
+ ErrorCorrection.MEDIUM: [914, 28, 6, 45, 14, 46],
+ ErrorCorrection.QUARTILE: [664, 30, 11, 24, 16, 25],
+ ErrorCorrection.HIGH: [514, 30, 30, 16, 2, 17],
+ },
+ # 25
+ {
+ ErrorCorrection.LOW: [1276, 26, 8, 106, 4, 107],
+ ErrorCorrection.MEDIUM: [1000, 28, 8, 47, 13, 48],
+ ErrorCorrection.QUARTILE: [718, 30, 7, 24, 22, 25],
+ ErrorCorrection.HIGH: [538, 30, 22, 15, 13, 16],
+ },
+ # 26
+ {
+ ErrorCorrection.LOW: [1370, 28, 10, 114, 2, 115],
+ ErrorCorrection.MEDIUM: [1062, 28, 19, 46, 4, 47],
+ ErrorCorrection.QUARTILE: [754, 28, 28, 22, 6, 23],
+ ErrorCorrection.HIGH: [596, 30, 33, 16, 4, 17],
+ },
+ # 27
+ {
+ ErrorCorrection.LOW: [1468, 30, 8, 122, 4, 123],
+ ErrorCorrection.MEDIUM: [1128, 28, 22, 45, 3, 46],
+ ErrorCorrection.QUARTILE: [808, 30, 8, 23, 26, 24],
+ ErrorCorrection.HIGH: [628, 30, 12, 15, 28, 16],
+ },
+ # 28
+ {
+ ErrorCorrection.LOW: [1531, 30, 3, 117, 10, 118],
+ ErrorCorrection.MEDIUM: [1193, 28, 3, 45, 23, 46],
+ ErrorCorrection.QUARTILE: [871, 30, 4, 24, 31, 25],
+ ErrorCorrection.HIGH: [661, 30, 11, 15, 31, 16],
+ },
+ # 29
+ {
+ ErrorCorrection.LOW: [1631, 30, 7, 116, 7, 117],
+ ErrorCorrection.MEDIUM: [1267, 28, 21, 45, 7, 46],
+ ErrorCorrection.QUARTILE: [911, 30, 1, 23, 37, 24],
+ ErrorCorrection.HIGH: [701, 30, 19, 15, 26, 16],
+ },
+ # 30
+ {
+ ErrorCorrection.LOW: [1735, 30, 5, 115, 10, 116],
+ ErrorCorrection.MEDIUM: [1373, 28, 19, 47, 10, 48],
+ ErrorCorrection.QUARTILE: [985, 30, 15, 24, 25, 25],
+ ErrorCorrection.HIGH: [745, 30, 23, 15, 25, 16],
+ },
+ # 31
+ {
+ ErrorCorrection.LOW: [1843, 30, 13, 115, 3, 116],
+ ErrorCorrection.MEDIUM: [1455, 28, 2, 46, 29, 47],
+ ErrorCorrection.QUARTILE: [1033, 30, 42, 24, 1, 25],
+ ErrorCorrection.HIGH: [793, 30, 23, 15, 28, 16],
+ },
+ # 32
+ {
+ ErrorCorrection.LOW: [1955, 30, 17, 115, 0, 0],
+ ErrorCorrection.MEDIUM: [1541, 28, 10, 46, 23, 47],
+ ErrorCorrection.QUARTILE: [1115, 30, 10, 24, 35, 25],
+ ErrorCorrection.HIGH: [845, 30, 19, 15, 35, 16],
+ },
+ # 33
+ {
+ ErrorCorrection.LOW: [2071, 30, 17, 115, 1, 116],
+ ErrorCorrection.MEDIUM: [1631, 28, 14, 46, 21, 47],
+ ErrorCorrection.QUARTILE: [1171, 30, 29, 24, 19, 25],
+ ErrorCorrection.HIGH: [901, 30, 11, 15, 46, 16],
+ },
+ # 34
+ {
+ ErrorCorrection.LOW: [2191, 30, 13, 115, 6, 116],
+ ErrorCorrection.MEDIUM: [1725, 28, 14, 46, 23, 47],
+ ErrorCorrection.QUARTILE: [1231, 30, 44, 24, 7, 25],
+ ErrorCorrection.HIGH: [961, 30, 59, 16, 1, 17],
+ },
+ # 35
+ {
+ ErrorCorrection.LOW: [2306, 30, 12, 121, 7, 122],
+ ErrorCorrection.MEDIUM: [1812, 28, 12, 47, 26, 48],
+ ErrorCorrection.QUARTILE: [1286, 30, 39, 24, 14, 25],
+ ErrorCorrection.HIGH: [986, 30, 22, 15, 41, 16],
+ },
+ # 36
+ {
+ ErrorCorrection.LOW: [2434, 30, 6, 121, 14, 122],
+ ErrorCorrection.MEDIUM: [1914, 28, 6, 47, 34, 48],
+ ErrorCorrection.QUARTILE: [1354, 30, 46, 24, 10, 25],
+ ErrorCorrection.HIGH: [1054, 30, 2, 15, 64, 16],
+ },
+ # 37
+ {
+ ErrorCorrection.LOW: [2566, 30, 17, 122, 4, 123],
+ ErrorCorrection.MEDIUM: [1992, 28, 29, 46, 14, 47],
+ ErrorCorrection.QUARTILE: [1426, 30, 49, 24, 10, 25],
+ ErrorCorrection.HIGH: [1096, 30, 24, 15, 46, 16],
+ },
+ # 38
+ {
+ ErrorCorrection.LOW: [2702, 30, 4, 122, 18, 123],
+ ErrorCorrection.MEDIUM: [2102, 28, 13, 46, 32, 47],
+ ErrorCorrection.QUARTILE: [1502, 30, 48, 24, 14, 25],
+ ErrorCorrection.HIGH: [1142, 30, 42, 15, 32, 16],
+ },
+ # 39
+ {
+ ErrorCorrection.LOW: [2812, 30, 20, 117, 4, 118],
+ ErrorCorrection.MEDIUM: [2216, 28, 40, 47, 7, 48],
+ ErrorCorrection.QUARTILE: [1582, 30, 43, 24, 22, 25],
+ ErrorCorrection.HIGH: [1222, 30, 10, 15, 67, 16],
+ },
+ # 40
+ {
+ ErrorCorrection.LOW: [2956, 30, 19, 118, 6, 119],
+ ErrorCorrection.MEDIUM: [2334, 28, 18, 47, 31, 48],
+ ErrorCorrection.QUARTILE: [1666, 30, 34, 24, 34, 25],
+ ErrorCorrection.HIGH: [1276, 30, 20, 15, 61, 16],
+ },
+]
+
+## sorted by version
+const _ALIGNMENT_PATTERN_POSITIONS: Array = [
+ [],
+ [6, 18],
+ [6, 22],
+ [6, 26],
+ [6, 30],
+ [6, 34],
+ [6, 22, 38],
+ [6, 24, 42],
+ [6, 26, 46],
+ [6, 28, 50],
+ [6, 30, 54],
+ [6, 32, 58],
+ [6, 34, 62],
+ [6, 26, 46, 66],
+ [6, 26, 48, 70],
+ [6, 26, 50, 74],
+ [6, 30, 54, 78],
+ [6, 30, 56, 82],
+ [6, 30, 58, 86],
+ [6, 34, 62, 90],
+ [6, 28, 50, 72, 94],
+ [6, 26, 50, 74, 98],
+ [6, 30, 54, 78, 102],
+ [6, 28, 54, 80, 106],
+ [6, 32, 58, 84, 110],
+ [6, 30, 58, 86, 114],
+ [6, 34, 62, 90, 118],
+ [6, 26, 50, 74, 98, 122],
+ [6, 30, 54, 78, 102, 126],
+ [6, 26, 52, 78, 104, 130],
+ [6, 30, 56, 82, 108, 134],
+ [6, 34, 60, 86, 112, 138],
+ [6, 30, 58, 86, 114, 142],
+ [6, 34, 62, 90, 118, 146],
+ [6, 30, 54, 78, 102, 126, 150],
+ [6, 24, 50, 76, 102, 128, 154],
+ [6, 28, 54, 80, 106, 132, 158],
+ [6, 32, 58, 84, 110, 136, 162],
+ [6, 26, 54, 82, 110, 138, 166],
+ [6, 30, 58, 86, 114, 142, 170],
+]
+
+## remainder bits after structured data bits
+const _REMAINDER_BITS: Array = [ 0, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4,4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0 ]
+
+static var _number_rx: RegEx = RegEx.new()
+static var _alphanumeric_rx: RegEx = RegEx.new()
+
+## cached qr data
+var _cached_qr: PackedByteArray = []
+
+## this can be either a String or PackedByteArray, based on the current encoding mode
+var _input_data: Variant = "":
+ get = get_input_data
+## Encoding Mode
+var mode: Mode = Mode.NUMERIC:
+ set = set_mode
+## Error Correction
+var error_correction: ErrorCorrection = ErrorCorrection.LOW:
+ set = set_error_correction
+## Extended Channel Interpretation (ECI) Value.
+var eci_value: int = ECI.ISO_8859_1:
+ set = set_eci_value
+
+## Use automatically the smallest version
+var auto_version: bool = true:
+ set = set_auto_version
+## Version
+## Will be changed on encoding to the used version if auto_version is true
+var version: int = 1:
+ set = set_version
+var auto_mask_pattern: bool = true:
+ set = set_auto_mask_pattern
+## Will be changed on encoding to the used mask pattern if auto_mask_pattern is true
+var mask_pattern: int = 0:
+ set = set_mask_pattern
+
+func set_auto_version(new_auto_version: bool) -> void:
+ if new_auto_version == auto_version:
+ return
+ auto_version = new_auto_version
+ self._clear_cache()
+
+func set_version(new_version: int) -> void:
+ if new_version == version:
+ return
+ version = clampi(new_version, 1, 40)
+ self._clear_cache()
+
+func set_error_correction(new_error_correction: ErrorCorrection) -> void:
+ if new_error_correction == error_correction:
+ return
+ error_correction = new_error_correction
+ self._clear_cache()
+
+func set_mode(new_mode: Mode) -> void:
+ if new_mode == mode:
+ return
+ mode = new_mode
+
+ match mode:
+ Mode.NUMERIC, Mode.ALPHANUMERIC, Mode.KANJI:
+ self._input_data = ""
+ Mode.BYTE:
+ self._input_data = PackedByteArray()
+ self._clear_cache()
+
+func set_eci_value(new_eci_value: int) -> void:
+ if new_eci_value == eci_value:
+ return
+ eci_value = new_eci_value
+ self._clear_cache()
+
+func set_auto_mask_pattern(new_auto_mask_pattern: bool) -> void:
+ if new_auto_mask_pattern == auto_mask_pattern:
+ return
+ auto_mask_pattern = new_auto_mask_pattern
+ self._clear_cache()
+
+func set_mask_pattern(new_mask_pattern: int) -> void:
+ if new_mask_pattern == mask_pattern:
+ return
+ mask_pattern = clampi(new_mask_pattern, 0, 7)
+ self._clear_cache()
+
+## return the data which was put in
+func get_input_data() -> Variant:
+ return _input_data
+
+
+## get module count of one axis
+func get_module_count() -> int:
+ return _calc_module_count(self.version)
+
+## returns ONE minimum version which fits the data
+## the returned version is just an approach
+## returns -1 if too huge
+func calc_min_version() -> int:
+ var input_size: int = self._get_input_data_size()
+ for idx in range(_DATA_CAPACITY.size()):
+ var cap: int = _DATA_CAPACITY[idx][self.error_correction][self.mode]
+ if self.eci_value != ECI.ISO_8859_1:
+ # subtract roughly eci header size
+ cap -= 4
+ if input_size <= cap:
+ return idx + 1
+ return -1
+
+static func _get_alphanumeric_number(char: String) -> int:
+ return _ALPHANUMERIC_CHARACTERS[char]
+
+# functions are adapted to our starting point 0, 0
+static func _mask_pattern_fns() -> Array[Callable]:
+ return [
+ func (pos: Vector2i) -> bool: return (pos.x + pos.y) % 2 == 0,
+ func (pos: Vector2i) -> bool: return pos.y % 2 == 0,
+ func (pos: Vector2i) -> bool: return pos.x % 3 == 0,
+ func (pos: Vector2i) -> bool: return (pos.x + pos.y) % 3 == 0,
+ func (pos: Vector2i) -> bool: return (pos.x / 3 + pos.y / 2) % 2 == 0,
+ func (pos: Vector2i) -> bool: return (pos.x * pos.y % 2) + (pos.x * pos.y) % 3 == 0,
+ func (pos: Vector2i) -> bool: return ((pos.x * pos.y % 2) + (pos.x * pos.y) % 3) % 2 == 0,
+ func (pos: Vector2i) -> bool: return (((pos.x + pos.y) % 2) + (pos.x * pos.y) % 3) % 2 == 0,
+ ]
+
+# helper function check if a bit is set
+static func _get_state(value: int, idx: int) -> bool:
+ return (value & (1 << idx))
+
+func _get_data_codeword_count() -> int:
+ return _ERROR_CORRECTION[self.version - 1][self.error_correction][0]
+
+func _get_ec_codeword_count() -> int:
+ return _ERROR_CORRECTION[self.version - 1][self.error_correction][1]
+
+func _get_ec_block_count(group: int) -> int:
+ return _ERROR_CORRECTION[self.version - 1][self.error_correction][2 + (group - 1) * 2]
+
+func _get_ec_block_codeword_count(group: int) -> int:
+ return _ERROR_CORRECTION[self.version - 1][self.error_correction][3 + (group - 1) * 2]
+
+static func _calc_module_count(version: int) -> int:
+ return 21 + 4 * (version - 1)
+
+func _get_allignment_pattern_positions() -> Array[Vector2i]:
+ var module_count: int = self.get_module_count()
+ var positions: Array[Vector2i] = []
+ for row in _ALIGNMENT_PATTERN_POSITIONS[self.version - 1]:
+ for col in _ALIGNMENT_PATTERN_POSITIONS[self.version - 1]:
+ # do not overlap finder positions
+ if row - 2 < 8 && col - 2 < 8 || \
+ row > module_count - 8 && col - 2 < 8 || \
+ row - 2 < 8 && col > module_count - 8:
+ continue
+ positions.append(Vector2i(row, col))
+ return positions
+
+static func _get_remainder_bits(version: int) -> int:
+ return _REMAINDER_BITS[version - 1]
+
+func _get_input_data_size() -> int:
+ match typeof(self._input_data):
+ TYPE_STRING:
+ return self._input_data.length()
+ TYPE_PACKED_BYTE_ARRAY:
+ return self._input_data.size()
+ return 0
+
+func _get_char_count_size() -> int:
+ if self.version < 10:
+ match self.mode:
+ Mode.NUMERIC:
+ return 10
+ Mode.ALPHANUMERIC:
+ return 9
+ Mode.BYTE:
+ return 8
+ Mode.KANJI:
+ return 8
+ elif self.version < 27:
+ match self.mode:
+ Mode.NUMERIC:
+ return 12
+ Mode.ALPHANUMERIC:
+ return 11
+ Mode.BYTE:
+ return 16
+ Mode.KANJI:
+ return 10
+ else:
+ match self.mode:
+ Mode.NUMERIC:
+ return 14
+ Mode.ALPHANUMERIC:
+ return 13
+ Mode.BYTE:
+ return 16
+ Mode.KANJI:
+ return 12
+ return 0
+
+static func _static_init() -> void:
+ # TODO: static init is not called in editor if not @tool
+ if _number_rx == null:
+ _number_rx = RegEx.new()
+ # TODO: static init is not called in editor if not @tool
+ if _alphanumeric_rx == null:
+ _alphanumeric_rx = RegEx.new()
+
+ _number_rx.compile("[^\\d]*")
+ _alphanumeric_rx.compile("[^0-9A-Z $%*+\\-.\\/:]*")
+
+func _init(error_correction_: ErrorCorrection = ErrorCorrection.LOW) -> void:
+ self.error_correction = error_correction_
+
+ # TODO: static init is not called in editor if not @tool
+ if Engine.is_editor_hint():
+ _static_init()
+
+## generate an QR code image
+func generate_image(module_px_size: int = 1, light_module_color: Color = Color.WHITE, dark_module_color: Color = Color.BLACK) -> Image:
+ module_px_size = max(1, module_px_size)
+
+ var qr_code: PackedByteArray = self.encode()
+
+ var module_count: int = self.get_module_count()
+ var image: Image = Image.create(module_count * module_px_size, module_count * module_px_size, false, Image.FORMAT_RGB8)
+
+ for y in range(module_count):
+ for x in range(module_count):
+ var color: Color = Color.WHITE
+ match qr_code[x + y * module_count]:
+ 0:
+ color = light_module_color
+ 1:
+ color = dark_module_color
+ _:
+ color = Color.PINK
+ for offset_x in range(module_px_size):
+ for offset_y in range(module_px_size):
+ image.set_pixel(x * module_px_size + offset_x, y * module_px_size + offset_y, color)
+
+ return image
+
+func put_numeric(number: String) -> void:
+ if self.mode != Mode.NUMERIC || number != self._input_data:
+ self._clear_cache()
+ self.mode = Mode.NUMERIC
+ self._input_data = _number_rx.sub(number, "", true)
+
+func put_alphanumeric(text: String) -> void:
+ if self.mode != Mode.ALPHANUMERIC || text != self._input_data:
+ self._clear_cache()
+ self.mode = Mode.ALPHANUMERIC
+ self._input_data = _alphanumeric_rx.sub(text, "", true)
+
+func put_byte(data: PackedByteArray) -> void:
+ if self.mode != Mode.BYTE || data != self._input_data:
+ self._clear_cache()
+ self.mode = Mode.BYTE
+ self._input_data = data
+
+func put_kanji(data: String) -> void:
+ if self.mode != Mode.KANJI || data != self._input_data:
+ self._clear_cache()
+ self.mode = Mode.KANJI
+ self._input_data = ShiftJIS.get_string_from_jis_2004(ShiftJIS.to_shift_jis_2004_buffer(data))
+
+## returns row by row
+## to get row size use get_module_count
+func encode() -> PackedByteArray:
+ if !self._cached_qr.is_empty():
+ return self._cached_qr.duplicate()
+
+ if self.auto_version:
+ self.version = self.calc_min_version()
+
+ var data_stream: BitStream = self._encode_data()
+ var err_correction: Array = self._error_correction(data_stream)
+ var structured_data: BitStream = self._structure_data(data_stream, err_correction)
+ var qr_data: PackedByteArray = self._place_modules(structured_data)
+ qr_data = self._mask_qr(qr_data)
+
+ self._cached_qr = qr_data.duplicate()
+
+ return qr_data
+
+func _encode_data() -> BitStream:
+ var stream: BitStream = BitStream.new()
+
+ # add ECI header
+ if self.eci_value != int(ECI.ISO_8859_1):
+ stream.append(0b0111, 4)
+ if self.eci_value <= 127:
+ stream.append(0, 1)
+ stream.append(self.eci_value, 7)
+ elif self.eci_value <= 16383:
+ stream.append(0b10, 2)
+ stream.append(self.eci_value, 14)
+ else:
+ stream.append(0b110, 3)
+ stream.append(self.eci_value, 21)
+
+ # add mode
+ stream.append(int(self.mode), 4)
+
+ # add character count indicator
+ stream.append(self._get_input_data_size(), self._get_char_count_size())
+
+ # add encoded data
+ match self.mode:
+ Mode.NUMERIC:
+ self._encode_numeric(stream)
+ Mode.ALPHANUMERIC:
+ self._encode_alphanumeric(stream)
+ Mode.BYTE:
+ self._encode_byte(stream)
+ Mode.KANJI:
+ self._encode_kanji(stream)
+
+ # add terminator
+ var required_bytes: int = self._get_data_codeword_count()
+ var terminator_size: int = min(8 * required_bytes - stream.size(), 4)
+ stream.append(0, terminator_size)
+
+ # add bits to multiple of 8
+ stream.append(0, (8 - stream.size() % 8) % 8)
+
+ # pad bytes to capacity
+ var missing_bytes = required_bytes - stream.size() / 8
+ for idx in range(missing_bytes):
+ if idx % 2 == 0:
+ stream.append(236, 8)
+ else:
+ stream.append(17, 8)
+
+ return stream
+
+func _clear_cache() -> void:
+ self._cached_qr.clear()
+
+func _encode_numeric(stream: BitStream) -> void:
+ assert(typeof(self._input_data) == TYPE_STRING)
+ const GROUP_SIZE: int = 3
+
+ for idx in range(ceili(self._input_data.length() / float(GROUP_SIZE))):
+ var chars: String = self._input_data.substr(idx * GROUP_SIZE, GROUP_SIZE)
+ var number: int = chars.to_int()
+ var bit_count: int = 0
+ match chars.length():
+ 3:
+ bit_count = 10
+ 2:
+ bit_count = 7
+ 1:
+ bit_count = 4
+ stream.append(number, bit_count)
+
+func _encode_alphanumeric(stream: BitStream) -> void:
+ assert(typeof(self._input_data) == TYPE_STRING)
+ const GROUP_SIZE: int = 2
+
+ for idx in range(ceili(self._input_data.length() / float(GROUP_SIZE))):
+ var chars: String = self._input_data.substr(idx * GROUP_SIZE, GROUP_SIZE)
+ var number: int = _get_alphanumeric_number(chars[0])
+ if chars.length() == 2:
+ number = 45 * number + _get_alphanumeric_number(chars[1])
+ stream.append(number, 11)
+ else:
+ stream.append(number, 6)
+
+func _encode_byte(stream: BitStream) -> void:
+ assert(typeof(self._input_data) == TYPE_PACKED_BYTE_ARRAY)
+
+ for val in self._input_data:
+ stream.append(val, 8)
+
+func _encode_kanji(stream: BitStream) -> void:
+ assert(typeof(self._input_data) == TYPE_STRING)
+
+ var jis_bytes: PackedByteArray = ShiftJIS.to_shift_jis_2004_buffer(self._input_data)
+ for idx in range(jis_bytes.size() / 2):
+ var value = jis_bytes.decode_u16(idx * 2)
+ if value >= 0x8140 && value <= 0x9FFC:
+ value = value - 0x8140
+ elif value >= 0xE040 && value <= 0xEBBF:
+ value = value - 0xC140
+ value = ((value & 0xFF00) >> 8) * 0xC0 + (value & 0x00FF)
+ stream.append(value, 13)
+
+# returns an array of PackedByteArray's, structured as Group, Block [G1B1, G1B2, G1B3, G2B1, G2B2, ...]
+func _error_correction(stream: BitStream) -> Array[PackedByteArray]:
+ var data: PackedByteArray = stream.to_byte_array()
+
+ var ec_words: int = self._get_ec_codeword_count()
+ var group_blocks: PackedByteArray = [
+ self._get_ec_block_count(1),
+ self._get_ec_block_count(2),
+ ]
+ var group_codewords: PackedByteArray = [
+ self._get_ec_block_codeword_count(1),
+ self._get_ec_block_codeword_count(2),
+ ]
+ var groups: int = 1
+ if group_blocks[1] > 0:
+ groups += 1
+
+ var err_corr: Array[PackedByteArray] = []
+ for group_idx in range(groups):
+ var block_size: int = group_codewords[group_idx]
+ for block_idx in range(group_blocks[group_idx]):
+ var start_idx: int = 0
+ # add offset to current group
+ for group_off in range(group_idx):
+ start_idx += group_blocks[group_off] * group_codewords[group_off]
+ start_idx = start_idx + block_idx * block_size
+ var cur_data: PackedByteArray = data.slice(start_idx, start_idx + block_size)
+ err_corr.append(ReedSolomon.encode(cur_data, ec_words))
+
+ return err_corr
+
+func _structure_data(data_stream: BitStream, err_correction: Array[PackedByteArray]) -> BitStream:
+ if err_correction.size() == 1:
+ var res: BitStream = data_stream.duplicate()
+ res.append_byte_array(err_correction[0])
+ # append remainder bits
+ res.append(0, _get_remainder_bits(self.version))
+ return res
+
+ var res: BitStream = BitStream.new()
+ var data_arr: PackedByteArray = data_stream.to_byte_array()
+ var group_blocks: PackedByteArray = [
+ self._get_ec_block_count(1),
+ self._get_ec_block_count(2),
+ ]
+ var group_codewords: Array[int] = [
+ self._get_ec_block_codeword_count(1),
+ self._get_ec_block_codeword_count(2),
+ ]
+ var groups: int = 1
+ if group_blocks[1] > 0:
+ groups += 1
+
+ # interleave data code words
+ var max_code_words: int = group_codewords.max()
+ for codeword_idx in range(max_code_words):
+ for group_idx in range(groups):
+ # if current group/block has not this much codewords skip
+ if codeword_idx >= group_codewords[group_idx]:
+ continue
+ var group_offset: int = 0
+ for group_off in range(group_idx):
+ group_offset += group_blocks[group_off] * group_codewords[group_off]
+ for block_idx in range(group_blocks[group_idx]):
+ var idx: int = group_offset + codeword_idx + block_idx * group_codewords[group_idx]
+ res.append(data_arr[idx], 8)
+
+ # interleave error code words
+ for word_idx in range(self._get_ec_codeword_count()):
+ for block in range(err_correction.size()):
+ res.append(err_correction[block][word_idx], 8)
+
+ # append remainder bits
+ res.append(0, _get_remainder_bits(self.version))
+
+ return res
+
+# pos is upper left black corner
+# 7 x 7 size
+static func _place_finder(data: PackedByteArray, module_count: int, pos: Vector2i) -> void:
+ for row in range(7):
+ for col in range(7):
+ data[(pos.x + row) + (pos.y + col) * module_count] = 1
+ for idx in range(5):
+ data[(pos.x + 1 + idx) + (pos.y + 1) * module_count] = 0
+ data[(pos.x + 1 + idx) + (pos.y + 5) * module_count] = 0
+ for idx in range(3):
+ data[(pos.x + 1) + (pos.y + 2 + idx) * module_count] = 0
+ data[(pos.x + 5) + (pos.y + 2 + idx) * module_count] = 0
+
+# pos is center
+# 5 x 5 size
+static func _place_align_pattern(data: PackedByteArray, module_count: int, pos: Vector2i) -> void:
+ for row in range(5):
+ for col in range(5):
+ data[(pos.x - 2 + row) + (pos.y - 2 + col) * module_count] = 1
+ for idx in range(3):
+ data[(pos.x - 1 + idx) + (pos.y - 1) * module_count] = 0
+ data[(pos.x - 1 + idx) + (pos.y + 1) * module_count] = 0
+ data[(pos.x - 1) + (pos.y) * module_count] = 0
+ data[(pos.x + 1) + (pos.y) * module_count] = 0
+
+static func _place_separators(data: PackedByteArray, module_count: int) -> void:
+ for idx in range(8):
+ # upper left
+ data[idx + 7 * module_count] = 0
+ data[7 + idx * module_count] = 0
+ # lower left
+ data[idx + (module_count - 8) * module_count] = 0
+ data[(module_count - 8) + idx * module_count] = 0
+ # upper right
+ data[(module_count - idx - 1) + 7 * module_count] = 0
+ data[7 + (module_count - idx - 1) * module_count] = 0
+
+static func _place_timing_patterns(data: PackedByteArray, module_count: int) -> void:
+ for idx in range(module_count - 6 * 2):
+ data[6 + idx + 6 * module_count] = (idx + 1) % 2
+ data[6 + (6 + idx) * module_count] = (idx + 1) % 2
+
+static func _is_data_module(module_count: int, alignment_pattern_pos: Array[Vector2i], pos: Vector2i) -> bool:
+ # finder with separation and format information area: upper left finder, upper right finder, lower left finder
+ # dark module is also included
+ if (pos.x <= 8 && pos.y <= 8) || (pos.x >= (module_count - 8) && pos.y <= 8) || (pos.x <= 8 && pos.y >= (module_count - 8)):
+ return false
+ # timing pattern
+ if pos.x == 6 || pos.y == 6:
+ return false
+ # version information area
+ # for version >= 7, upper and lower
+ # this check, will also success if it is in a finder area
+ if module_count >= 45 && ((pos.x >= module_count - 11 && pos.y <= 5) || (pos.x <= 5 && pos.y >= module_count - 11)):
+ return false
+
+ # check if in alignment pattern
+ for align_pos in alignment_pattern_pos:
+ if pos.x >= align_pos.x - 2 && pos.x <= align_pos.x + 2 && pos.y >= align_pos.y - 2 && pos.y <= align_pos.y + 2:
+ return false
+
+ return true
+
+static func _place_data(data: PackedByteArray, module_count: int, alignment_pattern_pos: Array[Vector2i], structured_data: BitStream) -> void:
+ var data_idx: int = 0
+ # base column where to go up or down
+ var base_col: int = module_count - 1
+ var upwards: bool = true
+
+ while base_col > 0:
+ # skip vertical timing pattern
+ if base_col == 6:
+ base_col -= 1
+
+ for row in range(module_count):
+ if upwards:
+ row = module_count - 1 - row
+ for offset in range(2):
+ var pos: Vector2i = Vector2i(base_col - offset, row)
+ if _is_data_module(module_count, alignment_pattern_pos, pos):
+ data[pos.x + pos.y * module_count] = int(structured_data.get_bit(data_idx))
+ data_idx += 1
+
+ base_col -= 2
+ upwards = !upwards
+
+ # all data modules placed
+ assert(data_idx == structured_data.size(), "failed to place all data (%d of %d)" % [data_idx, structured_data.size()])
+
+static func _calc_mask_rating(data: PackedByteArray, module_count: int) -> int:
+ var rating: int = 0
+
+ # condition 1
+ # horizontal
+ for y in range(module_count):
+ var count: int = 0
+ var block_value: int = 0
+ for x in range(module_count):
+ var cur_value: int = data[x + y * module_count]
+ if cur_value == block_value:
+ count += 1
+ else:
+ if count >= 5:
+ rating += count - 2
+ count = 1
+ block_value = cur_value
+ if count >= 5:
+ rating += count - 2
+ # vertical
+ for x in range(module_count):
+ var count: int = 0
+ var block_value: int = 0
+ for y in range(module_count):
+ var cur_value: int = data[x + y * module_count]
+ if cur_value == block_value:
+ count += 1
+ else:
+ if count >= 5:
+ rating += count - 2
+ count = 1
+ block_value = cur_value
+ if count >= 5:
+ rating += count - 2
+
+ # condition 2
+ for x in range(module_count - 1):
+ for y in range(module_count - 1):
+ var val: int = data[x + y * module_count] + data[x + 1 + y * module_count] + data[x + (y + 1) * module_count] + data[x + 1 + (y + 1) * module_count]
+ if val == 0 or val == 4:
+ rating += 3
+
+ # condition 3
+ for y in range(module_count):
+ for x in range(module_count - 6):
+ var start_idx: int = x + y * module_count
+ if (!data[start_idx]
+ && data[start_idx + 1]
+ && !data[start_idx + 2]
+ && !data[start_idx + 3]
+ && !data[start_idx + 4]
+ && data[start_idx + 5]
+ && !data[start_idx + 6]):
+ if x >= 4 && data[start_idx - 1] && data[start_idx - 2] && data[start_idx - 3] && data[start_idx - 4]:
+ rating += 40
+ if x <= (module_count - 10) && data[start_idx + 7] && data[start_idx + 8] && data[start_idx + 9] && data[start_idx + 10]:
+ rating += 40
+
+ for x in range(module_count):
+ for y in range(module_count - 6):
+ if (!data[x + y * module_count]
+ && data[x + (y + 1) * module_count]
+ && !data[x + (y + 2) * module_count]
+ && !data[x + (y + 3) * module_count]
+ && !data[x + (y + 4) * module_count]
+ && data[x + (y + 5) * module_count]
+ && !data[x + (y + 6) * module_count]):
+ if y >= 4 && data[x + (y - 1) * module_count] && data[x + (y - 2) * module_count] && data[x + (y - 3) * module_count] && data[x + (y - 4) * module_count]:
+ rating += 40
+ if y <= (module_count - 11) && data[x + (y + 7) * module_count] && data[x + (y + 8) * module_count] && data[x + (y + 9) * module_count] && data[x + (y + 10) * module_count]:
+ rating += 40
+
+ # condition 4
+ var dark_mods: int = data.count(0)
+ var ratio: float = dark_mods / float(module_count * module_count)
+ var percent: int = int((ratio * 100) - 50)
+ rating += absi(percent) / 5 * 10
+ return rating
+
+static func _place_format(qr_data: PackedByteArray, module_count: int, error_corr: ErrorCorrection, mask_pattern_val: int) -> void:
+ var base_code: int = (int(error_corr) << 3) | mask_pattern_val
+
+ var code: int = base_code
+ for _idx in range(10):
+ code = (code << 1) ^ ((code >> 9) * 0x537)
+ code = (base_code << 10 | code) ^ 0x5412
+
+ # upper left finder
+ for idx in range(8):
+ # skip timing pattern
+ var pos: int = idx
+ if idx > 5:
+ pos += 1
+ # horizontal
+ qr_data[pos + 8 * module_count] = int(_get_state(code, 14 - idx))
+ # vertical
+ qr_data[8 + pos * module_count] = int(_get_state(code, idx))
+ # lower left finder
+ for idx in range(7):
+ qr_data[8 + (module_count - 1 - idx) * module_count] = int(_get_state(code, 14 - idx))
+ # upper right finder
+ for idx in range(8):
+ qr_data[(module_count - 1 - idx) + 8 * module_count] = int(_get_state(code, idx))
+
+static func _place_version(qr_data: PackedByteArray, version: int) -> void:
+ if version < 7:
+ return
+
+ var code: int = version
+ for _idx in range(12):
+ code = (code << 1) ^ ((code >> 11) * 0x1F25)
+ code = version << 12 | code
+
+ var module_count: int = _calc_module_count(version)
+ for idx in range(18):
+ var x: int = idx / 3
+ var y: int = module_count - 11 + idx % 3
+ qr_data[x + y * module_count] = int(_get_state(code, idx))
+ qr_data[y + x * module_count] = int(_get_state(code, idx))
+
+# returns qr module data, ordered by rows
+# (col/x, row/y) | index
+# (0, 0) (1, 0) (2, 0) | 0, 1, 2
+# (0, 1) (1, 1) (2, 1) | 3, 4, 5
+# (0, 2) (1, 2) (2, 2) | 6, 7, 8
+func _place_modules(structured_data: BitStream) -> PackedByteArray:
+ var qr_data: PackedByteArray = PackedByteArray()
+ var module_count: int = self.get_module_count()
+ qr_data.resize(module_count * module_count)
+
+ # place upper left finder
+ _place_finder(qr_data, module_count, Vector2i(0, 0))
+ # place lower left finder
+ _place_finder(qr_data, module_count, Vector2i(0, module_count - 7))
+ # place upper right finder
+ _place_finder(qr_data, module_count, Vector2i(module_count - 7, 0))
+ _place_separators(qr_data, module_count)
+
+ var alignment_pattern_pos: Array[Vector2i] = self._get_allignment_pattern_positions()
+ for pos in alignment_pattern_pos:
+ _place_align_pattern(qr_data, module_count, pos)
+
+ _place_timing_patterns(qr_data, module_count)
+
+ # dark module
+ qr_data[8 + (module_count - 8) * module_count] = 1
+
+ # place data
+ _place_data(qr_data, module_count, alignment_pattern_pos, structured_data)
+
+ return qr_data
+
+static func _mask(qr_data: PackedByteArray, module_count: int, alignment_pattern_pos: Array[Vector2i], mask_pattern: int) -> void:
+ var mask_fn: Callable = _mask_pattern_fns()[mask_pattern]
+
+ for x in range(module_count):
+ for y in range(module_count):
+ var pos: Vector2i = Vector2i(x, y)
+ if _is_data_module(module_count, alignment_pattern_pos, pos):
+ var idx: int = x + y * module_count
+ qr_data[idx] = int(mask_fn.call(pos)) ^ qr_data[idx]
+
+# return mask pattern number
+func _get_best_qr_mask(masked_qrs: Array[PackedByteArray], module_count: int) -> int:
+ var min_idx: int = 0
+ # integer max
+ var cur_min_value: int = 9223372036854775807
+ for idx in range(masked_qrs.size()):
+ var rating: int = _calc_mask_rating(masked_qrs[idx], module_count)
+ if rating < cur_min_value:
+ min_idx = idx
+ cur_min_value = rating
+
+ return min_idx
+
+func _mask_qr(qr_data: PackedByteArray) -> PackedByteArray:
+ var module_count: int = self.get_module_count()
+ var alignment_pattern_pos: Array[Vector2i] = self._get_allignment_pattern_positions()
+
+ # apply mask pattern
+ if !self.auto_mask_pattern:
+ _mask(qr_data, module_count, alignment_pattern_pos, self.mask_pattern)
+ _place_format(qr_data, module_count, self.error_correction, self.mask_pattern)
+ _place_version(qr_data, self.version)
+
+ return qr_data
+
+ # get best mask pattern
+ var masked_qr: Array[PackedByteArray] = []
+ var mask_fns: Array[Callable] = _mask_pattern_fns()
+
+ for pattern_idx in range(mask_fns.size()):
+ var cur_qr: PackedByteArray = qr_data.duplicate()
+ _mask(cur_qr, module_count, alignment_pattern_pos, pattern_idx)
+ # normally the format version is applied AFTER getting the best pattern, but will produce worse qr codes
+ _place_format(cur_qr, module_count, self.error_correction, pattern_idx)
+ _place_version(cur_qr, self.version)
+ masked_qr.append(cur_qr)
+ var best_mask: int = _get_best_qr_mask(masked_qr, module_count)
+ self.mask_pattern = best_mask
+ qr_data = masked_qr[best_mask]
+
+ return qr_data
+
+#### DEVEL TOOLS
+
+static func _print_qr(data: PackedByteArray, module_count: int) -> void:
+ for y in range(module_count):
+ var row: String = ""
+ for x in range(module_count):
+ var value: int = data[y * module_count + x]
+ match value:
+ 0:
+ row += "⬜"
+ 1:
+ row += "⬛"
+ 2:
+ row += "🟨"
+ 3:
+ row += "🟦"
+ _:
+ row += "🟥"
+ print(row)
+
+static func _bin_to_string(value: int, bits: int = 8) -> String:
+ var val: String = ""
+ for idx in range(bits):
+ if idx % 4 == 0:
+ val = " " + val
+ val = str(int(bool(value & (1 << idx)))) + val
+ return val.strip_edges()
+
+static func _arr_to_string(arr: PackedByteArray) -> String:
+ var val: String = ""
+ for byte in arr:
+ val += "[" + _bin_to_string(byte, 8) + "] "
+ return val.strip_edges()
diff --git a/addons/qr_code/qr_code.svg b/addons/qr_code/qr_code.svg
new file mode 100644
index 0000000..35238b2
--- /dev/null
+++ b/addons/qr_code/qr_code.svg
@@ -0,0 +1,63 @@
+
+
diff --git a/addons/qr_code/qr_code.svg.import b/addons/qr_code/qr_code.svg.import
new file mode 100644
index 0000000..06f477f
--- /dev/null
+++ b/addons/qr_code/qr_code.svg.import
@@ -0,0 +1,37 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cn383mw8drmm5"
+path="res://.godot/imported/qr_code.svg-8435c81cb02327831b4999115d02816f.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://addons/qr_code/qr_code.svg"
+dest_files=["res://.godot/imported/qr_code.svg-8435c81cb02327831b4999115d02816f.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
+svg/scale=1.0
+editor/scale_with_editor_scale=false
+editor/convert_colors_with_editor_theme=false
diff --git a/addons/qr_code/qr_code_rect.gd b/addons/qr_code/qr_code_rect.gd
new file mode 100644
index 0000000..b68657f
--- /dev/null
+++ b/addons/qr_code/qr_code_rect.gd
@@ -0,0 +1,294 @@
+@tool
+@icon("qr_code.svg")
+extends TextureRect
+class_name QRCodeRect
+
+const QRCode := preload("qr_code.gd")
+const ShiftJIS := preload("shift_jis.gd")
+
+var _qr: QRCode = QRCode.new()
+
+@export var mode: QRCode.Mode:
+ set = set_mode,
+ get = get_mode
+@export var error_correction: QRCode.ErrorCorrection:
+ set = set_error_correction,
+ get = get_error_correction
+## Extended Channel Interpretation (ECI) Value.
+@export var eci_value: QRCode.ECI:
+ set = set_eci_value,
+ get = get_eci_value
+var data: Variant = "":
+ set = set_data,
+ get = get_data
+## Use automatically the smallest version possible.
+var auto_version: bool = true:
+ set = set_auto_version,
+ get = get_auto_version
+var version: int = 1:
+ set = set_version,
+ get = get_version
+## Use automatically the best mask pattern.
+var auto_mask_pattern: bool = true:
+ set = set_auto_mask_pattern,
+ get = get_auto_mask_pattern
+## Used mask pattern.
+var mask_pattern = 0:
+ set = set_mask_pattern,
+ get = get_mask_pattern
+var light_module_color: Color = Color.WHITE:
+ set = set_light_module_color
+var dark_module_color: Color = Color.BLACK:
+ set = set_dark_module_color
+## Automatically set the module pixel size based on the size.
+## Do not use expand mode KEEP_SIZE when using it.
+## Turn this off when the QR Code changes or is resized often, as it impacts the performance quite heavily.
+var auto_module_px_size: bool = true:
+ set = set_auto_module_px_size
+## Use that many pixel for one module.
+var module_px_size: int = 1:
+ set = set_module_px_size
+
+func set_mode(new_mode: QRCode.Mode) -> void:
+ self._qr.mode = new_mode
+ self.notify_property_list_changed()
+ self._update_qr()
+
+func get_mode() -> QRCode.Mode:
+ return self._qr.mode
+
+func set_error_correction(new_error_correction: QRCode.ErrorCorrection) -> void:
+ self._qr.error_correction = new_error_correction
+ self._update_qr()
+
+func get_error_correction() -> QRCode.ErrorCorrection:
+ return self._qr.error_correction
+
+func set_eci_value(new_eci_value: int) -> void:
+ self._qr.eci_value = new_eci_value
+ self.notify_property_list_changed()
+ self._update_qr()
+
+func get_eci_value() -> int:
+ return self._qr.eci_value
+
+func set_data(new_data: Variant) -> void:
+ match self._qr.mode:
+ QRCode.Mode.NUMERIC:
+ self._qr.put_numeric(new_data)
+ QRCode.Mode.ALPHANUMERIC:
+ self._qr.put_alphanumeric(new_data)
+ QRCode.Mode.BYTE:
+ match self.eci_value:
+ QRCode.ECI.ISO_8859_1:
+ self._qr.put_byte(new_data.to_ascii_buffer())
+ QRCode.ECI.SHIFT_JIS:
+ self._qr.put_byte(ShiftJIS.to_shift_jis_2004_buffer(new_data))
+ QRCode.ECI.UTF_8:
+ self._qr.put_byte(new_data.to_utf8_buffer())
+ QRCode.ECI.UTF_16:
+ self._qr.put_byte(new_data.to_utf16_buffer())
+ QRCode.ECI.US_ASCII:
+ self._qr.put_byte(new_data.to_ascii_buffer())
+ _:
+ self._qr.put_byte(new_data)
+ QRCode.Mode.KANJI:
+ self._qr.put_kanji(new_data)
+
+ self._update_qr()
+
+func get_data() -> Variant:
+ var input_data: Variant = self._qr.get_input_data()
+ if self.mode == QRCode.Mode.BYTE:
+ match self.eci_value:
+ QRCode.ECI.ISO_8859_1:
+ return input_data.get_string_from_ascii()
+ QRCode.ECI.SHIFT_JIS:
+ return ShiftJIS.get_string_from_jis_2004(input_data)
+ QRCode.ECI.UTF_8:
+ return input_data.get_string_from_utf8()
+ QRCode.ECI.UTF_16:
+ return input_data.get_string_from_utf16()
+ QRCode.ECI.US_ASCII:
+ return input_data.get_string_from_ascii()
+
+ return self._qr.get_input_data()
+
+func set_auto_version(new_auto_version: bool) -> void:
+ self._qr.auto_version = new_auto_version
+ self.notify_property_list_changed()
+ self._update_qr()
+
+func get_auto_version() -> bool:
+ return self._qr.auto_version
+
+func set_version(new_version: int) -> void:
+ self._qr.version = new_version
+ self._update_qr()
+
+func get_version() -> int:
+ return self._qr.version
+
+func set_auto_mask_pattern(new_auto_mask_pattern: bool) -> void:
+ self._qr.auto_mask_pattern = new_auto_mask_pattern
+ self.notify_property_list_changed()
+ self._update_qr()
+
+func get_auto_mask_pattern() -> bool:
+ return self._qr.auto_mask_pattern
+
+func set_mask_pattern(new_mask_pattern: int) -> void:
+ self._qr.mask_pattern = new_mask_pattern
+ self._update_qr()
+
+func get_mask_pattern() -> int:
+ return self._qr.mask_pattern
+
+func set_light_module_color(new_light_module_color: Color) -> void:
+ light_module_color = new_light_module_color
+ self._update_qr()
+
+func set_dark_module_color(new_dark_module_color: Color) -> void:
+ dark_module_color = new_dark_module_color
+ self._update_qr()
+
+func set_auto_module_px_size(new_auto_module_px_size: bool) -> void:
+ auto_module_px_size = new_auto_module_px_size
+ self.notify_property_list_changed()
+ self.update_configuration_warnings()
+ self._update_qr()
+
+func set_module_px_size(new_module_px_size: int) -> void:
+ module_px_size = new_module_px_size
+ if !self.auto_module_px_size:
+ self._update_qr()
+
+func _init() -> void:
+ if self.texture != null:
+ self._update_qr()
+
+func _set(property: StringName, value: Variant) -> bool:
+ if property == "expand_mode":
+ self.update_configuration_warnings()
+
+ return false
+
+func _get_property_list() -> Array[Dictionary]:
+ var data_prop: Dictionary = {
+ "name": "data",
+ "usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE,
+ }
+ match self.mode:
+ QRCode.Mode.NUMERIC:
+ data_prop["type"] = TYPE_STRING
+ QRCode.Mode.ALPHANUMERIC, QRCode.Mode.KANJI:
+ data_prop["type"] = TYPE_STRING
+ data_prop["hint"] = PROPERTY_HINT_MULTILINE_TEXT
+ QRCode.Mode.BYTE:
+ # these encoding is nativeley supported
+ if self.eci_value in [QRCode.ECI.ISO_8859_1, QRCode.ECI.SHIFT_JIS, QRCode.ECI.UTF_8, QRCode.ECI.UTF_16, QRCode.ECI.US_ASCII]:
+ data_prop["type"] = TYPE_STRING
+ data_prop["hint"] = PROPERTY_HINT_MULTILINE_TEXT
+ else:
+ data_prop["type"] = TYPE_PACKED_BYTE_ARRAY
+
+ var version_prop: Dictionary = {
+ "name": "version",
+ "type": TYPE_INT,
+ "usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE,
+ "hint": PROPERTY_HINT_RANGE,
+ "hint_string": "1,40"
+ }
+ if self.auto_version:
+ version_prop["usage"] = (version_prop["usage"] | PROPERTY_USAGE_READ_ONLY) & ~PROPERTY_USAGE_STORAGE
+
+ var mask_prop: Dictionary = {
+ "name": "mask_pattern",
+ "type": TYPE_INT,
+ "usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE,
+ "hint": PROPERTY_HINT_RANGE,
+ "hint_string": "0,7"
+ }
+ if self.auto_mask_pattern:
+ mask_prop["usage"] = (mask_prop["usage"] | PROPERTY_USAGE_READ_ONLY) & ~PROPERTY_USAGE_STORAGE
+
+ var module_px_size_prop: Dictionary = {
+ "name": "module_px_size",
+ "type": TYPE_INT,
+ "usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE,
+ "hint": PROPERTY_HINT_RANGE,
+ "hint_string": "1,1,or_greater"
+ }
+ if self.auto_module_px_size:
+ module_px_size_prop["usage"] = (module_px_size_prop["usage"] | PROPERTY_USAGE_READ_ONLY) & ~PROPERTY_USAGE_STORAGE
+
+ return [
+ data_prop,
+ {
+ "name": "auto_version",
+ "type": TYPE_BOOL,
+ "usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE,
+ },
+ version_prop,
+ {
+ "name": "auto_mask_pattern",
+ "type": TYPE_BOOL,
+ "usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE,
+ },
+ mask_prop,
+ {
+ "name": "Appearance",
+ "type": TYPE_NIL,
+ "usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_GROUP,
+ },
+ {
+ "name": "light_module_color",
+ "type": TYPE_COLOR,
+ "usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE ,
+ },
+ {
+ "name": "dark_module_color",
+ "type": TYPE_COLOR,
+ "usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE ,
+ },
+ {
+ "name": "auto_module_px_size",
+ "type": TYPE_BOOL,
+ "usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE,
+ },
+ module_px_size_prop
+ ]
+
+func _property_can_revert(property: StringName) -> bool:
+ return property in ["auto_version", "auto_mask_pattern", "light_module_color", "dark_module_color", "auto_module_px_size"]
+
+func _property_get_revert(property: StringName) -> Variant:
+ match property:
+ "auto_version":
+ return true
+ "auto_mask_pattern":
+ return true
+ "light_module_color":
+ return Color.WHITE
+ "dark_module_color":
+ return Color.BLACK
+ "auto_module_px_size":
+ return true
+ _:
+ return null
+
+func _get_configuration_warnings():
+ if self.auto_module_px_size && self.expand_mode == EXPAND_KEEP_SIZE:
+ return ["Do not use auto module px size AND keep size expand mode."]
+ return []
+
+func _notification(what: int) -> void:
+ match what:
+ NOTIFICATION_RESIZED:
+ if self.auto_module_px_size:
+ self._update_qr()
+
+func _update_qr() -> void:
+ if self.auto_module_px_size:
+ self.module_px_size = mini(self.size.x, self.size.y) / self._qr.get_module_count()
+ self.texture = ImageTexture.create_from_image(self._qr.generate_image(self.module_px_size, self.light_module_color, self.dark_module_color))
diff --git a/addons/qr_code/reed_solomon.gd b/addons/qr_code/reed_solomon.gd
new file mode 100644
index 0000000..84e348f
--- /dev/null
+++ b/addons/qr_code/reed_solomon.gd
@@ -0,0 +1,76 @@
+# log -> exponent/antilog
+static var _anti_log_table: PackedByteArray = []
+# exponent/antilog -> log
+static var _log_table: PackedByteArray = []
+
+static func _static_init() -> void:
+ _create_log_anti_log_tables()
+
+static func _anti_log(degree: int) -> int:
+ var res: int = 1
+ var alpha: int = 2
+
+ while degree != 0:
+ if degree & 1 == 1:
+ res = mul(res, alpha)
+ degree = degree >> 1
+ alpha = mul(alpha, alpha)
+
+ return res
+
+static func _create_log_anti_log_tables() -> void:
+ _anti_log_table.resize(256)
+ _anti_log_table.fill(0)
+ _log_table.resize(256)
+ _log_table.fill(0)
+ for degree in range(0, 256):
+ var value: int = _anti_log(degree)
+ _anti_log_table[degree] = value
+ _log_table[value] = degree % 255
+
+# Russian Peasant Multiplication algorithm, adapted to reed solomon
+static func mul(lhs: int, rhs: int) -> int:
+ var res: int = 0
+ while rhs > 0:
+ if rhs & 1:
+ res = res ^ lhs
+ lhs = lhs << 1 # lhs * 2
+ rhs = rhs >> 1 # rhs / 2
+ if lhs & 256:
+ lhs = lhs ^ 0x11D
+ return res
+
+static func generator_polynom(size: int) -> PackedByteArray:
+ var res: PackedByteArray = []
+ res.resize(size + 1)
+ res.fill(0)
+ res[0] = 1
+
+ var a_j: int = 1
+ for exp in range(0, size):
+ var cur_val: int = a_j
+ for cur_exp in range(1, exp + 1):
+ var old_res: int = res[cur_exp]
+ res[cur_exp] = cur_val ^ old_res
+ cur_val = mul(old_res, a_j)
+ res[exp + 1] = cur_val
+
+ a_j = mul(a_j, 0x02)
+ return res
+
+static func encode(data: PackedByteArray, code_words: int) -> PackedByteArray:
+ assert(len(data) + code_words <= 255, "message to encode is to long")
+ var gen_poly: PackedByteArray = generator_polynom(code_words)
+ var enc_msg: PackedByteArray = []
+ enc_msg.resize(len(data) + len(gen_poly) - 1)
+ enc_msg.fill(0)
+
+ for idx in range(len(data)):
+ enc_msg[idx] = data[idx]
+
+ for idx in range(len(data)):
+ var coef: int = enc_msg[idx]
+ for p_idx in range(1, len(gen_poly)):
+ enc_msg[idx+p_idx] ^= mul(gen_poly[p_idx], coef)
+
+ return enc_msg.slice(len(data))
diff --git a/addons/qr_code/shift_jis.gd b/addons/qr_code/shift_jis.gd
new file mode 100644
index 0000000..a6d20d7
--- /dev/null
+++ b/addons/qr_code/shift_jis.gd
@@ -0,0 +1,23050 @@
+## returns u16 int array, which is Shift JIS encoded
+## unknown characters are skipped
+static func to_shift_jis_2004_buffer(text: String) -> PackedByteArray:
+ var res: PackedByteArray = PackedByteArray()
+ res.resize(2 * text.length())
+
+ var byte_idx: int = 0
+ var idx: int = 0
+ while idx < text.length():
+ var unicode: int = text.unicode_at(idx)
+ # unicode value combined with the next one
+ # there are 25 characters which are using two unicode numbers
+ var unicode_comb: int = -1
+ if (idx + 1) < text.length():
+ unicode_comb = (unicode << 16) | text.unicode_at(idx + 1)
+
+ if unicode_comb != -1 && _UNICODE_TO_SHIFT_JIS_TABLE.has(unicode_comb):
+ res.encode_u16(byte_idx, _UNICODE_TO_SHIFT_JIS_TABLE[unicode_comb])
+ idx += 2
+ elif _UNICODE_TO_SHIFT_JIS_TABLE.has(unicode):
+ res.encode_u16(byte_idx, _UNICODE_TO_SHIFT_JIS_TABLE[unicode])
+ idx += 1
+ else:
+ idx += 1
+ continue
+ byte_idx += 2
+
+ res.resize(byte_idx)
+ return res
+
+
+## requires an u16 int array, which is Shift JIS encoded
+## unknown characters are skipped
+static func get_string_from_jis_2004(arr: PackedByteArray) -> String:
+ assert(arr.size() % 2 == 0)
+ var res: String = ""
+
+ for idx in range(arr.size() / 2):
+ var unicode: int = _SHIFT_JIS_TO_UNICODE_TABLE.get(arr.decode_u16(idx * 2), -1)
+ if unicode != -1:
+ res += char(unicode)
+
+ return res
+
+
+## returns u8 int array, which is JIS 8 encoded
+## unknown characters are skipped
+static func to_jis_8_buffer(text: String) -> PackedByteArray:
+ var res: PackedByteArray = PackedByteArray()
+ res.resize(text.length())
+
+ var byte_idx: int = 0
+ for idx in range(text.length()):
+ var unicode: int = text.unicode_at(idx)
+ var jis_val: int = _UNICODE_TO_SHIFT_JIS_TABLE.get(unicode, -1)
+ if jis_val != -1 && jis_val <= 0xFF:
+ res.append(jis_val)
+ byte_idx += 1
+
+ res.resize(byte_idx)
+ return res
+
+
+## requires an u8 int array, which is JIS 8 encoded
+## unknown characters are skipped
+static func get_string_from_jis_8(arr: PackedByteArray) -> String:
+ var res: String = ""
+
+ for idx in range(arr.size()):
+ var unicode: int = _SHIFT_JIS_TO_UNICODE_TABLE.get(arr.decode_u8(idx), -1)
+ if unicode != -1:
+ res += char(unicode)
+
+ return res
+
+
+## Shift_JIS-2004 (JIS X 0213:2004 Appendix 1) vs Unicode mapping table
+##
+## Date: 3 May 2009
+## License:
+## Copyright (C) 2001 earthian@tama.or.jp, All Rights Reserved.
+## Copyright (C) 2001 I'O, All Rights Reserved.
+## Copyright (C) 2006, 2009 Project X0213, All Rights Reserved.
+## You can use, modify, distribute this table freely.
+## Note:
+## [1983] JIS codepoint defined by JIS X 0208-1983
+## [1990] JIS codepoint defined by JIS X 0208-1990
+## [2000] JIS codepoint defined by JIS X 0213:2000
+## [2004] JIS codepoint defined by JIS X 0213:2004
+## [Unicode3.1] UCS codepoint defined by Unicode 3.1
+## [Unicode3.2] UCS codepoint defined by Unicode 3.2
+## Fullwidth UCS fullwidth form (U+Fxxx)
+## Windows Windows (CP932) mapping
+const _UNICODE_TO_SHIFT_JIS_TABLE: Dictionary = {
+ 0x0000: 0x00, #
+ 0x0001: 0x01, #
+ 0x0002: 0x02, #
+ 0x0003: 0x03, #
+ 0x0004: 0x04, #
+ 0x0005: 0x05, #
+ 0x0006: 0x06, #
+ 0x0007: 0x07, #
+ 0x0008: 0x08, #
+ 0x0009: 0x09, #
+ 0x000A: 0x0A, #
+ 0x000B: 0x0B, #
+ 0x000C: 0x0C, #
+ 0x000D: 0x0D, #
+ 0x000E: 0x0E, #
+ 0x000F: 0x0F, #
+ 0x0010: 0x10, #
+ 0x0011: 0x11, #
+ 0x0012: 0x12, #
+ 0x0013: 0x13, #
+ 0x0014: 0x14, #
+ 0x0015: 0x15, #
+ 0x0016: 0x16, #
+ 0x0017: 0x17, #
+ 0x0018: 0x18, #
+ 0x0019: 0x19, #
+ 0x001A: 0x1A, #
+ 0x001B: 0x1B, #
+ 0x001C: 0x1C, #
+ 0x001D: 0x1D, #
+ 0x001E: 0x1E, #
+ 0x001F: 0x1F, #
+ 0x0020: 0x20, # SPACE
+ 0x0021: 0x21, # EXCLAMATION MARK
+ 0x0022: 0x22, # QUOTATION MARK
+ 0x0023: 0x23, # NUMBER SIGN
+ 0x0024: 0x24, # DOLLAR SIGN
+ 0x0025: 0x25, # PERCENT SIGN
+ 0x0026: 0x26, # AMPERSAND
+ 0x0027: 0x27, # APOSTROPHE
+ 0x0028: 0x28, # LEFT PARENTHESIS
+ 0x0029: 0x29, # RIGHT PARENTHESIS
+ 0x002A: 0x2A, # ASTERISK
+ 0x002B: 0x2B, # PLUS SIGN
+ 0x002C: 0x2C, # COMMA
+ 0x002D: 0x2D, # HYPHEN-MINUS
+ 0x002E: 0x2E, # FULL STOP
+ 0x002F: 0x2F, # SOLIDUS
+ 0x0030: 0x30, # DIGIT ZERO
+ 0x0031: 0x31, # DIGIT ONE
+ 0x0032: 0x32, # DIGIT TWO
+ 0x0033: 0x33, # DIGIT THREE
+ 0x0034: 0x34, # DIGIT FOUR
+ 0x0035: 0x35, # DIGIT FIVE
+ 0x0036: 0x36, # DIGIT SIX
+ 0x0037: 0x37, # DIGIT SEVEN
+ 0x0038: 0x38, # DIGIT EIGHT
+ 0x0039: 0x39, # DIGIT NINE
+ 0x003A: 0x3A, # COLON
+ 0x003B: 0x3B, # SEMICOLON
+ 0x003C: 0x3C, # LESS-THAN SIGN
+ 0x003D: 0x3D, # EQUALS SIGN
+ 0x003E: 0x3E, # GREATER-THAN SIGN
+ 0x003F: 0x3F, # QUESTION MARK
+ 0x0040: 0x40, # COMMERCIAL AT
+ 0x0041: 0x41, # LATIN CAPITAL LETTER A
+ 0x0042: 0x42, # LATIN CAPITAL LETTER B
+ 0x0043: 0x43, # LATIN CAPITAL LETTER C
+ 0x0044: 0x44, # LATIN CAPITAL LETTER D
+ 0x0045: 0x45, # LATIN CAPITAL LETTER E
+ 0x0046: 0x46, # LATIN CAPITAL LETTER F
+ 0x0047: 0x47, # LATIN CAPITAL LETTER G
+ 0x0048: 0x48, # LATIN CAPITAL LETTER H
+ 0x0049: 0x49, # LATIN CAPITAL LETTER I
+ 0x004A: 0x4A, # LATIN CAPITAL LETTER J
+ 0x004B: 0x4B, # LATIN CAPITAL LETTER K
+ 0x004C: 0x4C, # LATIN CAPITAL LETTER L
+ 0x004D: 0x4D, # LATIN CAPITAL LETTER M
+ 0x004E: 0x4E, # LATIN CAPITAL LETTER N
+ 0x004F: 0x4F, # LATIN CAPITAL LETTER O
+ 0x0050: 0x50, # LATIN CAPITAL LETTER P
+ 0x0051: 0x51, # LATIN CAPITAL LETTER Q
+ 0x0052: 0x52, # LATIN CAPITAL LETTER R
+ 0x0053: 0x53, # LATIN CAPITAL LETTER S
+ 0x0054: 0x54, # LATIN CAPITAL LETTER T
+ 0x0055: 0x55, # LATIN CAPITAL LETTER U
+ 0x0056: 0x56, # LATIN CAPITAL LETTER V
+ 0x0057: 0x57, # LATIN CAPITAL LETTER W
+ 0x0058: 0x58, # LATIN CAPITAL LETTER X
+ 0x0059: 0x59, # LATIN CAPITAL LETTER Y
+ 0x005A: 0x5A, # LATIN CAPITAL LETTER Z
+ 0x005B: 0x5B, # LEFT SQUARE BRACKET
+ 0x00A5: 0x5C, # YEN SIGN
+ 0x005D: 0x5D, # RIGHT SQUARE BRACKET
+ 0x005E: 0x5E, # CIRCUMFLEX ACCENT
+ 0x005F: 0x5F, # LOW LINE
+ 0x0060: 0x60, # GRAVE ACCENT
+ 0x0061: 0x61, # LATIN SMALL LETTER A
+ 0x0062: 0x62, # LATIN SMALL LETTER B
+ 0x0063: 0x63, # LATIN SMALL LETTER C
+ 0x0064: 0x64, # LATIN SMALL LETTER D
+ 0x0065: 0x65, # LATIN SMALL LETTER E
+ 0x0066: 0x66, # LATIN SMALL LETTER F
+ 0x0067: 0x67, # LATIN SMALL LETTER G
+ 0x0068: 0x68, # LATIN SMALL LETTER H
+ 0x0069: 0x69, # LATIN SMALL LETTER I
+ 0x006A: 0x6A, # LATIN SMALL LETTER J
+ 0x006B: 0x6B, # LATIN SMALL LETTER K
+ 0x006C: 0x6C, # LATIN SMALL LETTER L
+ 0x006D: 0x6D, # LATIN SMALL LETTER M
+ 0x006E: 0x6E, # LATIN SMALL LETTER N
+ 0x006F: 0x6F, # LATIN SMALL LETTER O
+ 0x0070: 0x70, # LATIN SMALL LETTER P
+ 0x0071: 0x71, # LATIN SMALL LETTER Q
+ 0x0072: 0x72, # LATIN SMALL LETTER R
+ 0x0073: 0x73, # LATIN SMALL LETTER S
+ 0x0074: 0x74, # LATIN SMALL LETTER T
+ 0x0075: 0x75, # LATIN SMALL LETTER U
+ 0x0076: 0x76, # LATIN SMALL LETTER V
+ 0x0077: 0x77, # LATIN SMALL LETTER W
+ 0x0078: 0x78, # LATIN SMALL LETTER X
+ 0x0079: 0x79, # LATIN SMALL LETTER Y
+ 0x007A: 0x7A, # LATIN SMALL LETTER Z
+ 0x007B: 0x7B, # LEFT CURLY BRACKET
+ 0x007C: 0x7C, # VERTICAL LINE
+ 0x007D: 0x7D, # RIGHT CURLY BRACKET
+ 0x203E: 0x7E, # OVERLINE
+ 0x007F: 0x7F, #
+# 0x80 -
+# 0x81 -
+# 0x82 -
+# 0x83 -
+# 0x84 -
+# 0x85 -
+# 0x86 -
+# 0x87 -
+# 0x88 -
+# 0x89 -
+# 0x8A -
+# 0x8B -
+# 0x8C -
+# 0x8D -
+# 0x8E -
+# 0x8F -
+# 0x90 -
+# 0x91 -
+# 0x92 -
+# 0x93 -
+# 0x94 -
+# 0x95 -
+# 0x96 -
+# 0x97 -
+# 0x98 -
+# 0x99 -
+# 0x9A -
+# 0x9B -
+# 0x9C -
+# 0x9D -
+# 0x9E -
+# 0x9F -
+# 0xA0 -
+ 0xFF61: 0xA1, # HALFWIDTH IDEOGRAPHIC FULL STOP
+ 0xFF62: 0xA2, # HALFWIDTH LEFT CORNER BRACKET
+ 0xFF63: 0xA3, # HALFWIDTH RIGHT CORNER BRACKET
+ 0xFF64: 0xA4, # HALFWIDTH IDEOGRAPHIC COMMA
+ 0xFF65: 0xA5, # HALFWIDTH KATAKANA MIDDLE DOT
+ 0xFF66: 0xA6, # HALFWIDTH KATAKANA LETTER WO
+ 0xFF67: 0xA7, # HALFWIDTH KATAKANA LETTER SMALL A
+ 0xFF68: 0xA8, # HALFWIDTH KATAKANA LETTER SMALL I
+ 0xFF69: 0xA9, # HALFWIDTH KATAKANA LETTER SMALL U
+ 0xFF6A: 0xAA, # HALFWIDTH KATAKANA LETTER SMALL E
+ 0xFF6B: 0xAB, # HALFWIDTH KATAKANA LETTER SMALL O
+ 0xFF6C: 0xAC, # HALFWIDTH KATAKANA LETTER SMALL YA
+ 0xFF6D: 0xAD, # HALFWIDTH KATAKANA LETTER SMALL YU
+ 0xFF6E: 0xAE, # HALFWIDTH KATAKANA LETTER SMALL YO
+ 0xFF6F: 0xAF, # HALFWIDTH KATAKANA LETTER SMALL TU
+ 0xFF70: 0xB0, # HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK
+ 0xFF71: 0xB1, # HALFWIDTH KATAKANA LETTER A
+ 0xFF72: 0xB2, # HALFWIDTH KATAKANA LETTER I
+ 0xFF73: 0xB3, # HALFWIDTH KATAKANA LETTER U
+ 0xFF74: 0xB4, # HALFWIDTH KATAKANA LETTER E
+ 0xFF75: 0xB5, # HALFWIDTH KATAKANA LETTER O
+ 0xFF76: 0xB6, # HALFWIDTH KATAKANA LETTER KA
+ 0xFF77: 0xB7, # HALFWIDTH KATAKANA LETTER KI
+ 0xFF78: 0xB8, # HALFWIDTH KATAKANA LETTER KU
+ 0xFF79: 0xB9, # HALFWIDTH KATAKANA LETTER KE
+ 0xFF7A: 0xBA, # HALFWIDTH KATAKANA LETTER KO
+ 0xFF7B: 0xBB, # HALFWIDTH KATAKANA LETTER SA
+ 0xFF7C: 0xBC, # HALFWIDTH KATAKANA LETTER SI
+ 0xFF7D: 0xBD, # HALFWIDTH KATAKANA LETTER SU
+ 0xFF7E: 0xBE, # HALFWIDTH KATAKANA LETTER SE
+ 0xFF7F: 0xBF, # HALFWIDTH KATAKANA LETTER SO
+ 0xFF80: 0xC0, # HALFWIDTH KATAKANA LETTER TA
+ 0xFF81: 0xC1, # HALFWIDTH KATAKANA LETTER TI
+ 0xFF82: 0xC2, # HALFWIDTH KATAKANA LETTER TU
+ 0xFF83: 0xC3, # HALFWIDTH KATAKANA LETTER TE
+ 0xFF84: 0xC4, # HALFWIDTH KATAKANA LETTER TO
+ 0xFF85: 0xC5, # HALFWIDTH KATAKANA LETTER NA
+ 0xFF86: 0xC6, # HALFWIDTH KATAKANA LETTER NI
+ 0xFF87: 0xC7, # HALFWIDTH KATAKANA LETTER NU
+ 0xFF88: 0xC8, # HALFWIDTH KATAKANA LETTER NE
+ 0xFF89: 0xC9, # HALFWIDTH KATAKANA LETTER NO
+ 0xFF8A: 0xCA, # HALFWIDTH KATAKANA LETTER HA
+ 0xFF8B: 0xCB, # HALFWIDTH KATAKANA LETTER HI
+ 0xFF8C: 0xCC, # HALFWIDTH KATAKANA LETTER HU
+ 0xFF8D: 0xCD, # HALFWIDTH KATAKANA LETTER HE
+ 0xFF8E: 0xCE, # HALFWIDTH KATAKANA LETTER HO
+ 0xFF8F: 0xCF, # HALFWIDTH KATAKANA LETTER MA
+ 0xFF90: 0xD0, # HALFWIDTH KATAKANA LETTER MI
+ 0xFF91: 0xD1, # HALFWIDTH KATAKANA LETTER MU
+ 0xFF92: 0xD2, # HALFWIDTH KATAKANA LETTER ME
+ 0xFF93: 0xD3, # HALFWIDTH KATAKANA LETTER MO
+ 0xFF94: 0xD4, # HALFWIDTH KATAKANA LETTER YA
+ 0xFF95: 0xD5, # HALFWIDTH KATAKANA LETTER YU
+ 0xFF96: 0xD6, # HALFWIDTH KATAKANA LETTER YO
+ 0xFF97: 0xD7, # HALFWIDTH KATAKANA LETTER RA
+ 0xFF98: 0xD8, # HALFWIDTH KATAKANA LETTER RI
+ 0xFF99: 0xD9, # HALFWIDTH KATAKANA LETTER RU
+ 0xFF9A: 0xDA, # HALFWIDTH KATAKANA LETTER RE
+ 0xFF9B: 0xDB, # HALFWIDTH KATAKANA LETTER RO
+ 0xFF9C: 0xDC, # HALFWIDTH KATAKANA LETTER WA
+ 0xFF9D: 0xDD, # HALFWIDTH KATAKANA LETTER N
+ 0xFF9E: 0xDE, # HALFWIDTH KATAKANA VOICED SOUND MARK
+ 0xFF9F: 0xDF, # HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK
+# 0xE0 -
+# 0xE1 -
+# 0xE2 -
+# 0xE3 -
+# 0xE4 -
+# 0xE5 -
+# 0xE6 -
+# 0xE7 -
+# 0xE8 -
+# 0xE9 -
+# 0xEA -
+# 0xEB -
+# 0xEC -
+# 0xED -
+# 0xEE -
+# 0xEF -
+# 0xF0 -
+# 0xF1 -
+# 0xF2 -
+# 0xF3 -
+# 0xF4 -
+# 0xF5 -
+# 0xF6 -
+# 0xF7 -
+# 0xF8 -
+# 0xF9 -
+# 0xFA -
+# 0xFB -
+# 0xFC -
+# 0xFD -
+# 0xFE -
+# 0xFF -
+ 0x3000: 0x8140, # IDEOGRAPHIC SPACE
+ 0x3001: 0x8141, # IDEOGRAPHIC COMMA
+ 0x3002: 0x8142, # IDEOGRAPHIC FULL STOP
+ 0xFF0C: 0x8143, # FULLWIDTH COMMA
+ 0xFF0E: 0x8144, # FULLWIDTH FULL STOP
+ 0x30FB: 0x8145, # KATAKANA MIDDLE DOT
+ 0xFF1A: 0x8146, # FULLWIDTH COLON
+ 0xFF1B: 0x8147, # FULLWIDTH SEMICOLON
+ 0xFF1F: 0x8148, # FULLWIDTH QUESTION MARK
+ 0xFF01: 0x8149, # FULLWIDTH EXCLAMATION MARK
+ 0x309B: 0x814A, # KATAKANA-HIRAGANA VOICED SOUND MARK
+ 0x309C: 0x814B, # KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
+ 0x00B4: 0x814C, # ACUTE ACCENT
+ 0xFF40: 0x814D, # FULLWIDTH GRAVE ACCENT
+ 0x00A8: 0x814E, # DIAERESIS
+ 0xFF3E: 0x814F, # FULLWIDTH CIRCUMFLEX ACCENT
+ 0xFFE3: 0x8150, # FULLWIDTH MACRON
+ 0xFF3F: 0x8151, # FULLWIDTH LOW LINE
+ 0x30FD: 0x8152, # KATAKANA ITERATION MARK
+ 0x30FE: 0x8153, # KATAKANA VOICED ITERATION MARK
+ 0x309D: 0x8154, # HIRAGANA ITERATION MARK
+ 0x309E: 0x8155, # HIRAGANA VOICED ITERATION MARK
+ 0x3003: 0x8156, # DITTO MARK
+ 0x4EDD: 0x8157, #
+ 0x3005: 0x8158, # IDEOGRAPHIC ITERATION MARK
+ 0x3006: 0x8159, # IDEOGRAPHIC CLOSING MARK
+ 0x3007: 0x815A, # IDEOGRAPHIC NUMBER ZERO
+ 0x30FC: 0x815B, # KATAKANA-HIRAGANA PROLONGED SOUND MARK
+ 0x2014: 0x815C, # EM DASH Windows: U+2015
+ 0x2010: 0x815D, # HYPHEN
+ 0xFF0F: 0x815E, # FULLWIDTH SOLIDUS
+ 0x005C: 0x815F, # REVERSE SOLIDUS Fullwidth: U+FF3C
+ 0x301C: 0x8160, # WAVE DASH Windows: U+FF5E
+ 0x2016: 0x8161, # DOUBLE VERTICAL LINE Windows: U+2225
+ 0xFF5C: 0x8162, # FULLWIDTH VERTICAL LINE
+ 0x2026: 0x8163, # HORIZONTAL ELLIPSIS
+ 0x2025: 0x8164, # TWO DOT LEADER
+ 0x2018: 0x8165, # LEFT SINGLE QUOTATION MARK
+ 0x2019: 0x8166, # RIGHT SINGLE QUOTATION MARK
+ 0x201C: 0x8167, # LEFT DOUBLE QUOTATION MARK
+ 0x201D: 0x8168, # RIGHT DOUBLE QUOTATION MARK
+ 0xFF08: 0x8169, # FULLWIDTH LEFT PARENTHESIS
+ 0xFF09: 0x816A, # FULLWIDTH RIGHT PARENTHESIS
+ 0x3014: 0x816B, # LEFT TORTOISE SHELL BRACKET
+ 0x3015: 0x816C, # RIGHT TORTOISE SHELL BRACKET
+ 0xFF3B: 0x816D, # FULLWIDTH LEFT SQUARE BRACKET
+ 0xFF3D: 0x816E, # FULLWIDTH RIGHT SQUARE BRACKET
+ 0xFF5B: 0x816F, # FULLWIDTH LEFT CURLY BRACKET
+ 0xFF5D: 0x8170, # FULLWIDTH RIGHT CURLY BRACKET
+ 0x3008: 0x8171, # LEFT ANGLE BRACKET
+ 0x3009: 0x8172, # RIGHT ANGLE BRACKET
+ 0x300A: 0x8173, # LEFT DOUBLE ANGLE BRACKET
+ 0x300B: 0x8174, # RIGHT DOUBLE ANGLE BRACKET
+ 0x300C: 0x8175, # LEFT CORNER BRACKET
+ 0x300D: 0x8176, # RIGHT CORNER BRACKET
+ 0x300E: 0x8177, # LEFT WHITE CORNER BRACKET
+ 0x300F: 0x8178, # RIGHT WHITE CORNER BRACKET
+ 0x3010: 0x8179, # LEFT BLACK LENTICULAR BRACKET
+ 0x3011: 0x817A, # RIGHT BLACK LENTICULAR BRACKET
+ 0xFF0B: 0x817B, # FULLWIDTH PLUS SIGN
+ 0x2212: 0x817C, # MINUS SIGN Windows: U+FF0D
+ 0x00B1: 0x817D, # PLUS-MINUS SIGN
+ 0x00D7: 0x817E, # MULTIPLICATION SIGN
+ 0x00F7: 0x8180, # DIVISION SIGN
+ 0xFF1D: 0x8181, # FULLWIDTH EQUALS SIGN
+ 0x2260: 0x8182, # NOT EQUAL TO
+ 0xFF1C: 0x8183, # FULLWIDTH LESS-THAN SIGN
+ 0xFF1E: 0x8184, # FULLWIDTH GREATER-THAN SIGN
+ 0x2266: 0x8185, # LESS-THAN OVER EQUAL TO
+ 0x2267: 0x8186, # GREATER-THAN OVER EQUAL TO
+ 0x221E: 0x8187, # INFINITY
+ 0x2234: 0x8188, # THEREFORE
+ 0x2642: 0x8189, # MALE SIGN
+ 0x2640: 0x818A, # FEMALE SIGN
+ 0x00B0: 0x818B, # DEGREE SIGN
+ 0x2032: 0x818C, # PRIME
+ 0x2033: 0x818D, # DOUBLE PRIME
+ 0x2103: 0x818E, # DEGREE CELSIUS
+ 0xFFE5: 0x818F, # FULLWIDTH YEN SIGN
+ 0xFF04: 0x8190, # FULLWIDTH DOLLAR SIGN
+ 0x00A2: 0x8191, # CENT SIGN Windows: U+FFE0
+ 0x00A3: 0x8192, # POUND SIGN Windows: U+FFE1
+ 0xFF05: 0x8193, # FULLWIDTH PERCENT SIGN
+ 0xFF03: 0x8194, # FULLWIDTH NUMBER SIGN
+ 0xFF06: 0x8195, # FULLWIDTH AMPERSAND
+ 0xFF0A: 0x8196, # FULLWIDTH ASTERISK
+ 0xFF20: 0x8197, # FULLWIDTH COMMERCIAL AT
+ 0x00A7: 0x8198, # SECTION SIGN
+ 0x2606: 0x8199, # WHITE STAR
+ 0x2605: 0x819A, # BLACK STAR
+ 0x25CB: 0x819B, # WHITE CIRCLE
+ 0x25CF: 0x819C, # BLACK CIRCLE
+ 0x25CE: 0x819D, # BULLSEYE
+ 0x25C7: 0x819E, # WHITE DIAMOND
+ 0x25C6: 0x819F, # BLACK DIAMOND
+ 0x25A1: 0x81A0, # WHITE SQUARE
+ 0x25A0: 0x81A1, # BLACK SQUARE
+ 0x25B3: 0x81A2, # WHITE UP-POINTING TRIANGLE
+ 0x25B2: 0x81A3, # BLACK UP-POINTING TRIANGLE
+ 0x25BD: 0x81A4, # WHITE DOWN-POINTING TRIANGLE
+ 0x25BC: 0x81A5, # BLACK DOWN-POINTING TRIANGLE
+ 0x203B: 0x81A6, # REFERENCE MARK
+ 0x3012: 0x81A7, # POSTAL MARK
+ 0x2192: 0x81A8, # RIGHTWARDS ARROW
+ 0x2190: 0x81A9, # LEFTWARDS ARROW
+ 0x2191: 0x81AA, # UPWARDS ARROW
+ 0x2193: 0x81AB, # DOWNWARDS ARROW
+ 0x3013: 0x81AC, # GETA MARK
+ 0xFF07: 0x81AD, # FULLWIDTH APOSTROPHE [2000]
+ 0xFF02: 0x81AE, # FULLWIDTH QUOTATION MARK [2000]
+ 0xFF0D: 0x81AF, # FULLWIDTH HYPHEN-MINUS [2000]
+ 0x007E: 0x81B0, # TILDE [2000] Fullwidth: U+FF5E
+ 0x3033: 0x81B1, # VERTICAL KANA REPEAT MARK UPPER HALF [2000]
+ 0x3034: 0x81B2, # VERTICAL KANA REPEAT WITH VOICED SOUND MARK UPPER HALF [2000]
+ 0x3035: 0x81B3, # VERTICAL KANA REPEAT MARK LOWER HALF [2000]
+ 0x303B: 0x81B4, # VERTICAL IDEOGRAPHIC ITERATION MARK [2000] [Unicode3.2]
+ 0x303C: 0x81B5, # MASU MARK [2000] [Unicode3.2]
+ 0x30FF: 0x81B6, # KATAKANA DIGRAPH KOTO [2000] [Unicode3.2]
+ 0x309F: 0x81B7, # HIRAGANA DIGRAPH YORI [2000] [Unicode3.2]
+ 0x2208: 0x81B8, # ELEMENT OF [1983]
+ 0x220B: 0x81B9, # CONTAINS AS MEMBER [1983]
+ 0x2286: 0x81BA, # SUBSET OF OR EQUAL TO [1983]
+ 0x2287: 0x81BB, # SUPERSET OF OR EQUAL TO [1983]
+ 0x2282: 0x81BC, # SUBSET OF [1983]
+ 0x2283: 0x81BD, # SUPERSET OF [1983]
+ 0x222A: 0x81BE, # UNION [1983]
+ 0x2229: 0x81BF, # INTERSECTION [1983]
+ 0x2284: 0x81C0, # NOT A SUBSET OF [2000]
+ 0x2285: 0x81C1, # NOT A SUPERSET OF [2000]
+ 0x228A: 0x81C2, # SUBSET OF WITH NOT EQUAL TO [2000]
+ 0x228B: 0x81C3, # SUPERSET OF WITH NOT EQUAL TO [2000]
+ 0x2209: 0x81C4, # NOT AN ELEMENT OF [2000]
+ 0x2205: 0x81C5, # EMPTY SET [2000]
+ 0x2305: 0x81C6, # PROJECTIVE [2000]
+ 0x2306: 0x81C7, # PERSPECTIVE [2000]
+ 0x2227: 0x81C8, # LOGICAL AND [1983]
+ 0x2228: 0x81C9, # LOGICAL OR [1983]
+ 0x00AC: 0x81CA, # NOT SIGN [1983] Windows: U+FFE2
+ 0x21D2: 0x81CB, # RIGHTWARDS DOUBLE ARROW [1983]
+ 0x21D4: 0x81CC, # LEFT RIGHT DOUBLE ARROW [1983]
+ 0x2200: 0x81CD, # FOR ALL [1983]
+ 0x2203: 0x81CE, # THERE EXISTS [1983]
+ 0x2295: 0x81CF, # CIRCLED PLUS [2000]
+ 0x2296: 0x81D0, # CIRCLED MINUS [2000]
+ 0x2297: 0x81D1, # CIRCLED TIMES [2000]
+ 0x2225: 0x81D2, # PARALLEL TO [2000]
+ 0x2226: 0x81D3, # NOT PARALLEL TO [2000]
+ 0xFF5F: 0x81D4, # FULLWIDTH LEFT WHITE PARENTHESIS [2000] [Unicode3.2]
+ 0xFF60: 0x81D5, # FULLWIDTH RIGHT WHITE PARENTHESIS [2000] [Unicode3.2]
+ 0x3018: 0x81D6, # LEFT WHITE TORTOISE SHELL BRACKET [2000]
+ 0x3019: 0x81D7, # RIGHT WHITE TORTOISE SHELL BRACKET [2000]
+ 0x3016: 0x81D8, # LEFT WHITE LENTICULAR BRACKET [2000]
+ 0x3017: 0x81D9, # RIGHT WHITE LENTICULAR BRACKET [2000]
+ 0x2220: 0x81DA, # ANGLE [1983]
+ 0x22A5: 0x81DB, # UP TACK [1983]
+ 0x2312: 0x81DC, # ARC [1983]
+ 0x2202: 0x81DD, # PARTIAL DIFFERENTIAL [1983]
+ 0x2207: 0x81DE, # NABLA [1983]
+ 0x2261: 0x81DF, # IDENTICAL TO [1983]
+ 0x2252: 0x81E0, # APPROXIMATELY EQUAL TO OR THE IMAGE OF [1983]
+ 0x226A: 0x81E1, # MUCH LESS-THAN [1983]
+ 0x226B: 0x81E2, # MUCH GREATER-THAN [1983]
+ 0x221A: 0x81E3, # SQUARE ROOT [1983]
+ 0x223D: 0x81E4, # REVERSED TILDE [1983]
+ 0x221D: 0x81E5, # PROPORTIONAL TO [1983]
+ 0x2235: 0x81E6, # BECAUSE [1983]
+ 0x222B: 0x81E7, # INTEGRAL [1983]
+ 0x222C: 0x81E8, # DOUBLE INTEGRAL [1983]
+ 0x2262: 0x81E9, # NOT IDENTICAL TO [2000]
+ 0x2243: 0x81EA, # ASYMPTOTICALLY EQUAL TO [2000]
+ 0x2245: 0x81EB, # APPROXIMATELY EQUAL TO [2000]
+ 0x2248: 0x81EC, # ALMOST EQUAL TO [2000]
+ 0x2276: 0x81ED, # LESS-THAN OR GREATER-THAN [2000]
+ 0x2277: 0x81EE, # GREATER-THAN OR LESS-THAN [2000]
+ 0x2194: 0x81EF, # LEFT RIGHT ARROW [2000]
+ 0x212B: 0x81F0, # ANGSTROM SIGN [1983]
+ 0x2030: 0x81F1, # PER MILLE SIGN [1983]
+ 0x266F: 0x81F2, # MUSIC SHARP SIGN [1983]
+ 0x266D: 0x81F3, # MUSIC FLAT SIGN [1983]
+ 0x266A: 0x81F4, # EIGHTH NOTE [1983]
+ 0x2020: 0x81F5, # DAGGER [1983]
+ 0x2021: 0x81F6, # DOUBLE DAGGER [1983]
+ 0x00B6: 0x81F7, # PILCROW SIGN [1983]
+ 0x266E: 0x81F8, # MUSIC NATURAL SIGN [2000]
+ 0x266B: 0x81F9, # BEAMED EIGHTH NOTES [2000]
+ 0x266C: 0x81FA, # BEAMED SIXTEENTH NOTES [2000]
+ 0x2669: 0x81FB, # QUARTER NOTE [2000]
+ 0x25EF: 0x81FC, # LARGE CIRCLE [1983]
+ 0x25B7: 0x8240, # WHITE RIGHT-POINTING TRIANGLE [2000]
+ 0x25B6: 0x8241, # BLACK RIGHT-POINTING TRIANGLE [2000]
+ 0x25C1: 0x8242, # WHITE LEFT-POINTING TRIANGLE [2000]
+ 0x25C0: 0x8243, # BLACK LEFT-POINTING TRIANGLE [2000]
+ 0x2197: 0x8244, # NORTH EAST ARROW [2000]
+ 0x2198: 0x8245, # SOUTH EAST ARROW [2000]
+ 0x2196: 0x8246, # NORTH WEST ARROW [2000]
+ 0x2199: 0x8247, # SOUTH WEST ARROW [2000]
+ 0x21C4: 0x8248, # RIGHTWARDS ARROW OVER LEFTWARDS ARROW [2000]
+ 0x21E8: 0x8249, # RIGHTWARDS WHITE ARROW [2000]
+ 0x21E6: 0x824A, # LEFTWARDS WHITE ARROW [2000]
+ 0x21E7: 0x824B, # UPWARDS WHITE ARROW [2000]
+ 0x21E9: 0x824C, # DOWNWARDS WHITE ARROW [2000]
+ 0x2934: 0x824D, # ARROW POINTING RIGHTWARDS THEN CURVING UPWARDS [2000] [Unicode3.2]
+ 0x2935: 0x824E, # ARROW POINTING RIGHTWARDS THEN CURVING DOWNWARDS [2000] [Unicode3.2]
+ 0xFF10: 0x824F, # FULLWIDTH DIGIT ZERO
+ 0xFF11: 0x8250, # FULLWIDTH DIGIT ONE
+ 0xFF12: 0x8251, # FULLWIDTH DIGIT TWO
+ 0xFF13: 0x8252, # FULLWIDTH DIGIT THREE
+ 0xFF14: 0x8253, # FULLWIDTH DIGIT FOUR
+ 0xFF15: 0x8254, # FULLWIDTH DIGIT FIVE
+ 0xFF16: 0x8255, # FULLWIDTH DIGIT SIX
+ 0xFF17: 0x8256, # FULLWIDTH DIGIT SEVEN
+ 0xFF18: 0x8257, # FULLWIDTH DIGIT EIGHT
+ 0xFF19: 0x8258, # FULLWIDTH DIGIT NINE
+ 0x29BF: 0x8259, # CIRCLED BULLET [2000] [Unicode3.2]
+ 0x25C9: 0x825A, # FISHEYE [2000]
+ 0x303D: 0x825B, # PART ALTERNATION MARK [2000] [Unicode3.2]
+ 0xFE46: 0x825C, # WHITE SESAME DOT [2000] [Unicode3.2]
+ 0xFE45: 0x825D, # SESAME DOT [2000] [Unicode3.2]
+ 0x25E6: 0x825E, # WHITE BULLET [2000]
+ 0x2022: 0x825F, # BULLET [2000]
+ 0xFF21: 0x8260, # FULLWIDTH LATIN CAPITAL LETTER A
+ 0xFF22: 0x8261, # FULLWIDTH LATIN CAPITAL LETTER B
+ 0xFF23: 0x8262, # FULLWIDTH LATIN CAPITAL LETTER C
+ 0xFF24: 0x8263, # FULLWIDTH LATIN CAPITAL LETTER D
+ 0xFF25: 0x8264, # FULLWIDTH LATIN CAPITAL LETTER E
+ 0xFF26: 0x8265, # FULLWIDTH LATIN CAPITAL LETTER F
+ 0xFF27: 0x8266, # FULLWIDTH LATIN CAPITAL LETTER G
+ 0xFF28: 0x8267, # FULLWIDTH LATIN CAPITAL LETTER H
+ 0xFF29: 0x8268, # FULLWIDTH LATIN CAPITAL LETTER I
+ 0xFF2A: 0x8269, # FULLWIDTH LATIN CAPITAL LETTER J
+ 0xFF2B: 0x826A, # FULLWIDTH LATIN CAPITAL LETTER K
+ 0xFF2C: 0x826B, # FULLWIDTH LATIN CAPITAL LETTER L
+ 0xFF2D: 0x826C, # FULLWIDTH LATIN CAPITAL LETTER M
+ 0xFF2E: 0x826D, # FULLWIDTH LATIN CAPITAL LETTER N
+ 0xFF2F: 0x826E, # FULLWIDTH LATIN CAPITAL LETTER O
+ 0xFF30: 0x826F, # FULLWIDTH LATIN CAPITAL LETTER P
+ 0xFF31: 0x8270, # FULLWIDTH LATIN CAPITAL LETTER Q
+ 0xFF32: 0x8271, # FULLWIDTH LATIN CAPITAL LETTER R
+ 0xFF33: 0x8272, # FULLWIDTH LATIN CAPITAL LETTER S
+ 0xFF34: 0x8273, # FULLWIDTH LATIN CAPITAL LETTER T
+ 0xFF35: 0x8274, # FULLWIDTH LATIN CAPITAL LETTER U
+ 0xFF36: 0x8275, # FULLWIDTH LATIN CAPITAL LETTER V
+ 0xFF37: 0x8276, # FULLWIDTH LATIN CAPITAL LETTER W
+ 0xFF38: 0x8277, # FULLWIDTH LATIN CAPITAL LETTER X
+ 0xFF39: 0x8278, # FULLWIDTH LATIN CAPITAL LETTER Y
+ 0xFF3A: 0x8279, # FULLWIDTH LATIN CAPITAL LETTER Z
+ 0x2213: 0x827A, # MINUS-OR-PLUS SIGN [2000]
+ 0x2135: 0x827B, # ALEF SYMBOL [2000]
+ 0x210F: 0x827C, # PLANCK CONSTANT OVER TWO PI [2000]
+ 0x33CB: 0x827D, # SQUARE HP [2000]
+ 0x2113: 0x827E, # SCRIPT SMALL L [2000]
+ 0x2127: 0x8280, # INVERTED OHM SIGN [2000]
+ 0xFF41: 0x8281, # FULLWIDTH LATIN SMALL LETTER A
+ 0xFF42: 0x8282, # FULLWIDTH LATIN SMALL LETTER B
+ 0xFF43: 0x8283, # FULLWIDTH LATIN SMALL LETTER C
+ 0xFF44: 0x8284, # FULLWIDTH LATIN SMALL LETTER D
+ 0xFF45: 0x8285, # FULLWIDTH LATIN SMALL LETTER E
+ 0xFF46: 0x8286, # FULLWIDTH LATIN SMALL LETTER F
+ 0xFF47: 0x8287, # FULLWIDTH LATIN SMALL LETTER G
+ 0xFF48: 0x8288, # FULLWIDTH LATIN SMALL LETTER H
+ 0xFF49: 0x8289, # FULLWIDTH LATIN SMALL LETTER I
+ 0xFF4A: 0x828A, # FULLWIDTH LATIN SMALL LETTER J
+ 0xFF4B: 0x828B, # FULLWIDTH LATIN SMALL LETTER K
+ 0xFF4C: 0x828C, # FULLWIDTH LATIN SMALL LETTER L
+ 0xFF4D: 0x828D, # FULLWIDTH LATIN SMALL LETTER M
+ 0xFF4E: 0x828E, # FULLWIDTH LATIN SMALL LETTER N
+ 0xFF4F: 0x828F, # FULLWIDTH LATIN SMALL LETTER O
+ 0xFF50: 0x8290, # FULLWIDTH LATIN SMALL LETTER P
+ 0xFF51: 0x8291, # FULLWIDTH LATIN SMALL LETTER Q
+ 0xFF52: 0x8292, # FULLWIDTH LATIN SMALL LETTER R
+ 0xFF53: 0x8293, # FULLWIDTH LATIN SMALL LETTER S
+ 0xFF54: 0x8294, # FULLWIDTH LATIN SMALL LETTER T
+ 0xFF55: 0x8295, # FULLWIDTH LATIN SMALL LETTER U
+ 0xFF56: 0x8296, # FULLWIDTH LATIN SMALL LETTER V
+ 0xFF57: 0x8297, # FULLWIDTH LATIN SMALL LETTER W
+ 0xFF58: 0x8298, # FULLWIDTH LATIN SMALL LETTER X
+ 0xFF59: 0x8299, # FULLWIDTH LATIN SMALL LETTER Y
+ 0xFF5A: 0x829A, # FULLWIDTH LATIN SMALL LETTER Z
+ 0x30A0: 0x829B, # KATAKANA-HIRAGANA DOUBLE HYPHEN [2000] [Unicode3.2]
+ 0x2013: 0x829C, # EN DASH [2000]
+ 0x29FA: 0x829D, # DOUBLE PLUS [2000] [Unicode3.2]
+ 0x29FB: 0x829E, # TRIPLE PLUS [2000] [Unicode3.2]
+ 0x3041: 0x829F, # HIRAGANA LETTER SMALL A
+ 0x3042: 0x82A0, # HIRAGANA LETTER A
+ 0x3043: 0x82A1, # HIRAGANA LETTER SMALL I
+ 0x3044: 0x82A2, # HIRAGANA LETTER I
+ 0x3045: 0x82A3, # HIRAGANA LETTER SMALL U
+ 0x3046: 0x82A4, # HIRAGANA LETTER U
+ 0x3047: 0x82A5, # HIRAGANA LETTER SMALL E
+ 0x3048: 0x82A6, # HIRAGANA LETTER E
+ 0x3049: 0x82A7, # HIRAGANA LETTER SMALL O
+ 0x304A: 0x82A8, # HIRAGANA LETTER O
+ 0x304B: 0x82A9, # HIRAGANA LETTER KA
+ 0x304C: 0x82AA, # HIRAGANA LETTER GA
+ 0x304D: 0x82AB, # HIRAGANA LETTER KI
+ 0x304E: 0x82AC, # HIRAGANA LETTER GI
+ 0x304F: 0x82AD, # HIRAGANA LETTER KU
+ 0x3050: 0x82AE, # HIRAGANA LETTER GU
+ 0x3051: 0x82AF, # HIRAGANA LETTER KE
+ 0x3052: 0x82B0, # HIRAGANA LETTER GE
+ 0x3053: 0x82B1, # HIRAGANA LETTER KO
+ 0x3054: 0x82B2, # HIRAGANA LETTER GO
+ 0x3055: 0x82B3, # HIRAGANA LETTER SA
+ 0x3056: 0x82B4, # HIRAGANA LETTER ZA
+ 0x3057: 0x82B5, # HIRAGANA LETTER SI
+ 0x3058: 0x82B6, # HIRAGANA LETTER ZI
+ 0x3059: 0x82B7, # HIRAGANA LETTER SU
+ 0x305A: 0x82B8, # HIRAGANA LETTER ZU
+ 0x305B: 0x82B9, # HIRAGANA LETTER SE
+ 0x305C: 0x82BA, # HIRAGANA LETTER ZE
+ 0x305D: 0x82BB, # HIRAGANA LETTER SO
+ 0x305E: 0x82BC, # HIRAGANA LETTER ZO
+ 0x305F: 0x82BD, # HIRAGANA LETTER TA
+ 0x3060: 0x82BE, # HIRAGANA LETTER DA
+ 0x3061: 0x82BF, # HIRAGANA LETTER TI
+ 0x3062: 0x82C0, # HIRAGANA LETTER DI
+ 0x3063: 0x82C1, # HIRAGANA LETTER SMALL TU
+ 0x3064: 0x82C2, # HIRAGANA LETTER TU
+ 0x3065: 0x82C3, # HIRAGANA LETTER DU
+ 0x3066: 0x82C4, # HIRAGANA LETTER TE
+ 0x3067: 0x82C5, # HIRAGANA LETTER DE
+ 0x3068: 0x82C6, # HIRAGANA LETTER TO
+ 0x3069: 0x82C7, # HIRAGANA LETTER DO
+ 0x306A: 0x82C8, # HIRAGANA LETTER NA
+ 0x306B: 0x82C9, # HIRAGANA LETTER NI
+ 0x306C: 0x82CA, # HIRAGANA LETTER NU
+ 0x306D: 0x82CB, # HIRAGANA LETTER NE
+ 0x306E: 0x82CC, # HIRAGANA LETTER NO
+ 0x306F: 0x82CD, # HIRAGANA LETTER HA
+ 0x3070: 0x82CE, # HIRAGANA LETTER BA
+ 0x3071: 0x82CF, # HIRAGANA LETTER PA
+ 0x3072: 0x82D0, # HIRAGANA LETTER HI
+ 0x3073: 0x82D1, # HIRAGANA LETTER BI
+ 0x3074: 0x82D2, # HIRAGANA LETTER PI
+ 0x3075: 0x82D3, # HIRAGANA LETTER HU
+ 0x3076: 0x82D4, # HIRAGANA LETTER BU
+ 0x3077: 0x82D5, # HIRAGANA LETTER PU
+ 0x3078: 0x82D6, # HIRAGANA LETTER HE
+ 0x3079: 0x82D7, # HIRAGANA LETTER BE
+ 0x307A: 0x82D8, # HIRAGANA LETTER PE
+ 0x307B: 0x82D9, # HIRAGANA LETTER HO
+ 0x307C: 0x82DA, # HIRAGANA LETTER BO
+ 0x307D: 0x82DB, # HIRAGANA LETTER PO
+ 0x307E: 0x82DC, # HIRAGANA LETTER MA
+ 0x307F: 0x82DD, # HIRAGANA LETTER MI
+ 0x3080: 0x82DE, # HIRAGANA LETTER MU
+ 0x3081: 0x82DF, # HIRAGANA LETTER ME
+ 0x3082: 0x82E0, # HIRAGANA LETTER MO
+ 0x3083: 0x82E1, # HIRAGANA LETTER SMALL YA
+ 0x3084: 0x82E2, # HIRAGANA LETTER YA
+ 0x3085: 0x82E3, # HIRAGANA LETTER SMALL YU
+ 0x3086: 0x82E4, # HIRAGANA LETTER YU
+ 0x3087: 0x82E5, # HIRAGANA LETTER SMALL YO
+ 0x3088: 0x82E6, # HIRAGANA LETTER YO
+ 0x3089: 0x82E7, # HIRAGANA LETTER RA
+ 0x308A: 0x82E8, # HIRAGANA LETTER RI
+ 0x308B: 0x82E9, # HIRAGANA LETTER RU
+ 0x308C: 0x82EA, # HIRAGANA LETTER RE
+ 0x308D: 0x82EB, # HIRAGANA LETTER RO
+ 0x308E: 0x82EC, # HIRAGANA LETTER SMALL WA
+ 0x308F: 0x82ED, # HIRAGANA LETTER WA
+ 0x3090: 0x82EE, # HIRAGANA LETTER WI
+ 0x3091: 0x82EF, # HIRAGANA LETTER WE
+ 0x3092: 0x82F0, # HIRAGANA LETTER WO
+ 0x3093: 0x82F1, # HIRAGANA LETTER N
+ 0x3094: 0x82F2, # HIRAGANA LETTER VU [2000]
+ 0x3095: 0x82F3, # HIRAGANA LETTER SMALL KA [2000] [Unicode3.2]
+ 0x3096: 0x82F4, # HIRAGANA LETTER SMALL KE [2000] [Unicode3.2]
+ 0x304B309A: 0x82F5, # [2000]
+ 0x304D309A: 0x82F6, # [2000]
+ 0x304F309A: 0x82F7, # [2000]
+ 0x3051309A: 0x82F8, # [2000]
+ 0x3053309A: 0x82F9, # [2000]
+# 0x82FA -
+# 0x82FB -
+# 0x82FC -
+ 0x30A1: 0x8340, # KATAKANA LETTER SMALL A
+ 0x30A2: 0x8341, # KATAKANA LETTER A
+ 0x30A3: 0x8342, # KATAKANA LETTER SMALL I
+ 0x30A4: 0x8343, # KATAKANA LETTER I
+ 0x30A5: 0x8344, # KATAKANA LETTER SMALL U
+ 0x30A6: 0x8345, # KATAKANA LETTER U
+ 0x30A7: 0x8346, # KATAKANA LETTER SMALL E
+ 0x30A8: 0x8347, # KATAKANA LETTER E
+ 0x30A9: 0x8348, # KATAKANA LETTER SMALL O
+ 0x30AA: 0x8349, # KATAKANA LETTER O
+ 0x30AB: 0x834A, # KATAKANA LETTER KA
+ 0x30AC: 0x834B, # KATAKANA LETTER GA
+ 0x30AD: 0x834C, # KATAKANA LETTER KI
+ 0x30AE: 0x834D, # KATAKANA LETTER GI
+ 0x30AF: 0x834E, # KATAKANA LETTER KU
+ 0x30B0: 0x834F, # KATAKANA LETTER GU
+ 0x30B1: 0x8350, # KATAKANA LETTER KE
+ 0x30B2: 0x8351, # KATAKANA LETTER GE
+ 0x30B3: 0x8352, # KATAKANA LETTER KO
+ 0x30B4: 0x8353, # KATAKANA LETTER GO
+ 0x30B5: 0x8354, # KATAKANA LETTER SA
+ 0x30B6: 0x8355, # KATAKANA LETTER ZA
+ 0x30B7: 0x8356, # KATAKANA LETTER SI
+ 0x30B8: 0x8357, # KATAKANA LETTER ZI
+ 0x30B9: 0x8358, # KATAKANA LETTER SU
+ 0x30BA: 0x8359, # KATAKANA LETTER ZU
+ 0x30BB: 0x835A, # KATAKANA LETTER SE
+ 0x30BC: 0x835B, # KATAKANA LETTER ZE
+ 0x30BD: 0x835C, # KATAKANA LETTER SO
+ 0x30BE: 0x835D, # KATAKANA LETTER ZO
+ 0x30BF: 0x835E, # KATAKANA LETTER TA
+ 0x30C0: 0x835F, # KATAKANA LETTER DA
+ 0x30C1: 0x8360, # KATAKANA LETTER TI
+ 0x30C2: 0x8361, # KATAKANA LETTER DI
+ 0x30C3: 0x8362, # KATAKANA LETTER SMALL TU
+ 0x30C4: 0x8363, # KATAKANA LETTER TU
+ 0x30C5: 0x8364, # KATAKANA LETTER DU
+ 0x30C6: 0x8365, # KATAKANA LETTER TE
+ 0x30C7: 0x8366, # KATAKANA LETTER DE
+ 0x30C8: 0x8367, # KATAKANA LETTER TO
+ 0x30C9: 0x8368, # KATAKANA LETTER DO
+ 0x30CA: 0x8369, # KATAKANA LETTER NA
+ 0x30CB: 0x836A, # KATAKANA LETTER NI
+ 0x30CC: 0x836B, # KATAKANA LETTER NU
+ 0x30CD: 0x836C, # KATAKANA LETTER NE
+ 0x30CE: 0x836D, # KATAKANA LETTER NO
+ 0x30CF: 0x836E, # KATAKANA LETTER HA
+ 0x30D0: 0x836F, # KATAKANA LETTER BA
+ 0x30D1: 0x8370, # KATAKANA LETTER PA
+ 0x30D2: 0x8371, # KATAKANA LETTER HI
+ 0x30D3: 0x8372, # KATAKANA LETTER BI
+ 0x30D4: 0x8373, # KATAKANA LETTER PI
+ 0x30D5: 0x8374, # KATAKANA LETTER HU
+ 0x30D6: 0x8375, # KATAKANA LETTER BU
+ 0x30D7: 0x8376, # KATAKANA LETTER PU
+ 0x30D8: 0x8377, # KATAKANA LETTER HE
+ 0x30D9: 0x8378, # KATAKANA LETTER BE
+ 0x30DA: 0x8379, # KATAKANA LETTER PE
+ 0x30DB: 0x837A, # KATAKANA LETTER HO
+ 0x30DC: 0x837B, # KATAKANA LETTER BO
+ 0x30DD: 0x837C, # KATAKANA LETTER PO
+ 0x30DE: 0x837D, # KATAKANA LETTER MA
+ 0x30DF: 0x837E, # KATAKANA LETTER MI
+ 0x30E0: 0x8380, # KATAKANA LETTER MU
+ 0x30E1: 0x8381, # KATAKANA LETTER ME
+ 0x30E2: 0x8382, # KATAKANA LETTER MO
+ 0x30E3: 0x8383, # KATAKANA LETTER SMALL YA
+ 0x30E4: 0x8384, # KATAKANA LETTER YA
+ 0x30E5: 0x8385, # KATAKANA LETTER SMALL YU
+ 0x30E6: 0x8386, # KATAKANA LETTER YU
+ 0x30E7: 0x8387, # KATAKANA LETTER SMALL YO
+ 0x30E8: 0x8388, # KATAKANA LETTER YO
+ 0x30E9: 0x8389, # KATAKANA LETTER RA
+ 0x30EA: 0x838A, # KATAKANA LETTER RI
+ 0x30EB: 0x838B, # KATAKANA LETTER RU
+ 0x30EC: 0x838C, # KATAKANA LETTER RE
+ 0x30ED: 0x838D, # KATAKANA LETTER RO
+ 0x30EE: 0x838E, # KATAKANA LETTER SMALL WA
+ 0x30EF: 0x838F, # KATAKANA LETTER WA
+ 0x30F0: 0x8390, # KATAKANA LETTER WI
+ 0x30F1: 0x8391, # KATAKANA LETTER WE
+ 0x30F2: 0x8392, # KATAKANA LETTER WO
+ 0x30F3: 0x8393, # KATAKANA LETTER N
+ 0x30F4: 0x8394, # KATAKANA LETTER VU
+ 0x30F5: 0x8395, # KATAKANA LETTER SMALL KA
+ 0x30F6: 0x8396, # KATAKANA LETTER SMALL KE
+ 0x30AB309A: 0x8397, # [2000]
+ 0x30AD309A: 0x8398, # [2000]
+ 0x30AF309A: 0x8399, # [2000]
+ 0x30B1309A: 0x839A, # [2000]
+ 0x30B3309A: 0x839B, # [2000]
+ 0x30BB309A: 0x839C, # [2000]
+ 0x30C4309A: 0x839D, # [2000]
+ 0x30C8309A: 0x839E, # [2000]
+ 0x0391: 0x839F, # GREEK CAPITAL LETTER ALPHA
+ 0x0392: 0x83A0, # GREEK CAPITAL LETTER BETA
+ 0x0393: 0x83A1, # GREEK CAPITAL LETTER GAMMA
+ 0x0394: 0x83A2, # GREEK CAPITAL LETTER DELTA
+ 0x0395: 0x83A3, # GREEK CAPITAL LETTER EPSILON
+ 0x0396: 0x83A4, # GREEK CAPITAL LETTER ZETA
+ 0x0397: 0x83A5, # GREEK CAPITAL LETTER ETA
+ 0x0398: 0x83A6, # GREEK CAPITAL LETTER THETA
+ 0x0399: 0x83A7, # GREEK CAPITAL LETTER IOTA
+ 0x039A: 0x83A8, # GREEK CAPITAL LETTER KAPPA
+ 0x039B: 0x83A9, # GREEK CAPITAL LETTER LAMDA
+ 0x039C: 0x83AA, # GREEK CAPITAL LETTER MU
+ 0x039D: 0x83AB, # GREEK CAPITAL LETTER NU
+ 0x039E: 0x83AC, # GREEK CAPITAL LETTER XI
+ 0x039F: 0x83AD, # GREEK CAPITAL LETTER OMICRON
+ 0x03A0: 0x83AE, # GREEK CAPITAL LETTER PI
+ 0x03A1: 0x83AF, # GREEK CAPITAL LETTER RHO
+ 0x03A3: 0x83B0, # GREEK CAPITAL LETTER SIGMA
+ 0x03A4: 0x83B1, # GREEK CAPITAL LETTER TAU
+ 0x03A5: 0x83B2, # GREEK CAPITAL LETTER UPSILON
+ 0x03A6: 0x83B3, # GREEK CAPITAL LETTER PHI
+ 0x03A7: 0x83B4, # GREEK CAPITAL LETTER CHI
+ 0x03A8: 0x83B5, # GREEK CAPITAL LETTER PSI
+ 0x03A9: 0x83B6, # GREEK CAPITAL LETTER OMEGA
+ 0x2664: 0x83B7, # WHITE SPADE SUIT [2000]
+ 0x2660: 0x83B8, # BLACK SPADE SUIT [2000]
+ 0x2662: 0x83B9, # WHITE DIAMOND SUIT [2000]
+ 0x2666: 0x83BA, # BLACK DIAMOND SUIT [2000]
+ 0x2661: 0x83BB, # WHITE HEART SUIT [2000]
+ 0x2665: 0x83BC, # BLACK HEART SUIT [2000]
+ 0x2667: 0x83BD, # WHITE CLUB SUIT [2000]
+ 0x2663: 0x83BE, # BLACK CLUB SUIT [2000]
+ 0x03B1: 0x83BF, # GREEK SMALL LETTER ALPHA
+ 0x03B2: 0x83C0, # GREEK SMALL LETTER BETA
+ 0x03B3: 0x83C1, # GREEK SMALL LETTER GAMMA
+ 0x03B4: 0x83C2, # GREEK SMALL LETTER DELTA
+ 0x03B5: 0x83C3, # GREEK SMALL LETTER EPSILON
+ 0x03B6: 0x83C4, # GREEK SMALL LETTER ZETA
+ 0x03B7: 0x83C5, # GREEK SMALL LETTER ETA
+ 0x03B8: 0x83C6, # GREEK SMALL LETTER THETA
+ 0x03B9: 0x83C7, # GREEK SMALL LETTER IOTA
+ 0x03BA: 0x83C8, # GREEK SMALL LETTER KAPPA
+ 0x03BB: 0x83C9, # GREEK SMALL LETTER LAMDA
+ 0x03BC: 0x83CA, # GREEK SMALL LETTER MU
+ 0x03BD: 0x83CB, # GREEK SMALL LETTER NU
+ 0x03BE: 0x83CC, # GREEK SMALL LETTER XI
+ 0x03BF: 0x83CD, # GREEK SMALL LETTER OMICRON
+ 0x03C0: 0x83CE, # GREEK SMALL LETTER PI
+ 0x03C1: 0x83CF, # GREEK SMALL LETTER RHO
+ 0x03C3: 0x83D0, # GREEK SMALL LETTER SIGMA
+ 0x03C4: 0x83D1, # GREEK SMALL LETTER TAU
+ 0x03C5: 0x83D2, # GREEK SMALL LETTER UPSILON
+ 0x03C6: 0x83D3, # GREEK SMALL LETTER PHI
+ 0x03C7: 0x83D4, # GREEK SMALL LETTER CHI
+ 0x03C8: 0x83D5, # GREEK SMALL LETTER PSI
+ 0x03C9: 0x83D6, # GREEK SMALL LETTER OMEGA
+ 0x03C2: 0x83D7, # GREEK SMALL LETTER FINAL SIGMA [2000]
+ 0x24F5: 0x83D8, # DOUBLE CIRCLED DIGIT ONE [2000] [Unicode3.2]
+ 0x24F6: 0x83D9, # DOUBLE CIRCLED DIGIT TWO [2000] [Unicode3.2]
+ 0x24F7: 0x83DA, # DOUBLE CIRCLED DIGIT THREE [2000] [Unicode3.2]
+ 0x24F8: 0x83DB, # DOUBLE CIRCLED DIGIT FOUR [2000] [Unicode3.2]
+ 0x24F9: 0x83DC, # DOUBLE CIRCLED DIGIT FIVE [2000] [Unicode3.2]
+ 0x24FA: 0x83DD, # DOUBLE CIRCLED DIGIT SIX [2000] [Unicode3.2]
+ 0x24FB: 0x83DE, # DOUBLE CIRCLED DIGIT SEVEN [2000] [Unicode3.2]
+ 0x24FC: 0x83DF, # DOUBLE CIRCLED DIGIT EIGHT [2000] [Unicode3.2]
+ 0x24FD: 0x83E0, # DOUBLE CIRCLED DIGIT NINE [2000] [Unicode3.2]
+ 0x24FE: 0x83E1, # DOUBLE CIRCLED NUMBER TEN [2000] [Unicode3.2]
+ 0x2616: 0x83E2, # WHITE SHOGI PIECE [2000] [Unicode3.2]
+ 0x2617: 0x83E3, # BLACK SHOGI PIECE [2000] [Unicode3.2]
+ 0x3020: 0x83E4, # POSTAL MARK FACE [2000]
+ 0x260E: 0x83E5, # BLACK TELEPHONE [2000]
+ 0x2600: 0x83E6, # BLACK SUN WITH RAYS [2000]
+ 0x2601: 0x83E7, # CLOUD [2000]
+ 0x2602: 0x83E8, # UMBRELLA [2000]
+ 0x2603: 0x83E9, # SNOWMAN [2000]
+ 0x2668: 0x83EA, # HOT SPRINGS [2000]
+ 0x25B1: 0x83EB, # WHITE PARALLELOGRAM [2000]
+ 0x31F0: 0x83EC, # KATAKANA LETTER SMALL KU [2000] [Unicode3.2]
+ 0x31F1: 0x83ED, # KATAKANA LETTER SMALL SI [2000] [Unicode3.2]
+ 0x31F2: 0x83EE, # KATAKANA LETTER SMALL SU [2000] [Unicode3.2]
+ 0x31F3: 0x83EF, # KATAKANA LETTER SMALL TO [2000] [Unicode3.2]
+ 0x31F4: 0x83F0, # KATAKANA LETTER SMALL NU [2000] [Unicode3.2]
+ 0x31F5: 0x83F1, # KATAKANA LETTER SMALL HA [2000] [Unicode3.2]
+ 0x31F6: 0x83F2, # KATAKANA LETTER SMALL HI [2000] [Unicode3.2]
+ 0x31F7: 0x83F3, # KATAKANA LETTER SMALL HU [2000] [Unicode3.2]
+ 0x31F8: 0x83F4, # KATAKANA LETTER SMALL HE [2000] [Unicode3.2]
+ 0x31F9: 0x83F5, # KATAKANA LETTER SMALL HO [2000] [Unicode3.2]
+ 0x31F7309A: 0x83F6, # [2000]
+ 0x31FA: 0x83F7, # KATAKANA LETTER SMALL MU [2000] [Unicode3.2]
+ 0x31FB: 0x83F8, # KATAKANA LETTER SMALL RA [2000] [Unicode3.2]
+ 0x31FC: 0x83F9, # KATAKANA LETTER SMALL RI [2000] [Unicode3.2]
+ 0x31FD: 0x83FA, # KATAKANA LETTER SMALL RU [2000] [Unicode3.2]
+ 0x31FE: 0x83FB, # KATAKANA LETTER SMALL RE [2000] [Unicode3.2]
+ 0x31FF: 0x83FC, # KATAKANA LETTER SMALL RO [2000] [Unicode3.2]
+ 0x0410: 0x8440, # CYRILLIC CAPITAL LETTER A
+ 0x0411: 0x8441, # CYRILLIC CAPITAL LETTER BE
+ 0x0412: 0x8442, # CYRILLIC CAPITAL LETTER VE
+ 0x0413: 0x8443, # CYRILLIC CAPITAL LETTER GHE
+ 0x0414: 0x8444, # CYRILLIC CAPITAL LETTER DE
+ 0x0415: 0x8445, # CYRILLIC CAPITAL LETTER IE
+ 0x0401: 0x8446, # CYRILLIC CAPITAL LETTER IO
+ 0x0416: 0x8447, # CYRILLIC CAPITAL LETTER ZHE
+ 0x0417: 0x8448, # CYRILLIC CAPITAL LETTER ZE
+ 0x0418: 0x8449, # CYRILLIC CAPITAL LETTER I
+ 0x0419: 0x844A, # CYRILLIC CAPITAL LETTER SHORT I
+ 0x041A: 0x844B, # CYRILLIC CAPITAL LETTER KA
+ 0x041B: 0x844C, # CYRILLIC CAPITAL LETTER EL
+ 0x041C: 0x844D, # CYRILLIC CAPITAL LETTER EM
+ 0x041D: 0x844E, # CYRILLIC CAPITAL LETTER EN
+ 0x041E: 0x844F, # CYRILLIC CAPITAL LETTER O
+ 0x041F: 0x8450, # CYRILLIC CAPITAL LETTER PE
+ 0x0420: 0x8451, # CYRILLIC CAPITAL LETTER ER
+ 0x0421: 0x8452, # CYRILLIC CAPITAL LETTER ES
+ 0x0422: 0x8453, # CYRILLIC CAPITAL LETTER TE
+ 0x0423: 0x8454, # CYRILLIC CAPITAL LETTER U
+ 0x0424: 0x8455, # CYRILLIC CAPITAL LETTER EF
+ 0x0425: 0x8456, # CYRILLIC CAPITAL LETTER HA
+ 0x0426: 0x8457, # CYRILLIC CAPITAL LETTER TSE
+ 0x0427: 0x8458, # CYRILLIC CAPITAL LETTER CHE
+ 0x0428: 0x8459, # CYRILLIC CAPITAL LETTER SHA
+ 0x0429: 0x845A, # CYRILLIC CAPITAL LETTER SHCHA
+ 0x042A: 0x845B, # CYRILLIC CAPITAL LETTER HARD SIGN
+ 0x042B: 0x845C, # CYRILLIC CAPITAL LETTER YERU
+ 0x042C: 0x845D, # CYRILLIC CAPITAL LETTER SOFT SIGN
+ 0x042D: 0x845E, # CYRILLIC CAPITAL LETTER E
+ 0x042E: 0x845F, # CYRILLIC CAPITAL LETTER YU
+ 0x042F: 0x8460, # CYRILLIC CAPITAL LETTER YA
+ 0x23BE: 0x8461, # DENTISTRY SYMBOL LIGHT VERTICAL AND TOP RIGHT [2000] [Unicode3.2]
+ 0x23BF: 0x8462, # DENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM RIGHT [2000] [Unicode3.2]
+ 0x23C0: 0x8463, # DENTISTRY SYMBOL LIGHT VERTICAL WITH CIRCLE [2000] [Unicode3.2]
+ 0x23C1: 0x8464, # DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH CIRCLE [2000] [Unicode3.2]
+ 0x23C2: 0x8465, # DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH CIRCLE [2000] [Unicode3.2]
+ 0x23C3: 0x8466, # DENTISTRY SYMBOL LIGHT VERTICAL WITH TRIANGLE [2000] [Unicode3.2]
+ 0x23C4: 0x8467, # DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH TRIANGLE [2000] [Unicode3.2]
+ 0x23C5: 0x8468, # DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH TRIANGLE [2000] [Unicode3.2]
+ 0x23C6: 0x8469, # DENTISTRY SYMBOL LIGHT VERTICAL AND WAVE [2000] [Unicode3.2]
+ 0x23C7: 0x846A, # DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH WAVE [2000] [Unicode3.2]
+ 0x23C8: 0x846B, # DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH WAVE [2000] [Unicode3.2]
+ 0x23C9: 0x846C, # DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL [2000] [Unicode3.2]
+ 0x23CA: 0x846D, # DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL [2000] [Unicode3.2]
+ 0x23CB: 0x846E, # DENTISTRY SYMBOL LIGHT VERTICAL AND TOP LEFT [2000] [Unicode3.2]
+ 0x23CC: 0x846F, # DENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM LEFT [2000] [Unicode3.2]
+ 0x0430: 0x8470, # CYRILLIC SMALL LETTER A
+ 0x0431: 0x8471, # CYRILLIC SMALL LETTER BE
+ 0x0432: 0x8472, # CYRILLIC SMALL LETTER VE
+ 0x0433: 0x8473, # CYRILLIC SMALL LETTER GHE
+ 0x0434: 0x8474, # CYRILLIC SMALL LETTER DE
+ 0x0435: 0x8475, # CYRILLIC SMALL LETTER IE
+ 0x0451: 0x8476, # CYRILLIC SMALL LETTER IO
+ 0x0436: 0x8477, # CYRILLIC SMALL LETTER ZHE
+ 0x0437: 0x8478, # CYRILLIC SMALL LETTER ZE
+ 0x0438: 0x8479, # CYRILLIC SMALL LETTER I
+ 0x0439: 0x847A, # CYRILLIC SMALL LETTER SHORT I
+ 0x043A: 0x847B, # CYRILLIC SMALL LETTER KA
+ 0x043B: 0x847C, # CYRILLIC SMALL LETTER EL
+ 0x043C: 0x847D, # CYRILLIC SMALL LETTER EM
+ 0x043D: 0x847E, # CYRILLIC SMALL LETTER EN
+ 0x043E: 0x8480, # CYRILLIC SMALL LETTER O
+ 0x043F: 0x8481, # CYRILLIC SMALL LETTER PE
+ 0x0440: 0x8482, # CYRILLIC SMALL LETTER ER
+ 0x0441: 0x8483, # CYRILLIC SMALL LETTER ES
+ 0x0442: 0x8484, # CYRILLIC SMALL LETTER TE
+ 0x0443: 0x8485, # CYRILLIC SMALL LETTER U
+ 0x0444: 0x8486, # CYRILLIC SMALL LETTER EF
+ 0x0445: 0x8487, # CYRILLIC SMALL LETTER HA
+ 0x0446: 0x8488, # CYRILLIC SMALL LETTER TSE
+ 0x0447: 0x8489, # CYRILLIC SMALL LETTER CHE
+ 0x0448: 0x848A, # CYRILLIC SMALL LETTER SHA
+ 0x0449: 0x848B, # CYRILLIC SMALL LETTER SHCHA
+ 0x044A: 0x848C, # CYRILLIC SMALL LETTER HARD SIGN
+ 0x044B: 0x848D, # CYRILLIC SMALL LETTER YERU
+ 0x044C: 0x848E, # CYRILLIC SMALL LETTER SOFT SIGN
+ 0x044D: 0x848F, # CYRILLIC SMALL LETTER E
+ 0x044E: 0x8490, # CYRILLIC SMALL LETTER YU
+ 0x044F: 0x8491, # CYRILLIC SMALL LETTER YA
+ 0x30F7: 0x8492, # KATAKANA LETTER VA [2000]
+ 0x30F8: 0x8493, # KATAKANA LETTER VI [2000]
+ 0x30F9: 0x8494, # KATAKANA LETTER VE [2000]
+ 0x30FA: 0x8495, # KATAKANA LETTER VO [2000]
+ 0x22DA: 0x8496, # LESS-THAN EQUAL TO OR GREATER-THAN [2000]
+ 0x22DB: 0x8497, # GREATER-THAN EQUAL TO OR LESS-THAN [2000]
+ 0x2153: 0x8498, # VULGAR FRACTION ONE THIRD [2000]
+ 0x2154: 0x8499, # VULGAR FRACTION TWO THIRDS [2000]
+ 0x2155: 0x849A, # VULGAR FRACTION ONE FIFTH [2000]
+ 0x2713: 0x849B, # CHECK MARK [2000]
+ 0x2318: 0x849C, # PLACE OF INTEREST SIGN [2000]
+ 0x2423: 0x849D, # OPEN BOX [2000]
+ 0x23CE: 0x849E, # RETURN SYMBOL [2000] [Unicode3.2]
+ 0x2500: 0x849F, # BOX DRAWINGS LIGHT HORIZONTAL [1983]
+ 0x2502: 0x84A0, # BOX DRAWINGS LIGHT VERTICAL [1983]
+ 0x250C: 0x84A1, # BOX DRAWINGS LIGHT DOWN AND RIGHT [1983]
+ 0x2510: 0x84A2, # BOX DRAWINGS LIGHT DOWN AND LEFT [1983]
+ 0x2518: 0x84A3, # BOX DRAWINGS LIGHT UP AND LEFT [1983]
+ 0x2514: 0x84A4, # BOX DRAWINGS LIGHT UP AND RIGHT [1983]
+ 0x251C: 0x84A5, # BOX DRAWINGS LIGHT VERTICAL AND RIGHT [1983]
+ 0x252C: 0x84A6, # BOX DRAWINGS LIGHT DOWN AND HORIZONTAL [1983]
+ 0x2524: 0x84A7, # BOX DRAWINGS LIGHT VERTICAL AND LEFT [1983]
+ 0x2534: 0x84A8, # BOX DRAWINGS LIGHT UP AND HORIZONTAL [1983]
+ 0x253C: 0x84A9, # BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL [1983]
+ 0x2501: 0x84AA, # BOX DRAWINGS HEAVY HORIZONTAL [1983]
+ 0x2503: 0x84AB, # BOX DRAWINGS HEAVY VERTICAL [1983]
+ 0x250F: 0x84AC, # BOX DRAWINGS HEAVY DOWN AND RIGHT [1983]
+ 0x2513: 0x84AD, # BOX DRAWINGS HEAVY DOWN AND LEFT [1983]
+ 0x251B: 0x84AE, # BOX DRAWINGS HEAVY UP AND LEFT [1983]
+ 0x2517: 0x84AF, # BOX DRAWINGS HEAVY UP AND RIGHT [1983]
+ 0x2523: 0x84B0, # BOX DRAWINGS HEAVY VERTICAL AND RIGHT [1983]
+ 0x2533: 0x84B1, # BOX DRAWINGS HEAVY DOWN AND HORIZONTAL [1983]
+ 0x252B: 0x84B2, # BOX DRAWINGS HEAVY VERTICAL AND LEFT [1983]
+ 0x253B: 0x84B3, # BOX DRAWINGS HEAVY UP AND HORIZONTAL [1983]
+ 0x254B: 0x84B4, # BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL [1983]
+ 0x2520: 0x84B5, # BOX DRAWINGS VERTICAL HEAVY AND RIGHT LIGHT [1983]
+ 0x252F: 0x84B6, # BOX DRAWINGS DOWN LIGHT AND HORIZONTAL HEAVY [1983]
+ 0x2528: 0x84B7, # BOX DRAWINGS VERTICAL HEAVY AND LEFT LIGHT [1983]
+ 0x2537: 0x84B8, # BOX DRAWINGS UP LIGHT AND HORIZONTAL HEAVY [1983]
+ 0x253F: 0x84B9, # BOX DRAWINGS VERTICAL LIGHT AND HORIZONTAL HEAVY [1983]
+ 0x251D: 0x84BA, # BOX DRAWINGS VERTICAL LIGHT AND RIGHT HEAVY [1983]
+ 0x2530: 0x84BB, # BOX DRAWINGS DOWN HEAVY AND HORIZONTAL LIGHT [1983]
+ 0x2525: 0x84BC, # BOX DRAWINGS VERTICAL LIGHT AND LEFT HEAVY [1983]
+ 0x2538: 0x84BD, # BOX DRAWINGS UP HEAVY AND HORIZONTAL LIGHT [1983]
+ 0x2542: 0x84BE, # BOX DRAWINGS VERTICAL HEAVY AND HORIZONTAL LIGHT [1983]
+ 0x3251: 0x84BF, # CIRCLED NUMBER TWENTY ONE [2000] [Unicode3.2]
+ 0x3252: 0x84C0, # CIRCLED NUMBER TWENTY TWO [2000] [Unicode3.2]
+ 0x3253: 0x84C1, # CIRCLED NUMBER TWENTY THREE [2000] [Unicode3.2]
+ 0x3254: 0x84C2, # CIRCLED NUMBER TWENTY FOUR [2000] [Unicode3.2]
+ 0x3255: 0x84C3, # CIRCLED NUMBER TWENTY FIVE [2000] [Unicode3.2]
+ 0x3256: 0x84C4, # CIRCLED NUMBER TWENTY SIX [2000] [Unicode3.2]
+ 0x3257: 0x84C5, # CIRCLED NUMBER TWENTY SEVEN [2000] [Unicode3.2]
+ 0x3258: 0x84C6, # CIRCLED NUMBER TWENTY EIGHT [2000] [Unicode3.2]
+ 0x3259: 0x84C7, # CIRCLED NUMBER TWENTY NINE [2000] [Unicode3.2]
+ 0x325A: 0x84C8, # CIRCLED NUMBER THIRTY [2000] [Unicode3.2]
+ 0x325B: 0x84C9, # CIRCLED NUMBER THIRTY ONE [2000] [Unicode3.2]
+ 0x325C: 0x84CA, # CIRCLED NUMBER THIRTY TWO [2000] [Unicode3.2]
+ 0x325D: 0x84CB, # CIRCLED NUMBER THIRTY THREE [2000] [Unicode3.2]
+ 0x325E: 0x84CC, # CIRCLED NUMBER THIRTY FOUR [2000] [Unicode3.2]
+ 0x325F: 0x84CD, # CIRCLED NUMBER THIRTY FIVE [2000] [Unicode3.2]
+ 0x32B1: 0x84CE, # CIRCLED NUMBER THIRTY SIX [2000] [Unicode3.2]
+ 0x32B2: 0x84CF, # CIRCLED NUMBER THIRTY SEVEN [2000] [Unicode3.2]
+ 0x32B3: 0x84D0, # CIRCLED NUMBER THIRTY EIGHT [2000] [Unicode3.2]
+ 0x32B4: 0x84D1, # CIRCLED NUMBER THIRTY NINE [2000] [Unicode3.2]
+ 0x32B5: 0x84D2, # CIRCLED NUMBER FORTY [2000] [Unicode3.2]
+ 0x32B6: 0x84D3, # CIRCLED NUMBER FORTY ONE [2000] [Unicode3.2]
+ 0x32B7: 0x84D4, # CIRCLED NUMBER FORTY TWO [2000] [Unicode3.2]
+ 0x32B8: 0x84D5, # CIRCLED NUMBER FORTY THREE [2000] [Unicode3.2]
+ 0x32B9: 0x84D6, # CIRCLED NUMBER FORTY FOUR [2000] [Unicode3.2]
+ 0x32BA: 0x84D7, # CIRCLED NUMBER FORTY FIVE [2000] [Unicode3.2]
+ 0x32BB: 0x84D8, # CIRCLED NUMBER FORTY SIX [2000] [Unicode3.2]
+ 0x32BC: 0x84D9, # CIRCLED NUMBER FORTY SEVEN [2000] [Unicode3.2]
+ 0x32BD: 0x84DA, # CIRCLED NUMBER FORTY EIGHT [2000] [Unicode3.2]
+ 0x32BE: 0x84DB, # CIRCLED NUMBER FORTY NINE [2000] [Unicode3.2]
+ 0x32BF: 0x84DC, # CIRCLED NUMBER FIFTY [2000] [Unicode3.2]
+# 0x84DD -
+# 0x84DE -
+# 0x84DF -
+# 0x84E0 -
+# 0x84E1 -
+# 0x84E2 -
+# 0x84E3 -
+# 0x84E4 -
+ 0x25D0: 0x84E5, # CIRCLE WITH LEFT HALF BLACK [2000]
+ 0x25D1: 0x84E6, # CIRCLE WITH RIGHT HALF BLACK [2000]
+ 0x25D2: 0x84E7, # CIRCLE WITH LOWER HALF BLACK [2000]
+ 0x25D3: 0x84E8, # CIRCLE WITH UPPER HALF BLACK [2000]
+ 0x203C: 0x84E9, # DOUBLE EXCLAMATION MARK [2000]
+ 0x2047: 0x84EA, # DOUBLE QUESTION MARK [2000] [Unicode3.2]
+ 0x2048: 0x84EB, # QUESTION EXCLAMATION MARK [2000]
+ 0x2049: 0x84EC, # EXCLAMATION QUESTION MARK [2000]
+ 0x01CD: 0x84ED, # LATIN CAPITAL LETTER A WITH CARON [2000]
+ 0x01CE: 0x84EE, # LATIN SMALL LETTER A WITH CARON [2000]
+ 0x01D0: 0x84EF, # LATIN SMALL LETTER I WITH CARON [2000]
+ 0x1E3E: 0x84F0, # LATIN CAPITAL LETTER M WITH ACUTE [2000]
+ 0x1E3F: 0x84F1, # LATIN SMALL LETTER M WITH ACUTE [2000]
+ 0x01F8: 0x84F2, # LATIN CAPITAL LETTER N WITH GRAVE [2000]
+ 0x01F9: 0x84F3, # LATIN SMALL LETTER N WITH GRAVE [2000]
+ 0x01D1: 0x84F4, # LATIN CAPITAL LETTER O WITH CARON [2000]
+ 0x01D2: 0x84F5, # LATIN SMALL LETTER O WITH CARON [2000]
+ 0x01D4: 0x84F6, # LATIN SMALL LETTER U WITH CARON [2000]
+ 0x01D6: 0x84F7, # LATIN SMALL LETTER U WITH DIAERESIS AND MACRON [2000]
+ 0x01D8: 0x84F8, # LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE [2000]
+ 0x01DA: 0x84F9, # LATIN SMALL LETTER U WITH DIAERESIS AND CARON [2000]
+ 0x01DC: 0x84FA, # LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE [2000]
+# 0x84FB -
+# 0x84FC -
+ 0x20AC: 0x8540, # EURO SIGN [2000]
+ 0x00A0: 0x8541, # NO-BREAK SPACE [2000]
+ 0x00A1: 0x8542, # INVERTED EXCLAMATION MARK [2000]
+ 0x00A4: 0x8543, # CURRENCY SIGN [2000]
+ 0x00A6: 0x8544, # BROKEN BAR [2000]
+ 0x00A9: 0x8545, # COPYRIGHT SIGN [2000]
+ 0x00AA: 0x8546, # FEMININE ORDINAL INDICATOR [2000]
+ 0x00AB: 0x8547, # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK [2000]
+ 0x00AD: 0x8548, # SOFT HYPHEN [2000]
+ 0x00AE: 0x8549, # REGISTERED SIGN [2000]
+ 0x00AF: 0x854A, # MACRON [2000]
+ 0x00B2: 0x854B, # SUPERSCRIPT TWO [2000]
+ 0x00B3: 0x854C, # SUPERSCRIPT THREE [2000]
+ 0x00B7: 0x854D, # MIDDLE DOT [2000]
+ 0x00B8: 0x854E, # CEDILLA [2000]
+ 0x00B9: 0x854F, # SUPERSCRIPT ONE [2000]
+ 0x00BA: 0x8550, # MASCULINE ORDINAL INDICATOR [2000]
+ 0x00BB: 0x8551, # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK [2000]
+ 0x00BC: 0x8552, # VULGAR FRACTION ONE QUARTER [2000]
+ 0x00BD: 0x8553, # VULGAR FRACTION ONE HALF [2000]
+ 0x00BE: 0x8554, # VULGAR FRACTION THREE QUARTERS [2000]
+ 0x00BF: 0x8555, # INVERTED QUESTION MARK [2000]
+ 0x00C0: 0x8556, # LATIN CAPITAL LETTER A WITH GRAVE [2000]
+ 0x00C1: 0x8557, # LATIN CAPITAL LETTER A WITH ACUTE [2000]
+ 0x00C2: 0x8558, # LATIN CAPITAL LETTER A WITH CIRCUMFLEX [2000]
+ 0x00C3: 0x8559, # LATIN CAPITAL LETTER A WITH TILDE [2000]
+ 0x00C4: 0x855A, # LATIN CAPITAL LETTER A WITH DIAERESIS [2000]
+ 0x00C5: 0x855B, # LATIN CAPITAL LETTER A WITH RING ABOVE [2000]
+ 0x00C6: 0x855C, # LATIN CAPITAL LETTER AE [2000]
+ 0x00C7: 0x855D, # LATIN CAPITAL LETTER C WITH CEDILLA [2000]
+ 0x00C8: 0x855E, # LATIN CAPITAL LETTER E WITH GRAVE [2000]
+ 0x00C9: 0x855F, # LATIN CAPITAL LETTER E WITH ACUTE [2000]
+ 0x00CA: 0x8560, # LATIN CAPITAL LETTER E WITH CIRCUMFLEX [2000]
+ 0x00CB: 0x8561, # LATIN CAPITAL LETTER E WITH DIAERESIS [2000]
+ 0x00CC: 0x8562, # LATIN CAPITAL LETTER I WITH GRAVE [2000]
+ 0x00CD: 0x8563, # LATIN CAPITAL LETTER I WITH ACUTE [2000]
+ 0x00CE: 0x8564, # LATIN CAPITAL LETTER I WITH CIRCUMFLEX [2000]
+ 0x00CF: 0x8565, # LATIN CAPITAL LETTER I WITH DIAERESIS [2000]
+ 0x00D0: 0x8566, # LATIN CAPITAL LETTER ETH [2000]
+ 0x00D1: 0x8567, # LATIN CAPITAL LETTER N WITH TILDE [2000]
+ 0x00D2: 0x8568, # LATIN CAPITAL LETTER O WITH GRAVE [2000]
+ 0x00D3: 0x8569, # LATIN CAPITAL LETTER O WITH ACUTE [2000]
+ 0x00D4: 0x856A, # LATIN CAPITAL LETTER O WITH CIRCUMFLEX [2000]
+ 0x00D5: 0x856B, # LATIN CAPITAL LETTER O WITH TILDE [2000]
+ 0x00D6: 0x856C, # LATIN CAPITAL LETTER O WITH DIAERESIS [2000]
+ 0x00D8: 0x856D, # LATIN CAPITAL LETTER O WITH STROKE [2000]
+ 0x00D9: 0x856E, # LATIN CAPITAL LETTER U WITH GRAVE [2000]
+ 0x00DA: 0x856F, # LATIN CAPITAL LETTER U WITH ACUTE [2000]
+ 0x00DB: 0x8570, # LATIN CAPITAL LETTER U WITH CIRCUMFLEX [2000]
+ 0x00DC: 0x8571, # LATIN CAPITAL LETTER U WITH DIAERESIS [2000]
+ 0x00DD: 0x8572, # LATIN CAPITAL LETTER Y WITH ACUTE [2000]
+ 0x00DE: 0x8573, # LATIN CAPITAL LETTER THORN [2000]
+ 0x00DF: 0x8574, # LATIN SMALL LETTER SHARP S [2000]
+ 0x00E0: 0x8575, # LATIN SMALL LETTER A WITH GRAVE [2000]
+ 0x00E1: 0x8576, # LATIN SMALL LETTER A WITH ACUTE [2000]
+ 0x00E2: 0x8577, # LATIN SMALL LETTER A WITH CIRCUMFLEX [2000]
+ 0x00E3: 0x8578, # LATIN SMALL LETTER A WITH TILDE [2000]
+ 0x00E4: 0x8579, # LATIN SMALL LETTER A WITH DIAERESIS [2000]
+ 0x00E5: 0x857A, # LATIN SMALL LETTER A WITH RING ABOVE [2000]
+ 0x00E6: 0x857B, # LATIN SMALL LETTER AE [2000]
+ 0x00E7: 0x857C, # LATIN SMALL LETTER C WITH CEDILLA [2000]
+ 0x00E8: 0x857D, # LATIN SMALL LETTER E WITH GRAVE [2000]
+ 0x00E9: 0x857E, # LATIN SMALL LETTER E WITH ACUTE [2000]
+ 0x00EA: 0x8580, # LATIN SMALL LETTER E WITH CIRCUMFLEX [2000]
+ 0x00EB: 0x8581, # LATIN SMALL LETTER E WITH DIAERESIS [2000]
+ 0x00EC: 0x8582, # LATIN SMALL LETTER I WITH GRAVE [2000]
+ 0x00ED: 0x8583, # LATIN SMALL LETTER I WITH ACUTE [2000]
+ 0x00EE: 0x8584, # LATIN SMALL LETTER I WITH CIRCUMFLEX [2000]
+ 0x00EF: 0x8585, # LATIN SMALL LETTER I WITH DIAERESIS [2000]
+ 0x00F0: 0x8586, # LATIN SMALL LETTER ETH [2000]
+ 0x00F1: 0x8587, # LATIN SMALL LETTER N WITH TILDE [2000]
+ 0x00F2: 0x8588, # LATIN SMALL LETTER O WITH GRAVE [2000]
+ 0x00F3: 0x8589, # LATIN SMALL LETTER O WITH ACUTE [2000]
+ 0x00F4: 0x858A, # LATIN SMALL LETTER O WITH CIRCUMFLEX [2000]
+ 0x00F5: 0x858B, # LATIN SMALL LETTER O WITH TILDE [2000]
+ 0x00F6: 0x858C, # LATIN SMALL LETTER O WITH DIAERESIS [2000]
+ 0x00F8: 0x858D, # LATIN SMALL LETTER O WITH STROKE [2000]
+ 0x00F9: 0x858E, # LATIN SMALL LETTER U WITH GRAVE [2000]
+ 0x00FA: 0x858F, # LATIN SMALL LETTER U WITH ACUTE [2000]
+ 0x00FB: 0x8590, # LATIN SMALL LETTER U WITH CIRCUMFLEX [2000]
+ 0x00FC: 0x8591, # LATIN SMALL LETTER U WITH DIAERESIS [2000]
+ 0x00FD: 0x8592, # LATIN SMALL LETTER Y WITH ACUTE [2000]
+ 0x00FE: 0x8593, # LATIN SMALL LETTER THORN [2000]
+ 0x00FF: 0x8594, # LATIN SMALL LETTER Y WITH DIAERESIS [2000]
+ 0x0100: 0x8595, # LATIN CAPITAL LETTER A WITH MACRON [2000]
+ 0x012A: 0x8596, # LATIN CAPITAL LETTER I WITH MACRON [2000]
+ 0x016A: 0x8597, # LATIN CAPITAL LETTER U WITH MACRON [2000]
+ 0x0112: 0x8598, # LATIN CAPITAL LETTER E WITH MACRON [2000]
+ 0x014C: 0x8599, # LATIN CAPITAL LETTER O WITH MACRON [2000]
+ 0x0101: 0x859A, # LATIN SMALL LETTER A WITH MACRON [2000]
+ 0x012B: 0x859B, # LATIN SMALL LETTER I WITH MACRON [2000]
+ 0x016B: 0x859C, # LATIN SMALL LETTER U WITH MACRON [2000]
+ 0x0113: 0x859D, # LATIN SMALL LETTER E WITH MACRON [2000]
+ 0x014D: 0x859E, # LATIN SMALL LETTER O WITH MACRON [2000]
+ 0x0104: 0x859F, # LATIN CAPITAL LETTER A WITH OGONEK [2000]
+ 0x02D8: 0x85A0, # BREVE [2000]
+ 0x0141: 0x85A1, # LATIN CAPITAL LETTER L WITH STROKE [2000]
+ 0x013D: 0x85A2, # LATIN CAPITAL LETTER L WITH CARON [2000]
+ 0x015A: 0x85A3, # LATIN CAPITAL LETTER S WITH ACUTE [2000]
+ 0x0160: 0x85A4, # LATIN CAPITAL LETTER S WITH CARON [2000]
+ 0x015E: 0x85A5, # LATIN CAPITAL LETTER S WITH CEDILLA [2000]
+ 0x0164: 0x85A6, # LATIN CAPITAL LETTER T WITH CARON [2000]
+ 0x0179: 0x85A7, # LATIN CAPITAL LETTER Z WITH ACUTE [2000]
+ 0x017D: 0x85A8, # LATIN CAPITAL LETTER Z WITH CARON [2000]
+ 0x017B: 0x85A9, # LATIN CAPITAL LETTER Z WITH DOT ABOVE [2000]
+ 0x0105: 0x85AA, # LATIN SMALL LETTER A WITH OGONEK [2000]
+ 0x02DB: 0x85AB, # OGONEK [2000]
+ 0x0142: 0x85AC, # LATIN SMALL LETTER L WITH STROKE [2000]
+ 0x013E: 0x85AD, # LATIN SMALL LETTER L WITH CARON [2000]
+ 0x015B: 0x85AE, # LATIN SMALL LETTER S WITH ACUTE [2000]
+ 0x02C7: 0x85AF, # CARON [2000]
+ 0x0161: 0x85B0, # LATIN SMALL LETTER S WITH CARON [2000]
+ 0x015F: 0x85B1, # LATIN SMALL LETTER S WITH CEDILLA [2000]
+ 0x0165: 0x85B2, # LATIN SMALL LETTER T WITH CARON [2000]
+ 0x017A: 0x85B3, # LATIN SMALL LETTER Z WITH ACUTE [2000]
+ 0x02DD: 0x85B4, # DOUBLE ACUTE ACCENT [2000]
+ 0x017E: 0x85B5, # LATIN SMALL LETTER Z WITH CARON [2000]
+ 0x017C: 0x85B6, # LATIN SMALL LETTER Z WITH DOT ABOVE [2000]
+ 0x0154: 0x85B7, # LATIN CAPITAL LETTER R WITH ACUTE [2000]
+ 0x0102: 0x85B8, # LATIN CAPITAL LETTER A WITH BREVE [2000]
+ 0x0139: 0x85B9, # LATIN CAPITAL LETTER L WITH ACUTE [2000]
+ 0x0106: 0x85BA, # LATIN CAPITAL LETTER C WITH ACUTE [2000]
+ 0x010C: 0x85BB, # LATIN CAPITAL LETTER C WITH CARON [2000]
+ 0x0118: 0x85BC, # LATIN CAPITAL LETTER E WITH OGONEK [2000]
+ 0x011A: 0x85BD, # LATIN CAPITAL LETTER E WITH CARON [2000]
+ 0x010E: 0x85BE, # LATIN CAPITAL LETTER D WITH CARON [2000]
+ 0x0143: 0x85BF, # LATIN CAPITAL LETTER N WITH ACUTE [2000]
+ 0x0147: 0x85C0, # LATIN CAPITAL LETTER N WITH CARON [2000]
+ 0x0150: 0x85C1, # LATIN CAPITAL LETTER O WITH DOUBLE ACUTE [2000]
+ 0x0158: 0x85C2, # LATIN CAPITAL LETTER R WITH CARON [2000]
+ 0x016E: 0x85C3, # LATIN CAPITAL LETTER U WITH RING ABOVE [2000]
+ 0x0170: 0x85C4, # LATIN CAPITAL LETTER U WITH DOUBLE ACUTE [2000]
+ 0x0162: 0x85C5, # LATIN CAPITAL LETTER T WITH CEDILLA [2000]
+ 0x0155: 0x85C6, # LATIN SMALL LETTER R WITH ACUTE [2000]
+ 0x0103: 0x85C7, # LATIN SMALL LETTER A WITH BREVE [2000]
+ 0x013A: 0x85C8, # LATIN SMALL LETTER L WITH ACUTE [2000]
+ 0x0107: 0x85C9, # LATIN SMALL LETTER C WITH ACUTE [2000]
+ 0x010D: 0x85CA, # LATIN SMALL LETTER C WITH CARON [2000]
+ 0x0119: 0x85CB, # LATIN SMALL LETTER E WITH OGONEK [2000]
+ 0x011B: 0x85CC, # LATIN SMALL LETTER E WITH CARON [2000]
+ 0x010F: 0x85CD, # LATIN SMALL LETTER D WITH CARON [2000]
+ 0x0111: 0x85CE, # LATIN SMALL LETTER D WITH STROKE [2000]
+ 0x0144: 0x85CF, # LATIN SMALL LETTER N WITH ACUTE [2000]
+ 0x0148: 0x85D0, # LATIN SMALL LETTER N WITH CARON [2000]
+ 0x0151: 0x85D1, # LATIN SMALL LETTER O WITH DOUBLE ACUTE [2000]
+ 0x0159: 0x85D2, # LATIN SMALL LETTER R WITH CARON [2000]
+ 0x016F: 0x85D3, # LATIN SMALL LETTER U WITH RING ABOVE [2000]
+ 0x0171: 0x85D4, # LATIN SMALL LETTER U WITH DOUBLE ACUTE [2000]
+ 0x0163: 0x85D5, # LATIN SMALL LETTER T WITH CEDILLA [2000]
+ 0x02D9: 0x85D6, # DOT ABOVE [2000]
+ 0x0108: 0x85D7, # LATIN CAPITAL LETTER C WITH CIRCUMFLEX [2000]
+ 0x011C: 0x85D8, # LATIN CAPITAL LETTER G WITH CIRCUMFLEX [2000]
+ 0x0124: 0x85D9, # LATIN CAPITAL LETTER H WITH CIRCUMFLEX [2000]
+ 0x0134: 0x85DA, # LATIN CAPITAL LETTER J WITH CIRCUMFLEX [2000]
+ 0x015C: 0x85DB, # LATIN CAPITAL LETTER S WITH CIRCUMFLEX [2000]
+ 0x016C: 0x85DC, # LATIN CAPITAL LETTER U WITH BREVE [2000]
+ 0x0109: 0x85DD, # LATIN SMALL LETTER C WITH CIRCUMFLEX [2000]
+ 0x011D: 0x85DE, # LATIN SMALL LETTER G WITH CIRCUMFLEX [2000]
+ 0x0125: 0x85DF, # LATIN SMALL LETTER H WITH CIRCUMFLEX [2000]
+ 0x0135: 0x85E0, # LATIN SMALL LETTER J WITH CIRCUMFLEX [2000]
+ 0x015D: 0x85E1, # LATIN SMALL LETTER S WITH CIRCUMFLEX [2000]
+ 0x016D: 0x85E2, # LATIN SMALL LETTER U WITH BREVE [2000]
+ 0x0271: 0x85E3, # LATIN SMALL LETTER M WITH HOOK [2000]
+ 0x028B: 0x85E4, # LATIN SMALL LETTER V WITH HOOK [2000]
+ 0x027E: 0x85E5, # LATIN SMALL LETTER R WITH FISHHOOK [2000]
+ 0x0283: 0x85E6, # LATIN SMALL LETTER ESH [2000]
+ 0x0292: 0x85E7, # LATIN SMALL LETTER EZH [2000]
+ 0x026C: 0x85E8, # LATIN SMALL LETTER L WITH BELT [2000]
+ 0x026E: 0x85E9, # LATIN SMALL LETTER LEZH [2000]
+ 0x0279: 0x85EA, # LATIN SMALL LETTER TURNED R [2000]
+ 0x0288: 0x85EB, # LATIN SMALL LETTER T WITH RETROFLEX HOOK [2000]
+ 0x0256: 0x85EC, # LATIN SMALL LETTER D WITH TAIL [2000]
+ 0x0273: 0x85ED, # LATIN SMALL LETTER N WITH RETROFLEX HOOK [2000]
+ 0x027D: 0x85EE, # LATIN SMALL LETTER R WITH TAIL [2000]
+ 0x0282: 0x85EF, # LATIN SMALL LETTER S WITH HOOK [2000]
+ 0x0290: 0x85F0, # LATIN SMALL LETTER Z WITH RETROFLEX HOOK [2000]
+ 0x027B: 0x85F1, # LATIN SMALL LETTER TURNED R WITH HOOK [2000]
+ 0x026D: 0x85F2, # LATIN SMALL LETTER L WITH RETROFLEX HOOK [2000]
+ 0x025F: 0x85F3, # LATIN SMALL LETTER DOTLESS J WITH STROKE [2000]
+ 0x0272: 0x85F4, # LATIN SMALL LETTER N WITH LEFT HOOK [2000]
+ 0x029D: 0x85F5, # LATIN SMALL LETTER J WITH CROSSED-TAIL [2000]
+ 0x028E: 0x85F6, # LATIN SMALL LETTER TURNED Y [2000]
+ 0x0261: 0x85F7, # LATIN SMALL LETTER SCRIPT G [2000]
+ 0x014B: 0x85F8, # LATIN SMALL LETTER ENG [2000]
+ 0x0270: 0x85F9, # LATIN SMALL LETTER TURNED M WITH LONG LEG [2000]
+ 0x0281: 0x85FA, # LATIN LETTER SMALL CAPITAL INVERTED R [2000]
+ 0x0127: 0x85FB, # LATIN SMALL LETTER H WITH STROKE [2000]
+ 0x0295: 0x85FC, # LATIN LETTER PHARYNGEAL VOICED FRICATIVE [2000]
+ 0x0294: 0x8640, # LATIN LETTER GLOTTAL STOP [2000]
+ 0x0266: 0x8641, # LATIN SMALL LETTER H WITH HOOK [2000]
+ 0x0298: 0x8642, # LATIN LETTER BILABIAL CLICK [2000]
+ 0x01C2: 0x8643, # LATIN LETTER ALVEOLAR CLICK [2000]
+ 0x0253: 0x8644, # LATIN SMALL LETTER B WITH HOOK [2000]
+ 0x0257: 0x8645, # LATIN SMALL LETTER D WITH HOOK [2000]
+ 0x0284: 0x8646, # LATIN SMALL LETTER DOTLESS J WITH STROKE AND HOOK [2000]
+ 0x0260: 0x8647, # LATIN SMALL LETTER G WITH HOOK [2000]
+ 0x0193: 0x8648, # LATIN CAPITAL LETTER G WITH HOOK [2000]
+ 0x0153: 0x8649, # LATIN SMALL LIGATURE OE [2000]
+ 0x0152: 0x864A, # LATIN CAPITAL LIGATURE OE [2000]
+ 0x0268: 0x864B, # LATIN SMALL LETTER I WITH STROKE [2000]
+ 0x0289: 0x864C, # LATIN SMALL LETTER U BAR [2000]
+ 0x0258: 0x864D, # LATIN SMALL LETTER REVERSED E [2000]
+ 0x0275: 0x864E, # LATIN SMALL LETTER BARRED O [2000]
+ 0x0259: 0x864F, # LATIN SMALL LETTER SCHWA [2000]
+ 0x025C: 0x8650, # LATIN SMALL LETTER REVERSED OPEN E [2000]
+ 0x025E: 0x8651, # LATIN SMALL LETTER CLOSED REVERSED OPEN E [2000]
+ 0x0250: 0x8652, # LATIN SMALL LETTER TURNED A [2000]
+ 0x026F: 0x8653, # LATIN SMALL LETTER TURNED M [2000]
+ 0x028A: 0x8654, # LATIN SMALL LETTER UPSILON [2000]
+ 0x0264: 0x8655, # LATIN SMALL LETTER RAMS HORN [2000]
+ 0x028C: 0x8656, # LATIN SMALL LETTER TURNED V [2000]
+ 0x0254: 0x8657, # LATIN SMALL LETTER OPEN O [2000]
+ 0x0251: 0x8658, # LATIN SMALL LETTER ALPHA [2000]
+ 0x0252: 0x8659, # LATIN SMALL LETTER TURNED ALPHA [2000]
+ 0x028D: 0x865A, # LATIN SMALL LETTER TURNED W [2000]
+ 0x0265: 0x865B, # LATIN SMALL LETTER TURNED H [2000]
+ 0x02A2: 0x865C, # LATIN LETTER REVERSED GLOTTAL STOP WITH STROKE [2000]
+ 0x02A1: 0x865D, # LATIN LETTER GLOTTAL STOP WITH STROKE [2000]
+ 0x0255: 0x865E, # LATIN SMALL LETTER C WITH CURL [2000]
+ 0x0291: 0x865F, # LATIN SMALL LETTER Z WITH CURL [2000]
+ 0x027A: 0x8660, # LATIN SMALL LETTER TURNED R WITH LONG LEG [2000]
+ 0x0267: 0x8661, # LATIN SMALL LETTER HENG WITH HOOK [2000]
+ 0x025A: 0x8662, # LATIN SMALL LETTER SCHWA WITH HOOK [2000]
+ 0x00E60300: 0x8663, # [2000]
+ 0x01FD: 0x8664, # LATIN SMALL LETTER AE WITH ACUTE [2000]
+ 0x1F70: 0x8665, # GREEK SMALL LETTER ALPHA WITH VARIA [2000]
+ 0x1F71: 0x8666, # GREEK SMALL LETTER ALPHA WITH OXIA [2000]
+ 0x02540300: 0x8667, # [2000]
+ 0x02540301: 0x8668, # [2000]
+ 0x028C0300: 0x8669, # [2000]
+ 0x028C0301: 0x866A, # [2000]
+ 0x02590300: 0x866B, # [2000]
+ 0x02590301: 0x866C, # [2000]
+ 0x025A0300: 0x866D, # [2000]
+ 0x025A0301: 0x866E, # [2000]
+ 0x1F72: 0x866F, # GREEK SMALL LETTER EPSILON WITH VARIA [2000]
+ 0x1F73: 0x8670, # GREEK SMALL LETTER EPSILON WITH OXIA [2000]
+ 0x0361: 0x8671, # COMBINING DOUBLE INVERTED BREVE [2000]
+ 0x02C8: 0x8672, # MODIFIER LETTER VERTICAL LINE [2000]
+ 0x02CC: 0x8673, # MODIFIER LETTER LOW VERTICAL LINE [2000]
+ 0x02D0: 0x8674, # MODIFIER LETTER TRIANGULAR COLON [2000]
+ 0x02D1: 0x8675, # MODIFIER LETTER HALF TRIANGULAR COLON [2000]
+ 0x0306: 0x8676, # COMBINING BREVE [2000]
+ 0x203F: 0x8677, # UNDERTIE [2000]
+ 0x030B: 0x8678, # COMBINING DOUBLE ACUTE ACCENT [2000]
+ 0x0301: 0x8679, # COMBINING ACUTE ACCENT [2000]
+ 0x0304: 0x867A, # COMBINING MACRON [2000]
+ 0x0300: 0x867B, # COMBINING GRAVE ACCENT [2000]
+ 0x030F: 0x867C, # COMBINING DOUBLE GRAVE ACCENT [2000]
+ 0x030C: 0x867D, # COMBINING CARON [2000]
+ 0x0302: 0x867E, # COMBINING CIRCUMFLEX ACCENT [2000]
+ 0x02E5: 0x8680, # MODIFIER LETTER EXTRA-HIGH TONE BAR [2000]
+ 0x02E6: 0x8681, # MODIFIER LETTER HIGH TONE BAR [2000]
+ 0x02E7: 0x8682, # MODIFIER LETTER MID TONE BAR [2000]
+ 0x02E8: 0x8683, # MODIFIER LETTER LOW TONE BAR [2000]
+ 0x02E9: 0x8684, # MODIFIER LETTER EXTRA-LOW TONE BAR [2000]
+ 0x02E902E5: 0x8685, # [2000]
+ 0x02E502E9: 0x8686, # [2000]
+ 0x0325: 0x8687, # COMBINING RING BELOW [2000]
+ 0x032C: 0x8688, # COMBINING CARON BELOW [2000]
+ 0x0339: 0x8689, # COMBINING RIGHT HALF RING BELOW [2000]
+ 0x031C: 0x868A, # COMBINING LEFT HALF RING BELOW [2000]
+ 0x031F: 0x868B, # COMBINING PLUS SIGN BELOW [2000]
+ 0x0320: 0x868C, # COMBINING MINUS SIGN BELOW [2000]
+ 0x0308: 0x868D, # COMBINING DIAERESIS [2000]
+ 0x033D: 0x868E, # COMBINING X ABOVE [2000]
+ 0x0329: 0x868F, # COMBINING VERTICAL LINE BELOW [2000]
+ 0x032F: 0x8690, # COMBINING INVERTED BREVE BELOW [2000]
+ 0x02DE: 0x8691, # MODIFIER LETTER RHOTIC HOOK [2000]
+ 0x0324: 0x8692, # COMBINING DIAERESIS BELOW [2000]
+ 0x0330: 0x8693, # COMBINING TILDE BELOW [2000]
+ 0x033C: 0x8694, # COMBINING SEAGULL BELOW [2000]
+ 0x0334: 0x8695, # COMBINING TILDE OVERLAY [2000]
+ 0x031D: 0x8696, # COMBINING UP TACK BELOW [2000]
+ 0x031E: 0x8697, # COMBINING DOWN TACK BELOW [2000]
+ 0x0318: 0x8698, # COMBINING LEFT TACK BELOW [2000]
+ 0x0319: 0x8699, # COMBINING RIGHT TACK BELOW [2000]
+ 0x032A: 0x869A, # COMBINING BRIDGE BELOW [2000]
+ 0x033A: 0x869B, # COMBINING INVERTED BRIDGE BELOW [2000]
+ 0x033B: 0x869C, # COMBINING SQUARE BELOW [2000]
+ 0x0303: 0x869D, # COMBINING TILDE [2000]
+ 0x031A: 0x869E, # COMBINING LEFT ANGLE ABOVE [2000]
+ 0x2776: 0x869F, # DINGBAT NEGATIVE CIRCLED DIGIT ONE [2000]
+ 0x2777: 0x86A0, # DINGBAT NEGATIVE CIRCLED DIGIT TWO [2000]
+ 0x2778: 0x86A1, # DINGBAT NEGATIVE CIRCLED DIGIT THREE [2000]
+ 0x2779: 0x86A2, # DINGBAT NEGATIVE CIRCLED DIGIT FOUR [2000]
+ 0x277A: 0x86A3, # DINGBAT NEGATIVE CIRCLED DIGIT FIVE [2000]
+ 0x277B: 0x86A4, # DINGBAT NEGATIVE CIRCLED DIGIT SIX [2000]
+ 0x277C: 0x86A5, # DINGBAT NEGATIVE CIRCLED DIGIT SEVEN [2000]
+ 0x277D: 0x86A6, # DINGBAT NEGATIVE CIRCLED DIGIT EIGHT [2000]
+ 0x277E: 0x86A7, # DINGBAT NEGATIVE CIRCLED DIGIT NINE [2000]
+ 0x277F: 0x86A8, # DINGBAT NEGATIVE CIRCLED NUMBER TEN [2000]
+ 0x24EB: 0x86A9, # NEGATIVE CIRCLED NUMBER ELEVEN [2000] [Unicode3.2]
+ 0x24EC: 0x86AA, # NEGATIVE CIRCLED NUMBER TWELVE [2000] [Unicode3.2]
+ 0x24ED: 0x86AB, # NEGATIVE CIRCLED NUMBER THIRTEEN [2000] [Unicode3.2]
+ 0x24EE: 0x86AC, # NEGATIVE CIRCLED NUMBER FOURTEEN [2000] [Unicode3.2]
+ 0x24EF: 0x86AD, # NEGATIVE CIRCLED NUMBER FIFTEEN [2000] [Unicode3.2]
+ 0x24F0: 0x86AE, # NEGATIVE CIRCLED NUMBER SIXTEEN [2000] [Unicode3.2]
+ 0x24F1: 0x86AF, # NEGATIVE CIRCLED NUMBER SEVENTEEN [2000] [Unicode3.2]
+ 0x24F2: 0x86B0, # NEGATIVE CIRCLED NUMBER EIGHTEEN [2000] [Unicode3.2]
+ 0x24F3: 0x86B1, # NEGATIVE CIRCLED NUMBER NINETEEN [2000] [Unicode3.2]
+ 0x24F4: 0x86B2, # NEGATIVE CIRCLED NUMBER TWENTY [2000] [Unicode3.2]
+ 0x2170: 0x86B3, # SMALL ROMAN NUMERAL ONE [2000]
+ 0x2171: 0x86B4, # SMALL ROMAN NUMERAL TWO [2000]
+ 0x2172: 0x86B5, # SMALL ROMAN NUMERAL THREE [2000]
+ 0x2173: 0x86B6, # SMALL ROMAN NUMERAL FOUR [2000]
+ 0x2174: 0x86B7, # SMALL ROMAN NUMERAL FIVE [2000]
+ 0x2175: 0x86B8, # SMALL ROMAN NUMERAL SIX [2000]
+ 0x2176: 0x86B9, # SMALL ROMAN NUMERAL SEVEN [2000]
+ 0x2177: 0x86BA, # SMALL ROMAN NUMERAL EIGHT [2000]
+ 0x2178: 0x86BB, # SMALL ROMAN NUMERAL NINE [2000]
+ 0x2179: 0x86BC, # SMALL ROMAN NUMERAL TEN [2000]
+ 0x217A: 0x86BD, # SMALL ROMAN NUMERAL ELEVEN [2000]
+ 0x217B: 0x86BE, # SMALL ROMAN NUMERAL TWELVE [2000]
+ 0x24D0: 0x86BF, # CIRCLED LATIN SMALL LETTER A [2000]
+ 0x24D1: 0x86C0, # CIRCLED LATIN SMALL LETTER B [2000]
+ 0x24D2: 0x86C1, # CIRCLED LATIN SMALL LETTER C [2000]
+ 0x24D3: 0x86C2, # CIRCLED LATIN SMALL LETTER D [2000]
+ 0x24D4: 0x86C3, # CIRCLED LATIN SMALL LETTER E [2000]
+ 0x24D5: 0x86C4, # CIRCLED LATIN SMALL LETTER F [2000]
+ 0x24D6: 0x86C5, # CIRCLED LATIN SMALL LETTER G [2000]
+ 0x24D7: 0x86C6, # CIRCLED LATIN SMALL LETTER H [2000]
+ 0x24D8: 0x86C7, # CIRCLED LATIN SMALL LETTER I [2000]
+ 0x24D9: 0x86C8, # CIRCLED LATIN SMALL LETTER J [2000]
+ 0x24DA: 0x86C9, # CIRCLED LATIN SMALL LETTER K [2000]
+ 0x24DB: 0x86CA, # CIRCLED LATIN SMALL LETTER L [2000]
+ 0x24DC: 0x86CB, # CIRCLED LATIN SMALL LETTER M [2000]
+ 0x24DD: 0x86CC, # CIRCLED LATIN SMALL LETTER N [2000]
+ 0x24DE: 0x86CD, # CIRCLED LATIN SMALL LETTER O [2000]
+ 0x24DF: 0x86CE, # CIRCLED LATIN SMALL LETTER P [2000]
+ 0x24E0: 0x86CF, # CIRCLED LATIN SMALL LETTER Q [2000]
+ 0x24E1: 0x86D0, # CIRCLED LATIN SMALL LETTER R [2000]
+ 0x24E2: 0x86D1, # CIRCLED LATIN SMALL LETTER S [2000]
+ 0x24E3: 0x86D2, # CIRCLED LATIN SMALL LETTER T [2000]
+ 0x24E4: 0x86D3, # CIRCLED LATIN SMALL LETTER U [2000]
+ 0x24E5: 0x86D4, # CIRCLED LATIN SMALL LETTER V [2000]
+ 0x24E6: 0x86D5, # CIRCLED LATIN SMALL LETTER W [2000]
+ 0x24E7: 0x86D6, # CIRCLED LATIN SMALL LETTER X [2000]
+ 0x24E8: 0x86D7, # CIRCLED LATIN SMALL LETTER Y [2000]
+ 0x24E9: 0x86D8, # CIRCLED LATIN SMALL LETTER Z [2000]
+ 0x32D0: 0x86D9, # CIRCLED KATAKANA A [2000]
+ 0x32D1: 0x86DA, # CIRCLED KATAKANA I [2000]
+ 0x32D2: 0x86DB, # CIRCLED KATAKANA U [2000]
+ 0x32D3: 0x86DC, # CIRCLED KATAKANA E [2000]
+ 0x32D4: 0x86DD, # CIRCLED KATAKANA O [2000]
+ 0x32D5: 0x86DE, # CIRCLED KATAKANA KA [2000]
+ 0x32D6: 0x86DF, # CIRCLED KATAKANA KI [2000]
+ 0x32D7: 0x86E0, # CIRCLED KATAKANA KU [2000]
+ 0x32D8: 0x86E1, # CIRCLED KATAKANA KE [2000]
+ 0x32D9: 0x86E2, # CIRCLED KATAKANA KO [2000]
+ 0x32DA: 0x86E3, # CIRCLED KATAKANA SA [2000]
+ 0x32DB: 0x86E4, # CIRCLED KATAKANA SI [2000]
+ 0x32DC: 0x86E5, # CIRCLED KATAKANA SU [2000]
+ 0x32DD: 0x86E6, # CIRCLED KATAKANA SE [2000]
+ 0x32DE: 0x86E7, # CIRCLED KATAKANA SO [2000]
+ 0x32DF: 0x86E8, # CIRCLED KATAKANA TA [2000]
+ 0x32E0: 0x86E9, # CIRCLED KATAKANA TI [2000]
+ 0x32E1: 0x86EA, # CIRCLED KATAKANA TU [2000]
+ 0x32E2: 0x86EB, # CIRCLED KATAKANA TE [2000]
+ 0x32E3: 0x86EC, # CIRCLED KATAKANA TO [2000]
+ 0x32FA: 0x86ED, # CIRCLED KATAKANA RO [2000]
+ 0x32E9: 0x86EE, # CIRCLED KATAKANA HA [2000]
+ 0x32E5: 0x86EF, # CIRCLED KATAKANA NI [2000]
+ 0x32ED: 0x86F0, # CIRCLED KATAKANA HO [2000]
+ 0x32EC: 0x86F1, # CIRCLED KATAKANA HE [2000]
+# 0x86F2 -
+# 0x86F3 -
+# 0x86F4 -
+# 0x86F5 -
+# 0x86F6 -
+# 0x86F7 -
+# 0x86F8 -
+# 0x86F9 -
+# 0x86FA -
+ 0x2051: 0x86FB, # TWO ASTERISKS ALIGNED VERTICALLY [2000] [Unicode3.2]
+ 0x2042: 0x86FC, # ASTERISM [2000]
+ 0x2460: 0x8740, # CIRCLED DIGIT ONE [2000]
+ 0x2461: 0x8741, # CIRCLED DIGIT TWO [2000]
+ 0x2462: 0x8742, # CIRCLED DIGIT THREE [2000]
+ 0x2463: 0x8743, # CIRCLED DIGIT FOUR [2000]
+ 0x2464: 0x8744, # CIRCLED DIGIT FIVE [2000]
+ 0x2465: 0x8745, # CIRCLED DIGIT SIX [2000]
+ 0x2466: 0x8746, # CIRCLED DIGIT SEVEN [2000]
+ 0x2467: 0x8747, # CIRCLED DIGIT EIGHT [2000]
+ 0x2468: 0x8748, # CIRCLED DIGIT NINE [2000]
+ 0x2469: 0x8749, # CIRCLED NUMBER TEN [2000]
+ 0x246A: 0x874A, # CIRCLED NUMBER ELEVEN [2000]
+ 0x246B: 0x874B, # CIRCLED NUMBER TWELVE [2000]
+ 0x246C: 0x874C, # CIRCLED NUMBER THIRTEEN [2000]
+ 0x246D: 0x874D, # CIRCLED NUMBER FOURTEEN [2000]
+ 0x246E: 0x874E, # CIRCLED NUMBER FIFTEEN [2000]
+ 0x246F: 0x874F, # CIRCLED NUMBER SIXTEEN [2000]
+ 0x2470: 0x8750, # CIRCLED NUMBER SEVENTEEN [2000]
+ 0x2471: 0x8751, # CIRCLED NUMBER EIGHTEEN [2000]
+ 0x2472: 0x8752, # CIRCLED NUMBER NINETEEN [2000]
+ 0x2473: 0x8753, # CIRCLED NUMBER TWENTY [2000]
+ 0x2160: 0x8754, # ROMAN NUMERAL ONE [2000]
+ 0x2161: 0x8755, # ROMAN NUMERAL TWO [2000]
+ 0x2162: 0x8756, # ROMAN NUMERAL THREE [2000]
+ 0x2163: 0x8757, # ROMAN NUMERAL FOUR [2000]
+ 0x2164: 0x8758, # ROMAN NUMERAL FIVE [2000]
+ 0x2165: 0x8759, # ROMAN NUMERAL SIX [2000]
+ 0x2166: 0x875A, # ROMAN NUMERAL SEVEN [2000]
+ 0x2167: 0x875B, # ROMAN NUMERAL EIGHT [2000]
+ 0x2168: 0x875C, # ROMAN NUMERAL NINE [2000]
+ 0x2169: 0x875D, # ROMAN NUMERAL TEN [2000]
+ 0x216A: 0x875E, # ROMAN NUMERAL ELEVEN [2000]
+ 0x3349: 0x875F, # SQUARE MIRI [2000]
+ 0x3314: 0x8760, # SQUARE KIRO [2000]
+ 0x3322: 0x8761, # SQUARE SENTI [2000]
+ 0x334D: 0x8762, # SQUARE MEETORU [2000]
+ 0x3318: 0x8763, # SQUARE GURAMU [2000]
+ 0x3327: 0x8764, # SQUARE TON [2000]
+ 0x3303: 0x8765, # SQUARE AARU [2000]
+ 0x3336: 0x8766, # SQUARE HEKUTAARU [2000]
+ 0x3351: 0x8767, # SQUARE RITTORU [2000]
+ 0x3357: 0x8768, # SQUARE WATTO [2000]
+ 0x330D: 0x8769, # SQUARE KARORII [2000]
+ 0x3326: 0x876A, # SQUARE DORU [2000]
+ 0x3323: 0x876B, # SQUARE SENTO [2000]
+ 0x332B: 0x876C, # SQUARE PAASENTO [2000]
+ 0x334A: 0x876D, # SQUARE MIRIBAARU [2000]
+ 0x333B: 0x876E, # SQUARE PEEZI [2000]
+ 0x339C: 0x876F, # SQUARE MM [2000]
+ 0x339D: 0x8770, # SQUARE CM [2000]
+ 0x339E: 0x8771, # SQUARE KM [2000]
+ 0x338E: 0x8772, # SQUARE MG [2000]
+ 0x338F: 0x8773, # SQUARE KG [2000]
+ 0x33C4: 0x8774, # SQUARE CC [2000]
+ 0x33A1: 0x8775, # SQUARE M SQUARED [2000]
+ 0x216B: 0x8776, # ROMAN NUMERAL TWELVE [2000]
+# 0x8777 -
+# 0x8778 -
+# 0x8779 -
+# 0x877A -
+# 0x877B -
+# 0x877C -
+# 0x877D -
+ 0x337B: 0x877E, # SQUARE ERA NAME HEISEI [2000]
+ 0x301D: 0x8780, # REVERSED DOUBLE PRIME QUOTATION MARK [2000]
+ 0x301F: 0x8781, # LOW DOUBLE PRIME QUOTATION MARK [2000]
+ 0x2116: 0x8782, # NUMERO SIGN [2000]
+ 0x33CD: 0x8783, # SQUARE KK [2000]
+ 0x2121: 0x8784, # TELEPHONE SIGN [2000]
+ 0x32A4: 0x8785, # CIRCLED IDEOGRAPH HIGH [2000]
+ 0x32A5: 0x8786, # CIRCLED IDEOGRAPH CENTRE [2000]
+ 0x32A6: 0x8787, # CIRCLED IDEOGRAPH LOW [2000]
+ 0x32A7: 0x8788, # CIRCLED IDEOGRAPH LEFT [2000]
+ 0x32A8: 0x8789, # CIRCLED IDEOGRAPH RIGHT [2000]
+ 0x3231: 0x878A, # PARENTHESIZED IDEOGRAPH STOCK [2000]
+ 0x3232: 0x878B, # PARENTHESIZED IDEOGRAPH HAVE [2000]
+ 0x3239: 0x878C, # PARENTHESIZED IDEOGRAPH REPRESENT [2000]
+ 0x337E: 0x878D, # SQUARE ERA NAME MEIZI [2000]
+ 0x337D: 0x878E, # SQUARE ERA NAME TAISYOU [2000]
+ 0x337C: 0x878F, # SQUARE ERA NAME SYOUWA [2000]
+# 0x8790 - Windows: U+2252
+# 0x8791 - Windows: U+2261
+# 0x8792 - Windows: U+222B
+ 0x222E: 0x8793, # CONTOUR INTEGRAL [2000]
+# 0x8794 - Windows: U+2211
+# 0x8795 - Windows: U+221A
+# 0x8796 - Windows: U+22A5
+# 0x8797 - Windows: U+2220
+ 0x221F: 0x8798, # RIGHT ANGLE [2000]
+ 0x22BF: 0x8799, # RIGHT TRIANGLE [2000]
+# 0x879A - Windows: U+2235
+# 0x879B - Windows: U+2229
+# 0x879C - Windows: U+222A
+ 0x2756: 0x879D, # BLACK DIAMOND MINUS WHITE X [2000]
+ 0x261E: 0x879E, # WHITE RIGHT POINTING INDEX [2000]
+ 0x4FF1: 0x879F, # [2004]
+ 0x2000B: 0x87A0, # [2000] [Unicode3.1]
+ 0x3402: 0x87A1, # [2000]
+ 0x4E28: 0x87A2, # [2000]
+ 0x4E2F: 0x87A3, # [2000]
+ 0x4E30: 0x87A4, # [2000]
+ 0x4E8D: 0x87A5, # [2000]
+ 0x4EE1: 0x87A6, # [2000]
+ 0x4EFD: 0x87A7, # [2000]
+ 0x4EFF: 0x87A8, # [2000]
+ 0x4F03: 0x87A9, # [2000]
+ 0x4F0B: 0x87AA, # [2000]
+ 0x4F60: 0x87AB, # [2000]
+ 0x4F48: 0x87AC, # [2000]
+ 0x4F49: 0x87AD, # [2000]
+ 0x4F56: 0x87AE, # [2000]
+ 0x4F5F: 0x87AF, # [2000]
+ 0x4F6A: 0x87B0, # [2000]
+ 0x4F6C: 0x87B1, # [2000]
+ 0x4F7E: 0x87B2, # [2000]
+ 0x4F8A: 0x87B3, # [2000]
+ 0x4F94: 0x87B4, # [2000]
+ 0x4F97: 0x87B5, # [2000]
+ 0xFA30: 0x87B6, # CJK COMPATIBILITY IDEOGRAPH-FA30 [2000] [Unicode3.2]
+ 0x4FC9: 0x87B7, # [2000]
+ 0x4FE0: 0x87B8, # [2000]
+ 0x5001: 0x87B9, # [2000]
+ 0x5002: 0x87BA, # [2000]
+ 0x500E: 0x87BB, # [2000]
+ 0x5018: 0x87BC, # [2000]
+ 0x5027: 0x87BD, # [2000]
+ 0x502E: 0x87BE, # [2000]
+ 0x5040: 0x87BF, # [2000]
+ 0x503B: 0x87C0, # [2000]
+ 0x5041: 0x87C1, # [2000]
+ 0x5094: 0x87C2, # [2000]
+ 0x50CC: 0x87C3, # [2000]
+ 0x50F2: 0x87C4, # [2000]
+ 0x50D0: 0x87C5, # [2000]
+ 0x50E6: 0x87C6, # [2000]
+ 0xFA31: 0x87C7, # CJK COMPATIBILITY IDEOGRAPH-FA31 [2000] [Unicode3.2]
+ 0x5106: 0x87C8, # [2000]
+ 0x5103: 0x87C9, # [2000]
+ 0x510B: 0x87CA, # [2000]
+ 0x511E: 0x87CB, # [2000]
+ 0x5135: 0x87CC, # [2000]
+ 0x514A: 0x87CD, # [2000]
+ 0xFA32: 0x87CE, # CJK COMPATIBILITY IDEOGRAPH-FA32 [2000] [Unicode3.2]
+ 0x5155: 0x87CF, # [2000]
+ 0x5157: 0x87D0, # [2000]
+ 0x34B5: 0x87D1, # [2000]
+ 0x519D: 0x87D2, # [2000]
+ 0x51C3: 0x87D3, # [2000]
+ 0x51CA: 0x87D4, # [2000]
+ 0x51DE: 0x87D5, # [2000]
+ 0x51E2: 0x87D6, # [2000]
+ 0x51EE: 0x87D7, # [2000]
+ 0x5201: 0x87D8, # [2000]
+ 0x34DB: 0x87D9, # [2000]
+ 0x5213: 0x87DA, # [2000]
+ 0x5215: 0x87DB, # [2000]
+ 0x5249: 0x87DC, # [2000]
+ 0x5257: 0x87DD, # [2000]
+ 0x5261: 0x87DE, # [2000]
+ 0x5293: 0x87DF, # [2000]
+ 0x52C8: 0x87E0, # [2000]
+ 0xFA33: 0x87E1, # CJK COMPATIBILITY IDEOGRAPH-FA33 [2000] [Unicode3.2]
+ 0x52CC: 0x87E2, # [2000]
+ 0x52D0: 0x87E3, # [2000]
+ 0x52D6: 0x87E4, # [2000]
+ 0x52DB: 0x87E5, # [2000]
+ 0xFA34: 0x87E6, # CJK COMPATIBILITY IDEOGRAPH-FA34 [2000] [Unicode3.2]
+ 0x52F0: 0x87E7, # [2000]
+ 0x52FB: 0x87E8, # [2000]
+ 0x5300: 0x87E9, # [2000]
+ 0x5307: 0x87EA, # [2000]
+ 0x531C: 0x87EB, # [2000]
+ 0xFA35: 0x87EC, # CJK COMPATIBILITY IDEOGRAPH-FA35 [2000] [Unicode3.2]
+ 0x5361: 0x87ED, # [2000]
+ 0x5363: 0x87EE, # [2000]
+ 0x537D: 0x87EF, # [2000]
+ 0x5393: 0x87F0, # [2000]
+ 0x539D: 0x87F1, # [2000]
+ 0x53B2: 0x87F2, # [2000]
+ 0x5412: 0x87F3, # [2000]
+ 0x5427: 0x87F4, # [2000]
+ 0x544D: 0x87F5, # [2000]
+ 0x549C: 0x87F6, # [2000]
+ 0x546B: 0x87F7, # [2000]
+ 0x5474: 0x87F8, # [2000]
+ 0x547F: 0x87F9, # [2000]
+ 0x5488: 0x87FA, # [2000]
+ 0x5496: 0x87FB, # [2000]
+ 0x54A1: 0x87FC, # [2000]
+ 0x54A9: 0x8840, # [2000]
+ 0x54C6: 0x8841, # [2000]
+ 0x54FF: 0x8842, # [2000]
+ 0x550E: 0x8843, # [2000]
+ 0x552B: 0x8844, # [2000]
+ 0x5535: 0x8845, # [2000]
+ 0x5550: 0x8846, # [2000]
+ 0x555E: 0x8847, # [2000]
+ 0x5581: 0x8848, # [2000]
+ 0x5586: 0x8849, # [2000]
+ 0x558E: 0x884A, # [2000]
+ 0xFA36: 0x884B, # CJK COMPATIBILITY IDEOGRAPH-FA36 [2000] [Unicode3.2]
+ 0x55AD: 0x884C, # [2000]
+ 0x55CE: 0x884D, # [2000]
+ 0xFA37: 0x884E, # CJK COMPATIBILITY IDEOGRAPH-FA37 [2000] [Unicode3.2]
+ 0x5608: 0x884F, # [2000]
+ 0x560E: 0x8850, # [2000]
+ 0x563B: 0x8851, # [2000]
+ 0x5649: 0x8852, # [2000]
+ 0x5676: 0x8853, # [2000]
+ 0x5666: 0x8854, # [2000]
+ 0xFA38: 0x8855, # CJK COMPATIBILITY IDEOGRAPH-FA38 [2000] [Unicode3.2]
+ 0x566F: 0x8856, # [2000]
+ 0x5671: 0x8857, # [2000]
+ 0x5672: 0x8858, # [2000]
+ 0x5699: 0x8859, # [2000]
+ 0x569E: 0x885A, # [2000]
+ 0x56A9: 0x885B, # [2000]
+ 0x56AC: 0x885C, # [2000]
+ 0x56B3: 0x885D, # [2000]
+ 0x56C9: 0x885E, # [2000]
+ 0x56CA: 0x885F, #