about summary refs log tree commit diff
path: root/.venv/lib/python3.12/site-packages/pypdf
diff options
context:
space:
mode:
Diffstat (limited to '.venv/lib/python3.12/site-packages/pypdf')
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/__init__.py49
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/_cmap.py520
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/_codecs/__init__.py61
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/_codecs/adobe_glyphs.py13970
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/_codecs/pdfdoc.py264
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/_codecs/std.py258
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/_codecs/symbol.py260
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/_codecs/zapfding.py261
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/_crypt_providers/__init__.py86
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/_crypt_providers/_base.py38
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/_crypt_providers/_cryptography.py118
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/_crypt_providers/_fallback.py93
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/_crypt_providers/_pycryptodome.py97
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/_doc_common.py1365
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/_encryption.py1168
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/_merger.py678
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/_page.py2458
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/_page_labels.py280
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/_protocols.py89
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/_reader.py1159
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/_text_extraction/__init__.py285
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/_text_extraction/_layout_mode/__init__.py16
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/_text_extraction/_layout_mode/_fixed_width_page.py381
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/_text_extraction/_layout_mode/_font.py112
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/_text_extraction/_layout_mode/_font_widths.py208
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/_text_extraction/_layout_mode/_text_state_manager.py213
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/_text_extraction/_layout_mode/_text_state_params.py127
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/_utils.py683
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/_version.py1
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/_writer.py3047
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/_xobj_image_helpers.py307
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/annotations/__init__.py45
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/annotations/_base.py27
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/annotations/_markup_annotations.py308
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/annotations/_non_markup_annotations.py109
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/constants.py762
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/errors.py62
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/filters.py910
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/generic/__init__.py464
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/generic/_base.py721
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/generic/_data_structures.py1616
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/generic/_fit.py168
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/generic/_image_inline.py235
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/generic/_outline.py33
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/generic/_rectangle.py132
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/generic/_utils.py180
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/generic/_viewerpref.py164
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/pagerange.py192
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/papersizes.py51
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/py.typed0
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/types.py83
-rw-r--r--.venv/lib/python3.12/site-packages/pypdf/xmp.py392
52 files changed, 35306 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/pypdf/__init__.py b/.venv/lib/python3.12/site-packages/pypdf/__init__.py
new file mode 100644
index 00000000..6a02b60d
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/__init__.py
@@ -0,0 +1,49 @@
+"""
+pypdf is a free and open-source pure-python PDF library capable of splitting,
+merging, cropping, and transforming the pages of PDF files. It can also add
+custom data, viewing options, and passwords to PDF files. pypdf can retrieve
+text and metadata from PDFs as well.
+
+You can read the full docs at https://pypdf.readthedocs.io/.
+"""
+
+from ._crypt_providers import crypt_provider
+from ._doc_common import DocumentInformation
+from ._encryption import PasswordType
+from ._merger import PdfMerger
+from ._page import PageObject, Transformation, mult
+from ._reader import PdfReader
+from ._version import __version__
+from ._writer import ObjectDeletionFlag, PdfWriter
+from .constants import ImageType
+from .pagerange import PageRange, parse_filename_page_ranges
+from .papersizes import PaperSize
+
+try:
+    import PIL
+
+    pil_version = PIL.__version__
+except ImportError:
+    pil_version = "none"
+
+_debug_versions = (
+    f"pypdf=={__version__}, crypt_provider={crypt_provider}, PIL={pil_version}"
+)
+
+__all__ = [
+    "__version__",
+    "_debug_versions",
+    "ImageType",
+    "mult",
+    "PageRange",
+    "PaperSize",
+    "DocumentInformation",
+    "ObjectDeletionFlag",
+    "parse_filename_page_ranges",
+    "PdfMerger",
+    "PdfReader",
+    "PdfWriter",
+    "Transformation",
+    "PageObject",
+    "PasswordType",
+]
diff --git a/.venv/lib/python3.12/site-packages/pypdf/_cmap.py b/.venv/lib/python3.12/site-packages/pypdf/_cmap.py
new file mode 100644
index 00000000..9a2d10a6
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/_cmap.py
@@ -0,0 +1,520 @@
+from binascii import unhexlify
+from math import ceil
+from typing import Any, Dict, List, Tuple, Union, cast
+
+from ._codecs import adobe_glyphs, charset_encoding
+from ._utils import b_, logger_error, logger_warning
+from .generic import (
+    DecodedStreamObject,
+    DictionaryObject,
+    IndirectObject,
+    NullObject,
+    StreamObject,
+)
+
+
+# code freely inspired from @twiggy ; see #711
+def build_char_map(
+    font_name: str, space_width: float, obj: DictionaryObject
+) -> Tuple[str, float, Union[str, Dict[int, str]], Dict[Any, Any], DictionaryObject]:
+    """
+    Determine information about a font.
+
+    Args:
+        font_name: font name as a string
+        space_width: default space width if no data is found.
+        obj: XObject or Page where you can find a /Resource dictionary
+
+    Returns:
+        Font sub-type, space_width criteria (50% of width), encoding, map character-map, font-dictionary.
+        The font-dictionary itself is suitable for the curious.
+    """
+    ft: DictionaryObject = obj["/Resources"]["/Font"][font_name]  # type: ignore
+    font_subtype, font_halfspace, font_encoding, font_map = build_char_map_from_dict(
+        space_width, ft
+    )
+    return font_subtype, font_halfspace, font_encoding, font_map, ft
+
+
+def build_char_map_from_dict(
+    space_width: float, ft: DictionaryObject
+) -> Tuple[str, float, Union[str, Dict[int, str]], Dict[Any, Any]]:
+    """
+    Determine information about a font.
+
+    Args:
+        space_width: default space with if no data found
+             (normally half the width of a character).
+        ft: Font Dictionary
+
+    Returns:
+        Font sub-type, space_width criteria(50% of width), encoding, map character-map.
+        The font-dictionary itself is suitable for the curious.
+    """
+    font_type: str = cast(str, ft["/Subtype"])
+
+    space_code = 32
+    encoding, space_code = parse_encoding(ft, space_code)
+    map_dict, space_code, int_entry = parse_to_unicode(ft, space_code)
+
+    # encoding can be either a string for decode
+    # (on 1,2 or a variable number of bytes) of a char table (for 1 byte only for me)
+    # if empty string, it means it is than encoding field is not present and
+    # we have to select the good encoding from cmap input data
+    if encoding == "":
+        if -1 not in map_dict or map_dict[-1] == 1:
+            # I have not been able to find any rule for no /Encoding nor /ToUnicode
+            # One example shows /Symbol,bold I consider 8 bits encoding default
+            encoding = "charmap"
+        else:
+            encoding = "utf-16-be"
+    # apply rule from PDF ref 1.7 §5.9.1, 1st bullet :
+    #   if cmap not empty encoding should be discarded
+    #   (here transformed into identity for those characters)
+    # if encoding is an str it is expected to be a identity translation
+    elif isinstance(encoding, dict):
+        for x in int_entry:
+            if x <= 255:
+                encoding[x] = chr(x)
+    try:
+        # override space_width with new params
+        space_width = _default_fonts_space_width[cast(str, ft["/BaseFont"])]
+    except Exception:
+        pass
+    # I consider the space_code is available on one byte
+    if isinstance(space_code, str):
+        try:  # one byte
+            sp = space_code.encode("charmap")[0]
+        except Exception:
+            sp = space_code.encode("utf-16-be")
+            sp = sp[0] + 256 * sp[1]
+    else:
+        sp = space_code
+    sp_width = compute_space_width(ft, sp, space_width)
+
+    return (
+        font_type,
+        float(sp_width / 2),
+        encoding,
+        # https://github.com/python/mypy/issues/4374
+        map_dict,
+    )
+
+
+# used when missing data, e.g. font def missing
+unknown_char_map: Tuple[str, float, Union[str, Dict[int, str]], Dict[Any, Any]] = (
+    "Unknown",
+    9999,
+    dict(zip(range(256), ["�"] * 256)),
+    {},
+)
+
+
+_predefined_cmap: Dict[str, str] = {
+    "/Identity-H": "utf-16-be",
+    "/Identity-V": "utf-16-be",
+    "/GB-EUC-H": "gbk",
+    "/GB-EUC-V": "gbk",
+    "/GBpc-EUC-H": "gb2312",
+    "/GBpc-EUC-V": "gb2312",
+    "/GBK-EUC-H": "gbk",
+    "/GBK-EUC-V": "gbk",
+    "/GBK2K-H": "gb18030",
+    "/GBK2K-V": "gb18030",
+    "/ETen-B5-H": "cp950",
+    "/ETen-B5-V": "cp950",
+    "/ETenms-B5-H": "cp950",
+    "/ETenms-B5-V": "cp950",
+    "/UniCNS-UTF16-H": "utf-16-be",
+    "/UniCNS-UTF16-V": "utf-16-be",
+    # UCS2 in code
+}
+
+# manually extracted from http://mirrors.ctan.org/fonts/adobe/afm/Adobe-Core35_AFMs-229.tar.gz
+_default_fonts_space_width: Dict[str, int] = {
+    "/Courier": 600,
+    "/Courier-Bold": 600,
+    "/Courier-BoldOblique": 600,
+    "/Courier-Oblique": 600,
+    "/Helvetica": 278,
+    "/Helvetica-Bold": 278,
+    "/Helvetica-BoldOblique": 278,
+    "/Helvetica-Oblique": 278,
+    "/Helvetica-Narrow": 228,
+    "/Helvetica-NarrowBold": 228,
+    "/Helvetica-NarrowBoldOblique": 228,
+    "/Helvetica-NarrowOblique": 228,
+    "/Times-Roman": 250,
+    "/Times-Bold": 250,
+    "/Times-BoldItalic": 250,
+    "/Times-Italic": 250,
+    "/Symbol": 250,
+    "/ZapfDingbats": 278,
+}
+
+
+def parse_encoding(
+    ft: DictionaryObject, space_code: int
+) -> Tuple[Union[str, Dict[int, str]], int]:
+    encoding: Union[str, List[str], Dict[int, str]] = []
+    if "/Encoding" not in ft:
+        try:
+            if "/BaseFont" in ft and cast(str, ft["/BaseFont"]) in charset_encoding:
+                encoding = dict(
+                    zip(range(256), charset_encoding[cast(str, ft["/BaseFont"])])
+                )
+            else:
+                encoding = "charmap"
+            return encoding, _default_fonts_space_width[cast(str, ft["/BaseFont"])]
+        except Exception:
+            if cast(str, ft["/Subtype"]) == "/Type1":
+                return "charmap", space_code
+            else:
+                return "", space_code
+    enc: Union(str, DictionaryObject) = ft["/Encoding"].get_object()  # type: ignore
+    if isinstance(enc, str):
+        try:
+            # already done : enc = NameObject.unnumber(enc.encode()).decode()
+            # for #xx decoding
+            if enc in charset_encoding:
+                encoding = charset_encoding[enc].copy()
+            elif enc in _predefined_cmap:
+                encoding = _predefined_cmap[enc]
+            elif "-UCS2-" in enc:
+                encoding = "utf-16-be"
+            else:
+                raise Exception("not found")
+        except Exception:
+            logger_error(f"Advanced encoding {enc} not implemented yet", __name__)
+            encoding = enc
+    elif isinstance(enc, DictionaryObject) and "/BaseEncoding" in enc:
+        try:
+            encoding = charset_encoding[cast(str, enc["/BaseEncoding"])].copy()
+        except Exception:
+            logger_error(
+                f"Advanced encoding {encoding} not implemented yet",
+                __name__,
+            )
+            encoding = charset_encoding["/StandardCoding"].copy()
+    else:
+        encoding = charset_encoding["/StandardCoding"].copy()
+    if "/Differences" in enc:
+        x: int = 0
+        o: Union[int, str]
+        for o in cast(DictionaryObject, cast(DictionaryObject, enc)["/Differences"]):
+            if isinstance(o, int):
+                x = o
+            else:  # isinstance(o,str):
+                try:
+                    encoding[x] = adobe_glyphs[o]  # type: ignore
+                except Exception:
+                    encoding[x] = o  # type: ignore
+                    if o == " ":
+                        space_code = x
+                x += 1
+    if isinstance(encoding, list):
+        encoding = dict(zip(range(256), encoding))
+    return encoding, space_code
+
+
+def parse_to_unicode(
+    ft: DictionaryObject, space_code: int
+) -> Tuple[Dict[Any, Any], int, List[int]]:
+    # will store all translation code
+    # and map_dict[-1] we will have the number of bytes to convert
+    map_dict: Dict[Any, Any] = {}
+
+    # will provide the list of cmap keys as int to correct encoding
+    int_entry: List[int] = []
+
+    if "/ToUnicode" not in ft:
+        if ft.get("/Subtype", "") == "/Type1":
+            return type1_alternative(ft, map_dict, space_code, int_entry)
+        else:
+            return {}, space_code, []
+    process_rg: bool = False
+    process_char: bool = False
+    multiline_rg: Union[
+        None, Tuple[int, int]
+    ] = None  # tuple = (current_char, remaining size) ; cf #1285 for example of file
+    cm = prepare_cm(ft)
+    for line in cm.split(b"\n"):
+        process_rg, process_char, multiline_rg = process_cm_line(
+            line.strip(b" \t"),
+            process_rg,
+            process_char,
+            multiline_rg,
+            map_dict,
+            int_entry,
+        )
+
+    for a, value in map_dict.items():
+        if value == " ":
+            space_code = a
+    return map_dict, space_code, int_entry
+
+
+def prepare_cm(ft: DictionaryObject) -> bytes:
+    tu = ft["/ToUnicode"]
+    cm: bytes
+    if isinstance(tu, StreamObject):
+        cm = b_(cast(DecodedStreamObject, ft["/ToUnicode"]).get_data())
+    elif isinstance(tu, str) and tu.startswith("/Identity"):
+        # the full range 0000-FFFF will be processed
+        cm = b"beginbfrange\n<0000> <0001> <0000>\nendbfrange"
+    if isinstance(cm, str):
+        cm = cm.encode()
+    # we need to prepare cm before due to missing return line in pdf printed
+    # to pdf from word
+    cm = (
+        cm.strip()
+        .replace(b"beginbfchar", b"\nbeginbfchar\n")
+        .replace(b"endbfchar", b"\nendbfchar\n")
+        .replace(b"beginbfrange", b"\nbeginbfrange\n")
+        .replace(b"endbfrange", b"\nendbfrange\n")
+        .replace(b"<<", b"\n{\n")  # text between << and >> not used but
+        .replace(b">>", b"\n}\n")  # some solution to find it back
+    )
+    ll = cm.split(b"<")
+    for i in range(len(ll)):
+        j = ll[i].find(b">")
+        if j >= 0:
+            if j == 0:
+                # string is empty: stash a placeholder here (see below)
+                # see https://github.com/py-pdf/pypdf/issues/1111
+                content = b"."
+            else:
+                content = ll[i][:j].replace(b" ", b"")
+            ll[i] = content + b" " + ll[i][j + 1 :]
+    cm = (
+        (b" ".join(ll))
+        .replace(b"[", b" [ ")
+        .replace(b"]", b" ]\n ")
+        .replace(b"\r", b"\n")
+    )
+    return cm
+
+
+def process_cm_line(
+    line: bytes,
+    process_rg: bool,
+    process_char: bool,
+    multiline_rg: Union[None, Tuple[int, int]],
+    map_dict: Dict[Any, Any],
+    int_entry: List[int],
+) -> Tuple[bool, bool, Union[None, Tuple[int, int]]]:
+    if line == b"" or line[0] == 37:  # 37 = %
+        return process_rg, process_char, multiline_rg
+    line = line.replace(b"\t", b" ")
+    if b"beginbfrange" in line:
+        process_rg = True
+    elif b"endbfrange" in line:
+        process_rg = False
+    elif b"beginbfchar" in line:
+        process_char = True
+    elif b"endbfchar" in line:
+        process_char = False
+    elif process_rg:
+        multiline_rg = parse_bfrange(line, map_dict, int_entry, multiline_rg)
+    elif process_char:
+        parse_bfchar(line, map_dict, int_entry)
+    return process_rg, process_char, multiline_rg
+
+
+def parse_bfrange(
+    line: bytes,
+    map_dict: Dict[Any, Any],
+    int_entry: List[int],
+    multiline_rg: Union[None, Tuple[int, int]],
+) -> Union[None, Tuple[int, int]]:
+    lst = [x for x in line.split(b" ") if x]
+    closure_found = False
+    if multiline_rg is not None:
+        fmt = b"%%0%dX" % (map_dict[-1] * 2)
+        a = multiline_rg[0]  # a, b not in the current line
+        b = multiline_rg[1]
+        for sq in lst[0:]:
+            if sq == b"]":
+                closure_found = True
+                break
+            map_dict[
+                unhexlify(fmt % a).decode(
+                    "charmap" if map_dict[-1] == 1 else "utf-16-be",
+                    "surrogatepass",
+                )
+            ] = unhexlify(sq).decode("utf-16-be", "surrogatepass")
+            int_entry.append(a)
+            a += 1
+    else:
+        a = int(lst[0], 16)
+        b = int(lst[1], 16)
+        nbi = max(len(lst[0]), len(lst[1]))
+        map_dict[-1] = ceil(nbi / 2)
+        fmt = b"%%0%dX" % (map_dict[-1] * 2)
+        if lst[2] == b"[":
+            for sq in lst[3:]:
+                if sq == b"]":
+                    closure_found = True
+                    break
+                map_dict[
+                    unhexlify(fmt % a).decode(
+                        "charmap" if map_dict[-1] == 1 else "utf-16-be",
+                        "surrogatepass",
+                    )
+                ] = unhexlify(sq).decode("utf-16-be", "surrogatepass")
+                int_entry.append(a)
+                a += 1
+        else:  # case without list
+            c = int(lst[2], 16)
+            fmt2 = b"%%0%dX" % max(4, len(lst[2]))
+            closure_found = True
+            while a <= b:
+                map_dict[
+                    unhexlify(fmt % a).decode(
+                        "charmap" if map_dict[-1] == 1 else "utf-16-be",
+                        "surrogatepass",
+                    )
+                ] = unhexlify(fmt2 % c).decode("utf-16-be", "surrogatepass")
+                int_entry.append(a)
+                a += 1
+                c += 1
+    return None if closure_found else (a, b)
+
+
+def parse_bfchar(line: bytes, map_dict: Dict[Any, Any], int_entry: List[int]) -> None:
+    lst = [x for x in line.split(b" ") if x]
+    map_dict[-1] = len(lst[0]) // 2
+    while len(lst) > 1:
+        map_to = ""
+        # placeholder (see above) means empty string
+        if lst[1] != b".":
+            map_to = unhexlify(lst[1]).decode(
+                "charmap" if len(lst[1]) < 4 else "utf-16-be", "surrogatepass"
+            )  # join is here as some cases where the code was split
+        map_dict[
+            unhexlify(lst[0]).decode(
+                "charmap" if map_dict[-1] == 1 else "utf-16-be", "surrogatepass"
+            )
+        ] = map_to
+        int_entry.append(int(lst[0], 16))
+        lst = lst[2:]
+
+
+def compute_space_width(
+    ft: DictionaryObject, space_code: int, space_width: float
+) -> float:
+    sp_width: float = space_width * 2.0  # default value
+    w = []
+    w1 = {}
+    st: int = 0
+    if "/DescendantFonts" in ft:  # ft["/Subtype"].startswith("/CIDFontType"):
+        ft1 = ft["/DescendantFonts"][0].get_object()  # type: ignore
+        try:
+            w1[-1] = cast(float, ft1["/DW"])
+        except Exception:
+            w1[-1] = 1000.0
+        if "/W" in ft1:
+            w = list(ft1["/W"])
+        else:
+            w = []
+        while len(w) > 0:
+            st = w[0] if isinstance(w[0], int) else w[0].get_object()
+            second = w[1].get_object()
+            if isinstance(second, int):
+                for x in range(st, second):
+                    w1[x] = w[2]
+                w = w[3:]
+            elif isinstance(second, list):
+                for y in second:
+                    w1[st] = y
+                    st += 1
+                w = w[2:]
+            else:
+                logger_warning(
+                    "unknown widths : \n" + (ft1["/W"]).__repr__(),
+                    __name__,
+                )
+                break
+        try:
+            sp_width = w1[space_code]
+        except Exception:
+            sp_width = (
+                w1[-1] / 2.0
+            )  # if using default we consider space will be only half size
+    elif "/Widths" in ft:
+        w = list(ft["/Widths"])  # type: ignore
+        try:
+            st = cast(int, ft["/FirstChar"])
+            en: int = cast(int, ft["/LastChar"])
+            if st > space_code or en < space_code:
+                raise Exception("Not in range")
+            if w[space_code - st] == 0:
+                raise Exception("null width")
+            sp_width = w[space_code - st]
+        except Exception:
+            if "/FontDescriptor" in ft and "/MissingWidth" in cast(
+                DictionaryObject, ft["/FontDescriptor"]
+            ):
+                sp_width = ft["/FontDescriptor"]["/MissingWidth"]  # type: ignore
+            else:
+                # will consider width of char as avg(width)/2
+                m = 0
+                cpt = 0
+                for x in w:
+                    if x > 0:
+                        m += x
+                        cpt += 1
+                sp_width = m / max(1, cpt) / 2
+
+    if isinstance(sp_width, IndirectObject):
+        # According to
+        # 'Table 122 - Entries common to all font descriptors (continued)'
+        # the MissingWidth should be a number, but according to #2286 it can
+        # be an indirect object
+        obj = sp_width.get_object()
+        if obj is None or isinstance(obj, NullObject):
+            return 0.0
+        return obj  # type: ignore
+
+    return sp_width
+
+
+def type1_alternative(
+    ft: DictionaryObject,
+    map_dict: Dict[Any, Any],
+    space_code: int,
+    int_entry: List[int],
+) -> Tuple[Dict[Any, Any], int, List[int]]:
+    if "/FontDescriptor" not in ft:
+        return map_dict, space_code, int_entry
+    ft_desc = cast(DictionaryObject, ft["/FontDescriptor"]).get("/FontFile")
+    if ft_desc is None:
+        return map_dict, space_code, int_entry
+    txt = ft_desc.get_object().get_data()
+    txt = txt.split(b"eexec\n")[0]  # only clear part
+    txt = txt.split(b"/Encoding")[1]  # to get the encoding part
+    lines = txt.replace(b"\r", b"\n").split(b"\n")
+    for li in lines:
+        if li.startswith(b"dup"):
+            words = [_w for _w in li.split(b" ") if _w != b""]
+            if len(words) > 3 and words[3] != b"put":
+                continue
+            try:
+                i = int(words[1])
+            except ValueError:  # pragma: no cover
+                continue
+            try:
+                v = adobe_glyphs[words[2].decode()]
+            except KeyError:
+                if words[2].startswith(b"/uni"):
+                    try:
+                        v = chr(int(words[2][4:], 16))
+                    except ValueError:  # pragma: no cover
+                        continue
+                else:
+                    continue
+            if words[2].decode() == b" ":
+                space_code = i
+            map_dict[chr(i)] = v
+            int_entry.append(i)
+    return map_dict, space_code, int_entry
diff --git a/.venv/lib/python3.12/site-packages/pypdf/_codecs/__init__.py b/.venv/lib/python3.12/site-packages/pypdf/_codecs/__init__.py
new file mode 100644
index 00000000..70d8e666
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/_codecs/__init__.py
@@ -0,0 +1,61 @@
+from typing import Dict, List
+
+from .adobe_glyphs import adobe_glyphs
+from .pdfdoc import _pdfdoc_encoding
+from .std import _std_encoding
+from .symbol import _symbol_encoding
+from .zapfding import _zapfding_encoding
+
+
+def fill_from_encoding(enc: str) -> List[str]:
+    lst: List[str] = []
+    for x in range(256):
+        try:
+            lst += (bytes((x,)).decode(enc),)
+        except Exception:
+            lst += (chr(x),)
+    return lst
+
+
+def rev_encoding(enc: List[str]) -> Dict[str, int]:
+    rev: Dict[str, int] = {}
+    for i in range(256):
+        char = enc[i]
+        if char == "\u0000":
+            continue
+        assert char not in rev, f"{char} at {i} already at {rev[char]}"
+        rev[char] = i
+    return rev
+
+
+_win_encoding = fill_from_encoding("cp1252")
+_mac_encoding = fill_from_encoding("mac_roman")
+
+
+_win_encoding_rev: Dict[str, int] = rev_encoding(_win_encoding)
+_mac_encoding_rev: Dict[str, int] = rev_encoding(_mac_encoding)
+_symbol_encoding_rev: Dict[str, int] = rev_encoding(_symbol_encoding)
+_zapfding_encoding_rev: Dict[str, int] = rev_encoding(_zapfding_encoding)
+_pdfdoc_encoding_rev: Dict[str, int] = rev_encoding(_pdfdoc_encoding)
+
+
+charset_encoding: Dict[str, List[str]] = {
+    "/StandardCoding": _std_encoding,
+    "/WinAnsiEncoding": _win_encoding,
+    "/MacRomanEncoding": _mac_encoding,
+    "/PDFDocEncoding": _pdfdoc_encoding,
+    "/Symbol": _symbol_encoding,
+    "/ZapfDingbats": _zapfding_encoding,
+}
+
+__all__ = [
+    "adobe_glyphs",
+    "_std_encoding",
+    "_symbol_encoding",
+    "_zapfding_encoding",
+    "_pdfdoc_encoding",
+    "_pdfdoc_encoding_rev",
+    "_win_encoding",
+    "_mac_encoding",
+    "charset_encoding",
+]
diff --git a/.venv/lib/python3.12/site-packages/pypdf/_codecs/adobe_glyphs.py b/.venv/lib/python3.12/site-packages/pypdf/_codecs/adobe_glyphs.py
new file mode 100644
index 00000000..19e2a99c
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/_codecs/adobe_glyphs.py
@@ -0,0 +1,13970 @@
+# https://raw.githubusercontent.com/adobe-type-tools/agl-aglfn/master/glyphlist.txt
+
+# converted manually to python
+# Extended with data from GlyphNameFormatter:
+#    https://github.com/LettError/glyphNameFormatter
+
+# -----------------------------------------------------------
+# Copyright 2002-2019 Adobe (http://www.adobe.com/).
+#
+# Redistribution and use in source and binary forms, with or
+# without modification, are permitted provided that the
+# following conditions are met:
+#
+# Redistributions of source code must retain the above
+# copyright notice, this list of conditions and the following
+# disclaimer.
+#
+# Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials
+# provided with the distribution.
+#
+# Neither the name of Adobe nor the names of its contributors
+# may be used to endorse or promote products derived from this
+# software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -----------------------------------------------------------
+# Name:          Adobe Glyph List
+# Table version: 2.0
+# Date:          September 20, 2002
+# URL:           https://github.com/adobe-type-tools/agl-aglfn
+#
+# Format: two semicolon-delimited fields:
+#   (1) glyph name--upper/lowercase letters and digits
+#   (2) Unicode scalar value--four uppercase hexadecimal digits
+#
+adobe_glyphs = {
+    "/A": "\u0041",
+    "/AA": "\uA732",
+    "/AE": "\u00C6",
+    "/AEacute": "\u01FC",
+    "/AEmacron": "\u01E2",
+    "/AEsmall": "\uF7E6",
+    "/AO": "\uA734",
+    "/AU": "\uA736",
+    "/AV": "\uA738",
+    "/AVhorizontalbar": "\uA73A",
+    "/AY": "\uA73C",
+    "/Aacute": "\u00C1",
+    "/Aacutesmall": "\uF7E1",
+    "/Abreve": "\u0102",
+    "/Abreveacute": "\u1EAE",
+    "/Abrevecyr": "\u04D0",
+    "/Abrevecyrillic": "\u04D0",
+    "/Abrevedotbelow": "\u1EB6",
+    "/Abrevegrave": "\u1EB0",
+    "/Abrevehoi": "\u1EB2",
+    "/Abrevehookabove": "\u1EB2",
+    "/Abrevetilde": "\u1EB4",
+    "/Acaron": "\u01CD",
+    "/Acircle": "\u24B6",
+    "/Acircleblack": "\u1F150",
+    "/Acircumflex": "\u00C2",
+    "/Acircumflexacute": "\u1EA4",
+    "/Acircumflexdotbelow": "\u1EAC",
+    "/Acircumflexgrave": "\u1EA6",
+    "/Acircumflexhoi": "\u1EA8",
+    "/Acircumflexhookabove": "\u1EA8",
+    "/Acircumflexsmall": "\uF7E2",
+    "/Acircumflextilde": "\u1EAA",
+    "/Acute": "\uF6C9",
+    "/Acutesmall": "\uF7B4",
+    "/Acyr": "\u0410",
+    "/Acyrillic": "\u0410",
+    "/Adblgrave": "\u0200",
+    "/Adieresis": "\u00C4",
+    "/Adieresiscyr": "\u04D2",
+    "/Adieresiscyrillic": "\u04D2",
+    "/Adieresismacron": "\u01DE",
+    "/Adieresissmall": "\uF7E4",
+    "/Adot": "\u0226",
+    "/Adotbelow": "\u1EA0",
+    "/Adotmacron": "\u01E0",
+    "/Agrave": "\u00C0",
+    "/Agravedbl": "\u0200",
+    "/Agravesmall": "\uF7E0",
+    "/Ahoi": "\u1EA2",
+    "/Ahookabove": "\u1EA2",
+    "/Aiecyr": "\u04D4",
+    "/Aiecyrillic": "\u04D4",
+    "/Ainvertedbreve": "\u0202",
+    "/Akbar": "\uFDF3",
+    "/Alayhe": "\uFDF7",
+    "/Allah": "\uFDF2",
+    "/Alpha": "\u0391",
+    "/Alphaacute": "\u1FBB",
+    "/Alphaasper": "\u1F09",
+    "/Alphaasperacute": "\u1F0D",
+    "/Alphaasperacuteiotasub": "\u1F8D",
+    "/Alphaaspergrave": "\u1F0B",
+    "/Alphaaspergraveiotasub": "\u1F8B",
+    "/Alphaasperiotasub": "\u1F89",
+    "/Alphaaspertilde": "\u1F0F",
+    "/Alphaaspertildeiotasub": "\u1F8F",
+    "/Alphabreve": "\u1FB8",
+    "/Alphagrave": "\u1FBA",
+    "/Alphaiotasub": "\u1FBC",
+    "/Alphalenis": "\u1F08",
+    "/Alphalenisacute": "\u1F0C",
+    "/Alphalenisacuteiotasub": "\u1F8C",
+    "/Alphalenisgrave": "\u1F0A",
+    "/Alphalenisgraveiotasub": "\u1F8A",
+    "/Alphalenisiotasub": "\u1F88",
+    "/Alphalenistilde": "\u1F0E",
+    "/Alphalenistildeiotasub": "\u1F8E",
+    "/Alphatonos": "\u0386",
+    "/Alphawithmacron": "\u1FB9",
+    "/Amacron": "\u0100",
+    "/Amonospace": "\uFF21",
+    "/Aogonek": "\u0104",
+    "/Aparens": "\u1F110",
+    "/Aring": "\u00C5",
+    "/Aringacute": "\u01FA",
+    "/Aringbelow": "\u1E00",
+    "/Aringsmall": "\uF7E5",
+    "/Asmall": "\uF761",
+    "/Asquare": "\u1F130",
+    "/Asquareblack": "\u1F170",
+    "/Astroke": "\u023A",
+    "/Atilde": "\u00C3",
+    "/Atildesmall": "\uF7E3",
+    "/Aturned": "\u2C6F",
+    "/Ayahend": "\u06DD",
+    "/Aybarmenian": "\u0531",
+    "/B": "\u0042",
+    "/Bcircle": "\u24B7",
+    "/Bcircleblack": "\u1F151",
+    "/Bdot": "\u1E02",
+    "/Bdotaccent": "\u1E02",
+    "/Bdotbelow": "\u1E04",
+    "/Becyr": "\u0411",
+    "/Becyrillic": "\u0411",
+    "/Benarmenian": "\u0532",
+    "/Beta": "\u0392",
+    "/Bflourish": "\uA796",
+    "/Bhook": "\u0181",
+    "/BismillahArRahmanArRaheem": "\uFDFD",
+    "/Blinebelow": "\u1E06",
+    "/Bmonospace": "\uFF22",
+    "/Bparens": "\u1F111",
+    "/Brevesmall": "\uF6F4",
+    "/Bscript": "\u212C",
+    "/Bsmall": "\uF762",
+    "/Bsquare": "\u1F131",
+    "/Bsquareblack": "\u1F171",
+    "/Bstroke": "\u0243",
+    "/Btopbar": "\u0182",
+    "/C": "\u0043",
+    "/CDcircle": "\u1F12D",
+    "/Caarmenian": "\u053E",
+    "/Cacute": "\u0106",
+    "/Caron": "\uF6CA",
+    "/Caronsmall": "\uF6F5",
+    "/Cbar": "\uA792",
+    "/Ccaron": "\u010C",
+    "/Ccedilla": "\u00C7",
+    "/Ccedillaacute": "\u1E08",
+    "/Ccedillasmall": "\uF7E7",
+    "/Ccircle": "\u24B8",
+    "/Ccircleblack": "\u1F152",
+    "/Ccircumflex": "\u0108",
+    "/Cdblstruck": "\u2102",
+    "/Cdot": "\u010A",
+    "/Cdotaccent": "\u010A",
+    "/Cdotreversed": "\uA73E",
+    "/Cedillasmall": "\uF7B8",
+    "/Cfraktur": "\u212D",
+    "/Chaarmenian": "\u0549",
+    "/Cheabkhasiancyrillic": "\u04BC",
+    "/Cheabkhcyr": "\u04BC",
+    "/Cheabkhtailcyr": "\u04BE",
+    "/Checyr": "\u0427",
+    "/Checyrillic": "\u0427",
+    "/Chedescenderabkhasiancyrillic": "\u04BE",
+    "/Chedescendercyrillic": "\u04B6",
+    "/Chedieresiscyr": "\u04F4",
+    "/Chedieresiscyrillic": "\u04F4",
+    "/Cheharmenian": "\u0543",
+    "/Chekhakascyr": "\u04CB",
+    "/Chekhakassiancyrillic": "\u04CB",
+    "/Chetailcyr": "\u04B6",
+    "/Chevertcyr": "\u04B8",
+    "/Cheverticalstrokecyrillic": "\u04B8",
+    "/Chi": "\u03A7",
+    "/Chook": "\u0187",
+    "/Circumflexsmall": "\uF6F6",
+    "/Citaliccircle": "\u1F12B",
+    "/Cmonospace": "\uFF23",
+    "/Coarmenian": "\u0551",
+    "/Con": "\uA76E",
+    "/Cparens": "\u1F112",
+    "/Csmall": "\uF763",
+    "/Csquare": "\u1F132",
+    "/Csquareblack": "\u1F172",
+    "/Cstretched": "\u0297",
+    "/Cstroke": "\u023B",
+    "/Cuatrillo": "\uA72C",
+    "/Cuatrillocomma": "\uA72E",
+    "/D": "\u0044",
+    "/DZ": "\u01F1",
+    "/DZcaron": "\u01C4",
+    "/Daarmenian": "\u0534",
+    "/Dafrican": "\u0189",
+    "/Dcaron": "\u010E",
+    "/Dcedilla": "\u1E10",
+    "/Dchecyr": "\u052C",
+    "/Dcircle": "\u24B9",
+    "/Dcircleblack": "\u1F153",
+    "/Dcircumflexbelow": "\u1E12",
+    "/Dcroat": "\u0110",
+    "/Ddblstruckitalic": "\u2145",
+    "/Ddot": "\u1E0A",
+    "/Ddotaccent": "\u1E0A",
+    "/Ddotbelow": "\u1E0C",
+    "/Decyr": "\u0414",
+    "/Decyrillic": "\u0414",
+    "/Deicoptic": "\u03EE",
+    "/Dekomicyr": "\u0500",
+    "/Delta": "\u2206",
+    "/Deltagreek": "\u0394",
+    "/Dhook": "\u018A",
+    "/Dieresis": "\uF6CB",
+    "/DieresisAcute": "\uF6CC",
+    "/DieresisGrave": "\uF6CD",
+    "/Dieresissmall": "\uF7A8",
+    "/Digamma": "\u03DC",
+    "/Digammagreek": "\u03DC",
+    "/Digammapamphylian": "\u0376",
+    "/Dinsular": "\uA779",
+    "/Djecyr": "\u0402",
+    "/Djecyrillic": "\u0402",
+    "/Djekomicyr": "\u0502",
+    "/Dlinebelow": "\u1E0E",
+    "/Dmonospace": "\uFF24",
+    "/Dotaccentsmall": "\uF6F7",
+    "/Dparens": "\u1F113",
+    "/Dslash": "\u0110",
+    "/Dsmall": "\uF764",
+    "/Dsquare": "\u1F133",
+    "/Dsquareblack": "\u1F173",
+    "/Dtopbar": "\u018B",
+    "/Dz": "\u01F2",
+    "/Dzcaron": "\u01C5",
+    "/Dzeabkhasiancyrillic": "\u04E0",
+    "/Dzeabkhcyr": "\u04E0",
+    "/Dzecyr": "\u0405",
+    "/Dzecyrillic": "\u0405",
+    "/Dzhecyr": "\u040F",
+    "/Dzhecyrillic": "\u040F",
+    "/Dzjekomicyr": "\u0506",
+    "/Dzzhecyr": "\u052A",
+    "/E": "\u0045",
+    "/Eacute": "\u00C9",
+    "/Eacutesmall": "\uF7E9",
+    "/Ebreve": "\u0114",
+    "/Ecaron": "\u011A",
+    "/Ecedilla": "\u0228",
+    "/Ecedillabreve": "\u1E1C",
+    "/Echarmenian": "\u0535",
+    "/Ecircle": "\u24BA",
+    "/Ecircleblack": "\u1F154",
+    "/Ecircumflex": "\u00CA",
+    "/Ecircumflexacute": "\u1EBE",
+    "/Ecircumflexbelow": "\u1E18",
+    "/Ecircumflexdotbelow": "\u1EC6",
+    "/Ecircumflexgrave": "\u1EC0",
+    "/Ecircumflexhoi": "\u1EC2",
+    "/Ecircumflexhookabove": "\u1EC2",
+    "/Ecircumflexsmall": "\uF7EA",
+    "/Ecircumflextilde": "\u1EC4",
+    "/Ecyrillic": "\u0404",
+    "/Edblgrave": "\u0204",
+    "/Edieresis": "\u00CB",
+    "/Edieresissmall": "\uF7EB",
+    "/Edot": "\u0116",
+    "/Edotaccent": "\u0116",
+    "/Edotbelow": "\u1EB8",
+    "/Efcyr": "\u0424",
+    "/Efcyrillic": "\u0424",
+    "/Egrave": "\u00C8",
+    "/Egravedbl": "\u0204",
+    "/Egravesmall": "\uF7E8",
+    "/Egyptain": "\uA724",
+    "/Egyptalef": "\uA722",
+    "/Eharmenian": "\u0537",
+    "/Ehoi": "\u1EBA",
+    "/Ehookabove": "\u1EBA",
+    "/Eightroman": "\u2167",
+    "/Einvertedbreve": "\u0206",
+    "/Eiotifiedcyr": "\u0464",
+    "/Eiotifiedcyrillic": "\u0464",
+    "/Elcyr": "\u041B",
+    "/Elcyrillic": "\u041B",
+    "/Elevenroman": "\u216A",
+    "/Elhookcyr": "\u0512",
+    "/Elmiddlehookcyr": "\u0520",
+    "/Elsharptailcyr": "\u04C5",
+    "/Eltailcyr": "\u052E",
+    "/Emacron": "\u0112",
+    "/Emacronacute": "\u1E16",
+    "/Emacrongrave": "\u1E14",
+    "/Emcyr": "\u041C",
+    "/Emcyrillic": "\u041C",
+    "/Emonospace": "\uFF25",
+    "/Emsharptailcyr": "\u04CD",
+    "/Encyr": "\u041D",
+    "/Encyrillic": "\u041D",
+    "/Endescendercyrillic": "\u04A2",
+    "/Eng": "\u014A",
+    "/Engecyr": "\u04A4",
+    "/Enghecyrillic": "\u04A4",
+    "/Enhookcyr": "\u04C7",
+    "/Enhookcyrillic": "\u04C7",
+    "/Enhookleftcyr": "\u0528",
+    "/Enmiddlehookcyr": "\u0522",
+    "/Ensharptailcyr": "\u04C9",
+    "/Entailcyr": "\u04A2",
+    "/Eogonek": "\u0118",
+    "/Eopen": "\u0190",
+    "/Eparens": "\u1F114",
+    "/Epsilon": "\u0395",
+    "/Epsilonacute": "\u1FC9",
+    "/Epsilonasper": "\u1F19",
+    "/Epsilonasperacute": "\u1F1D",
+    "/Epsilonaspergrave": "\u1F1B",
+    "/Epsilongrave": "\u1FC8",
+    "/Epsilonlenis": "\u1F18",
+    "/Epsilonlenisacute": "\u1F1C",
+    "/Epsilonlenisgrave": "\u1F1A",
+    "/Epsilontonos": "\u0388",
+    "/Ercyr": "\u0420",
+    "/Ercyrillic": "\u0420",
+    "/Ereversed": "\u018E",
+    "/Ereversedcyr": "\u042D",
+    "/Ereversedcyrillic": "\u042D",
+    "/Ereverseddieresiscyr": "\u04EC",
+    "/Ereversedopen": "\uA7AB",
+    "/Ertickcyr": "\u048E",
+    "/Escript": "\u2130",
+    "/Escyr": "\u0421",
+    "/Escyrillic": "\u0421",
+    "/Esdescendercyrillic": "\u04AA",
+    "/Esh": "\u01A9",
+    "/Esmall": "\uF765",
+    "/Esmallturned": "\u2C7B",
+    "/Esquare": "\u1F134",
+    "/Esquareblack": "\u1F174",
+    "/Estailcyr": "\u04AA",
+    "/Estroke": "\u0246",
+    "/Et": "\uA76A",
+    "/Eta": "\u0397",
+    "/Etaacute": "\u1FCB",
+    "/Etaasper": "\u1F29",
+    "/Etaasperacute": "\u1F2D",
+    "/Etaasperacuteiotasub": "\u1F9D",
+    "/Etaaspergrave": "\u1F2B",
+    "/Etaaspergraveiotasub": "\u1F9B",
+    "/Etaasperiotasub": "\u1F99",
+    "/Etaaspertilde": "\u1F2F",
+    "/Etaaspertildeiotasub": "\u1F9F",
+    "/Etagrave": "\u1FCA",
+    "/Etaiotasub": "\u1FCC",
+    "/Etalenis": "\u1F28",
+    "/Etalenisacute": "\u1F2C",
+    "/Etalenisacuteiotasub": "\u1F9C",
+    "/Etalenisgrave": "\u1F2A",
+    "/Etalenisgraveiotasub": "\u1F9A",
+    "/Etalenisiotasub": "\u1F98",
+    "/Etalenistilde": "\u1F2E",
+    "/Etalenistildeiotasub": "\u1F9E",
+    "/Etarmenian": "\u0538",
+    "/Etatonos": "\u0389",
+    "/Eth": "\u00D0",
+    "/Ethsmall": "\uF7F0",
+    "/Etilde": "\u1EBC",
+    "/Etildebelow": "\u1E1A",
+    "/Eukrcyr": "\u0404",
+    "/Euro": "\u20AC",
+    "/Ezh": "\u01B7",
+    "/Ezhcaron": "\u01EE",
+    "/Ezhreversed": "\u01B8",
+    "/F": "\u0046",
+    "/Fcircle": "\u24BB",
+    "/Fcircleblack": "\u1F155",
+    "/Fdot": "\u1E1E",
+    "/Fdotaccent": "\u1E1E",
+    "/Feharmenian": "\u0556",
+    "/Feicoptic": "\u03E4",
+    "/Fhook": "\u0191",
+    "/Finsular": "\uA77B",
+    "/Fitacyr": "\u0472",
+    "/Fitacyrillic": "\u0472",
+    "/Fiveroman": "\u2164",
+    "/Fmonospace": "\uFF26",
+    "/Fourroman": "\u2163",
+    "/Fparens": "\u1F115",
+    "/Fscript": "\u2131",
+    "/Fsmall": "\uF766",
+    "/Fsquare": "\u1F135",
+    "/Fsquareblack": "\u1F175",
+    "/Fstroke": "\uA798",
+    "/Fturned": "\u2132",
+    "/G": "\u0047",
+    "/GBsquare": "\u3387",
+    "/Gacute": "\u01F4",
+    "/Gamma": "\u0393",
+    "/Gammaafrican": "\u0194",
+    "/Gammadblstruck": "\u213E",
+    "/Gangiacoptic": "\u03EA",
+    "/Gbreve": "\u011E",
+    "/Gcaron": "\u01E6",
+    "/Gcedilla": "\u0122",
+    "/Gcircle": "\u24BC",
+    "/Gcircleblack": "\u1F156",
+    "/Gcircumflex": "\u011C",
+    "/Gcommaaccent": "\u0122",
+    "/Gdot": "\u0120",
+    "/Gdotaccent": "\u0120",
+    "/Gecyr": "\u0413",
+    "/Gecyrillic": "\u0413",
+    "/Gehookcyr": "\u0494",
+    "/Gehookstrokecyr": "\u04FA",
+    "/Germandbls": "\u1E9E",
+    "/Gestrokecyr": "\u0492",
+    "/Getailcyr": "\u04F6",
+    "/Geupcyr": "\u0490",
+    "/Ghadarmenian": "\u0542",
+    "/Ghemiddlehookcyrillic": "\u0494",
+    "/Ghestrokecyrillic": "\u0492",
+    "/Gheupturncyrillic": "\u0490",
+    "/Ghook": "\u0193",
+    "/Ghooksmall": "\u029B",
+    "/Gimarmenian": "\u0533",
+    "/Ginsular": "\uA77D",
+    "/Ginsularturned": "\uA77E",
+    "/Gjecyr": "\u0403",
+    "/Gjecyrillic": "\u0403",
+    "/Glottalstop": "\u0241",
+    "/Gmacron": "\u1E20",
+    "/Gmonospace": "\uFF27",
+    "/Gobliquestroke": "\uA7A0",
+    "/Gparens": "\u1F116",
+    "/Grave": "\uF6CE",
+    "/Gravesmall": "\uF760",
+    "/Gsmall": "\uF767",
+    "/Gsmallhook": "\u029B",
+    "/Gsquare": "\u1F136",
+    "/Gsquareblack": "\u1F176",
+    "/Gstroke": "\u01E4",
+    "/Gturnedsans": "\u2141",
+    "/H": "\u0048",
+    "/H18533": "\u25CF",
+    "/H18543": "\u25AA",
+    "/H18551": "\u25AB",
+    "/H22073": "\u25A1",
+    "/HPsquare": "\u33CB",
+    "/HVsquare": "\u1F14A",
+    "/Haabkhasiancyrillic": "\u04A8",
+    "/Haabkhcyr": "\u04A8",
+    "/Hacyr": "\u0425",
+    "/Hadescendercyrillic": "\u04B2",
+    "/Hahookcyr": "\u04FC",
+    "/Hardcyr": "\u042A",
+    "/Hardsigncyrillic": "\u042A",
+    "/Hastrokecyr": "\u04FE",
+    "/Hbar": "\u0126",
+    "/Hbrevebelow": "\u1E2A",
+    "/Hcaron": "\u021E",
+    "/Hcedilla": "\u1E28",
+    "/Hcircle": "\u24BD",
+    "/Hcircleblack": "\u1F157",
+    "/Hcircumflex": "\u0124",
+    "/Hdblstruck": "\u210D",
+    "/Hdescender": "\u2C67",
+    "/Hdieresis": "\u1E26",
+    "/Hdot": "\u1E22",
+    "/Hdotaccent": "\u1E22",
+    "/Hdotbelow": "\u1E24",
+    "/Heng": "\uA726",
+    "/Heta": "\u0370",
+    "/Hfraktur": "\u210C",
+    "/Hgfullwidth": "\u32CC",
+    "/Hhalf": "\u2C75",
+    "/Hhook": "\uA7AA",
+    "/Hmonospace": "\uFF28",
+    "/Hoarmenian": "\u0540",
+    "/HonAA": "\u0611",
+    "/HonRA": "\u0612",
+    "/HonSAW": "\u0610",
+    "/Horicoptic": "\u03E8",
+    "/Hparens": "\u1F117",
+    "/Hscript": "\u210B",
+    "/Hsmall": "\uF768",
+    "/Hsquare": "\u1F137",
+    "/Hsquareblack": "\u1F177",
+    "/Hstrokemod": "\uA7F8",
+    "/Hturned": "\uA78D",
+    "/Hungarumlaut": "\uF6CF",
+    "/Hungarumlautsmall": "\uF6F8",
+    "/Hwair": "\u01F6",
+    "/Hzsquare": "\u3390",
+    "/I": "\u0049",
+    "/IAcyrillic": "\u042F",
+    "/ICsquareblack": "\u1F18B",
+    "/IJ": "\u0132",
+    "/IUcyrillic": "\u042E",
+    "/Iacute": "\u00CD",
+    "/Iacutesmall": "\uF7ED",
+    "/Ibreve": "\u012C",
+    "/Icaron": "\u01CF",
+    "/Icircle": "\u24BE",
+    "/Icircleblack": "\u1F158",
+    "/Icircumflex": "\u00CE",
+    "/Icircumflexsmall": "\uF7EE",
+    "/Icyr": "\u0418",
+    "/Icyrillic": "\u0406",
+    "/Idblgrave": "\u0208",
+    "/Idieresis": "\u00CF",
+    "/Idieresisacute": "\u1E2E",
+    "/Idieresiscyr": "\u04E4",
+    "/Idieresiscyrillic": "\u04E4",
+    "/Idieresissmall": "\uF7EF",
+    "/Idot": "\u0130",
+    "/Idotaccent": "\u0130",
+    "/Idotbelow": "\u1ECA",
+    "/Iebrevecyr": "\u04D6",
+    "/Iebrevecyrillic": "\u04D6",
+    "/Iecyr": "\u0415",
+    "/Iecyrillic": "\u0415",
+    "/Iegravecyr": "\u0400",
+    "/Ifraktur": "\u2111",
+    "/Igrave": "\u00CC",
+    "/Igravecyr": "\u040D",
+    "/Igravedbl": "\u0208",
+    "/Igravesmall": "\uF7EC",
+    "/Ihoi": "\u1EC8",
+    "/Ihookabove": "\u1EC8",
+    "/Iicyrillic": "\u0418",
+    "/Iinvertedbreve": "\u020A",
+    "/Iishortcyrillic": "\u0419",
+    "/Imacron": "\u012A",
+    "/Imacroncyr": "\u04E2",
+    "/Imacroncyrillic": "\u04E2",
+    "/Imonospace": "\uFF29",
+    "/Iniarmenian": "\u053B",
+    "/Iocyr": "\u0401",
+    "/Iocyrillic": "\u0401",
+    "/Iogonek": "\u012E",
+    "/Iota": "\u0399",
+    "/Iotaacute": "\u1FDB",
+    "/Iotaafrican": "\u0196",
+    "/Iotaasper": "\u1F39",
+    "/Iotaasperacute": "\u1F3D",
+    "/Iotaaspergrave": "\u1F3B",
+    "/Iotaaspertilde": "\u1F3F",
+    "/Iotabreve": "\u1FD8",
+    "/Iotadieresis": "\u03AA",
+    "/Iotagrave": "\u1FDA",
+    "/Iotalenis": "\u1F38",
+    "/Iotalenisacute": "\u1F3C",
+    "/Iotalenisgrave": "\u1F3A",
+    "/Iotalenistilde": "\u1F3E",
+    "/Iotatonos": "\u038A",
+    "/Iotawithmacron": "\u1FD9",
+    "/Iparens": "\u1F118",
+    "/Is": "\uA76C",
+    "/Iscript": "\u2110",
+    "/Ishortcyr": "\u0419",
+    "/Ishortsharptailcyr": "\u048A",
+    "/Ismall": "\uF769",
+    "/Isquare": "\u1F138",
+    "/Isquareblack": "\u1F178",
+    "/Istroke": "\u0197",
+    "/Itilde": "\u0128",
+    "/Itildebelow": "\u1E2C",
+    "/Iukrcyr": "\u0406",
+    "/Izhitsacyr": "\u0474",
+    "/Izhitsacyrillic": "\u0474",
+    "/Izhitsadblgravecyrillic": "\u0476",
+    "/Izhitsagravedblcyr": "\u0476",
+    "/J": "\u004A",
+    "/Jaarmenian": "\u0541",
+    "/Jallajalalouhou": "\uFDFB",
+    "/Jcircle": "\u24BF",
+    "/Jcircleblack": "\u1F159",
+    "/Jcircumflex": "\u0134",
+    "/Jcrossed-tail": "\uA7B2",
+    "/Jecyr": "\u0408",
+    "/Jecyrillic": "\u0408",
+    "/Jheharmenian": "\u054B",
+    "/Jmonospace": "\uFF2A",
+    "/Jparens": "\u1F119",
+    "/Jsmall": "\uF76A",
+    "/Jsquare": "\u1F139",
+    "/Jsquareblack": "\u1F179",
+    "/Jstroke": "\u0248",
+    "/K": "\u004B",
+    "/KBsquare": "\u3385",
+    "/KKsquare": "\u33CD",
+    "/KORONIS": "\u1FBD",
+    "/Kaaleutcyr": "\u051E",
+    "/Kabashkcyr": "\u04A0",
+    "/Kabashkircyrillic": "\u04A0",
+    "/Kacute": "\u1E30",
+    "/Kacyr": "\u041A",
+    "/Kacyrillic": "\u041A",
+    "/Kadescendercyrillic": "\u049A",
+    "/Kahookcyr": "\u04C3",
+    "/Kahookcyrillic": "\u04C3",
+    "/Kaisymbol": "\u03CF",
+    "/Kappa": "\u039A",
+    "/Kastrokecyr": "\u049E",
+    "/Kastrokecyrillic": "\u049E",
+    "/Katailcyr": "\u049A",
+    "/Kaverticalstrokecyr": "\u049C",
+    "/Kaverticalstrokecyrillic": "\u049C",
+    "/Kcaron": "\u01E8",
+    "/Kcedilla": "\u0136",
+    "/Kcircle": "\u24C0",
+    "/Kcircleblack": "\u1F15A",
+    "/Kcommaaccent": "\u0136",
+    "/Kdescender": "\u2C69",
+    "/Kdiagonalstroke": "\uA742",
+    "/Kdotbelow": "\u1E32",
+    "/Keharmenian": "\u0554",
+    "/Kenarmenian": "\u053F",
+    "/Khacyrillic": "\u0425",
+    "/Kheicoptic": "\u03E6",
+    "/Khook": "\u0198",
+    "/Kjecyr": "\u040C",
+    "/Kjecyrillic": "\u040C",
+    "/Klinebelow": "\u1E34",
+    "/Kmonospace": "\uFF2B",
+    "/Kobliquestroke": "\uA7A2",
+    "/Koppa": "\u03DE",
+    "/Koppaarchaic": "\u03D8",
+    "/Koppacyr": "\u0480",
+    "/Koppacyrillic": "\u0480",
+    "/Koppagreek": "\u03DE",
+    "/Kparens": "\u1F11A",
+    "/Ksicyr": "\u046E",
+    "/Ksicyrillic": "\u046E",
+    "/Ksmall": "\uF76B",
+    "/Ksquare": "\u1F13A",
+    "/Ksquareblack": "\u1F17A",
+    "/Kstroke": "\uA740",
+    "/Kstrokediagonalstroke": "\uA744",
+    "/Kturned": "\uA7B0",
+    "/L": "\u004C",
+    "/LJ": "\u01C7",
+    "/LL": "\uF6BF",
+    "/LLwelsh": "\u1EFA",
+    "/LTDfullwidth": "\u32CF",
+    "/Lacute": "\u0139",
+    "/Lambda": "\u039B",
+    "/Lbar": "\u023D",
+    "/Lbelt": "\uA7AD",
+    "/Lbroken": "\uA746",
+    "/Lcaron": "\u013D",
+    "/Lcedilla": "\u013B",
+    "/Lcircle": "\u24C1",
+    "/Lcircleblack": "\u1F15B",
+    "/Lcircumflexbelow": "\u1E3C",
+    "/Lcommaaccent": "\u013B",
+    "/Ldblbar": "\u2C60",
+    "/Ldot": "\u013F",
+    "/Ldotaccent": "\u013F",
+    "/Ldotbelow": "\u1E36",
+    "/Ldotbelowmacron": "\u1E38",
+    "/Lhacyr": "\u0514",
+    "/Liwnarmenian": "\u053C",
+    "/Lj": "\u01C8",
+    "/Ljecyr": "\u0409",
+    "/Ljecyrillic": "\u0409",
+    "/Ljekomicyr": "\u0508",
+    "/Llinebelow": "\u1E3A",
+    "/Lmacrondot": "\u1E38",
+    "/Lmiddletilde": "\u2C62",
+    "/Lmonospace": "\uFF2C",
+    "/Lparens": "\u1F11B",
+    "/Lreversedsans": "\u2143",
+    "/Lscript": "\u2112",
+    "/Lslash": "\u0141",
+    "/Lslashsmall": "\uF6F9",
+    "/Lsmall": "\uF76C",
+    "/Lsquare": "\u1F13B",
+    "/Lsquareblack": "\u1F17B",
+    "/Lstroke": "\uA748",
+    "/Lturned": "\uA780",
+    "/Lturnedsans": "\u2142",
+    "/M": "\u004D",
+    "/MBsquare": "\u3386",
+    "/MVsquare": "\u1F14B",
+    "/Macron": "\uF6D0",
+    "/Macronsmall": "\uF7AF",
+    "/Macute": "\u1E3E",
+    "/Mcircle": "\u24C2",
+    "/Mcircleblack": "\u1F15C",
+    "/Mdot": "\u1E40",
+    "/Mdotaccent": "\u1E40",
+    "/Mdotbelow": "\u1E42",
+    "/Menarmenian": "\u0544",
+    "/Mhook": "\u2C6E",
+    "/Mmonospace": "\uFF2D",
+    "/Mohammad": "\uFDF4",
+    "/Mparens": "\u1F11C",
+    "/Mscript": "\u2133",
+    "/Msmall": "\uF76D",
+    "/Msquare": "\u1F13C",
+    "/Msquareblack": "\u1F17C",
+    "/Mturned": "\u019C",
+    "/Mturnedsmall": "\uA7FA",
+    "/Mu": "\u039C",
+    "/N": "\u004E",
+    "/NJ": "\u01CA",
+    "/Nacute": "\u0143",
+    "/Ncaron": "\u0147",
+    "/Ncedilla": "\u0145",
+    "/Ncircle": "\u24C3",
+    "/Ncircleblack": "\u1F15D",
+    "/Ncircumflexbelow": "\u1E4A",
+    "/Ncommaaccent": "\u0145",
+    "/Ndblstruck": "\u2115",
+    "/Ndescender": "\uA790",
+    "/Ndot": "\u1E44",
+    "/Ndotaccent": "\u1E44",
+    "/Ndotbelow": "\u1E46",
+    "/Ngrave": "\u01F8",
+    "/Nhookleft": "\u019D",
+    "/Nineroman": "\u2168",
+    "/Nj": "\u01CB",
+    "/Njecyr": "\u040A",
+    "/Njecyrillic": "\u040A",
+    "/Njekomicyr": "\u050A",
+    "/Nlinebelow": "\u1E48",
+    "/Nlongrightleg": "\u0220",
+    "/Nmonospace": "\uFF2E",
+    "/Nobliquestroke": "\uA7A4",
+    "/Nowarmenian": "\u0546",
+    "/Nparens": "\u1F11D",
+    "/Nsmall": "\uF76E",
+    "/Nsquare": "\u1F13D",
+    "/Nsquareblack": "\u1F17D",
+    "/Ntilde": "\u00D1",
+    "/Ntildesmall": "\uF7F1",
+    "/Nu": "\u039D",
+    "/O": "\u004F",
+    "/OE": "\u0152",
+    "/OEsmall": "\uF6FA",
+    "/OO": "\uA74E",
+    "/Oacute": "\u00D3",
+    "/Oacutesmall": "\uF7F3",
+    "/Obar": "\u019F",
+    "/Obarcyr": "\u04E8",
+    "/Obardieresiscyr": "\u04EA",
+    "/Obarredcyrillic": "\u04E8",
+    "/Obarreddieresiscyrillic": "\u04EA",
+    "/Obreve": "\u014E",
+    "/Ocaron": "\u01D1",
+    "/Ocenteredtilde": "\u019F",
+    "/Ocircle": "\u24C4",
+    "/Ocircleblack": "\u1F15E",
+    "/Ocircumflex": "\u00D4",
+    "/Ocircumflexacute": "\u1ED0",
+    "/Ocircumflexdotbelow": "\u1ED8",
+    "/Ocircumflexgrave": "\u1ED2",
+    "/Ocircumflexhoi": "\u1ED4",
+    "/Ocircumflexhookabove": "\u1ED4",
+    "/Ocircumflexsmall": "\uF7F4",
+    "/Ocircumflextilde": "\u1ED6",
+    "/Ocyr": "\u041E",
+    "/Ocyrillic": "\u041E",
+    "/Odblacute": "\u0150",
+    "/Odblgrave": "\u020C",
+    "/Odieresis": "\u00D6",
+    "/Odieresiscyr": "\u04E6",
+    "/Odieresiscyrillic": "\u04E6",
+    "/Odieresismacron": "\u022A",
+    "/Odieresissmall": "\uF7F6",
+    "/Odot": "\u022E",
+    "/Odotbelow": "\u1ECC",
+    "/Odotmacron": "\u0230",
+    "/Ogoneksmall": "\uF6FB",
+    "/Ograve": "\u00D2",
+    "/Ogravedbl": "\u020C",
+    "/Ogravesmall": "\uF7F2",
+    "/Oharmenian": "\u0555",
+    "/Ohm": "\u2126",
+    "/Ohoi": "\u1ECE",
+    "/Ohookabove": "\u1ECE",
+    "/Ohorn": "\u01A0",
+    "/Ohornacute": "\u1EDA",
+    "/Ohorndotbelow": "\u1EE2",
+    "/Ohorngrave": "\u1EDC",
+    "/Ohornhoi": "\u1EDE",
+    "/Ohornhookabove": "\u1EDE",
+    "/Ohorntilde": "\u1EE0",
+    "/Ohungarumlaut": "\u0150",
+    "/Oi": "\u01A2",
+    "/Oinvertedbreve": "\u020E",
+    "/Oloop": "\uA74C",
+    "/Omacron": "\u014C",
+    "/Omacronacute": "\u1E52",
+    "/Omacrongrave": "\u1E50",
+    "/Omega": "\u2126",
+    "/Omegaacute": "\u1FFB",
+    "/Omegaasper": "\u1F69",
+    "/Omegaasperacute": "\u1F6D",
+    "/Omegaasperacuteiotasub": "\u1FAD",
+    "/Omegaaspergrave": "\u1F6B",
+    "/Omegaaspergraveiotasub": "\u1FAB",
+    "/Omegaasperiotasub": "\u1FA9",
+    "/Omegaaspertilde": "\u1F6F",
+    "/Omegaaspertildeiotasub": "\u1FAF",
+    "/Omegacyr": "\u0460",
+    "/Omegacyrillic": "\u0460",
+    "/Omegagrave": "\u1FFA",
+    "/Omegagreek": "\u03A9",
+    "/Omegaiotasub": "\u1FFC",
+    "/Omegalenis": "\u1F68",
+    "/Omegalenisacute": "\u1F6C",
+    "/Omegalenisacuteiotasub": "\u1FAC",
+    "/Omegalenisgrave": "\u1F6A",
+    "/Omegalenisgraveiotasub": "\u1FAA",
+    "/Omegalenisiotasub": "\u1FA8",
+    "/Omegalenistilde": "\u1F6E",
+    "/Omegalenistildeiotasub": "\u1FAE",
+    "/Omegaroundcyr": "\u047A",
+    "/Omegaroundcyrillic": "\u047A",
+    "/Omegatitlocyr": "\u047C",
+    "/Omegatitlocyrillic": "\u047C",
+    "/Omegatonos": "\u038F",
+    "/Omicron": "\u039F",
+    "/Omicronacute": "\u1FF9",
+    "/Omicronasper": "\u1F49",
+    "/Omicronasperacute": "\u1F4D",
+    "/Omicronaspergrave": "\u1F4B",
+    "/Omicrongrave": "\u1FF8",
+    "/Omicronlenis": "\u1F48",
+    "/Omicronlenisacute": "\u1F4C",
+    "/Omicronlenisgrave": "\u1F4A",
+    "/Omicrontonos": "\u038C",
+    "/Omonospace": "\uFF2F",
+    "/Oneroman": "\u2160",
+    "/Oogonek": "\u01EA",
+    "/Oogonekmacron": "\u01EC",
+    "/Oopen": "\u0186",
+    "/Oparens": "\u1F11E",
+    "/Oslash": "\u00D8",
+    "/Oslashacute": "\u01FE",
+    "/Oslashsmall": "\uF7F8",
+    "/Osmall": "\uF76F",
+    "/Osquare": "\u1F13E",
+    "/Osquareblack": "\u1F17E",
+    "/Ostroke": "\uA74A",
+    "/Ostrokeacute": "\u01FE",
+    "/Otcyr": "\u047E",
+    "/Otcyrillic": "\u047E",
+    "/Otilde": "\u00D5",
+    "/Otildeacute": "\u1E4C",
+    "/Otildedieresis": "\u1E4E",
+    "/Otildemacron": "\u022C",
+    "/Otildesmall": "\uF7F5",
+    "/Ou": "\u0222",
+    "/P": "\u0050",
+    "/PAsquareblack": "\u1F18C",
+    "/PPVsquare": "\u1F14E",
+    "/Pacute": "\u1E54",
+    "/Palochkacyr": "\u04C0",
+    "/Pcircle": "\u24C5",
+    "/Pcircleblack": "\u1F15F",
+    "/Pcrosssquareblack": "\u1F18A",
+    "/Pdblstruck": "\u2119",
+    "/Pdot": "\u1E56",
+    "/Pdotaccent": "\u1E56",
+    "/Pecyr": "\u041F",
+    "/Pecyrillic": "\u041F",
+    "/Peharmenian": "\u054A",
+    "/Pehookcyr": "\u04A6",
+    "/Pemiddlehookcyrillic": "\u04A6",
+    "/Petailcyr": "\u0524",
+    "/Pflourish": "\uA752",
+    "/Phi": "\u03A6",
+    "/Phook": "\u01A4",
+    "/Pi": "\u03A0",
+    "/Pidblstruck": "\u213F",
+    "/Piwrarmenian": "\u0553",
+    "/Pmonospace": "\uFF30",
+    "/Pparens": "\u1F11F",
+    "/Psi": "\u03A8",
+    "/Psicyr": "\u0470",
+    "/Psicyrillic": "\u0470",
+    "/Psmall": "\uF770",
+    "/Psquare": "\u1F13F",
+    "/Psquareblack": "\u1F17F",
+    "/Pstroke": "\u2C63",
+    "/Pstrokedescender": "\uA750",
+    "/Ptail": "\uA754",
+    "/Q": "\u0051",
+    "/Qacyr": "\u051A",
+    "/QalaUsedAsKoranicStopSign": "\uFDF1",
+    "/Qcircle": "\u24C6",
+    "/Qcircleblack": "\u1F160",
+    "/Qdblstruck": "\u211A",
+    "/Qdiagonalstroke": "\uA758",
+    "/Qmonospace": "\uFF31",
+    "/Qparens": "\u1F120",
+    "/Qrotated": "\u213A",
+    "/Qsmall": "\uF771",
+    "/Qsmallhooktail": "\u024A",
+    "/Qsquare": "\u1F140",
+    "/Qsquareblack": "\u1F180",
+    "/Qstrokedescender": "\uA756",
+    "/R": "\u0052",
+    "/Raarmenian": "\u054C",
+    "/Racute": "\u0154",
+    "/Rasoul": "\uFDF6",
+    "/Rcaron": "\u0158",
+    "/Rcedilla": "\u0156",
+    "/Rcircle": "\u24C7",
+    "/Rcircleblack": "\u1F161",
+    "/Rcommaaccent": "\u0156",
+    "/Rdblgrave": "\u0210",
+    "/Rdblstruck": "\u211D",
+    "/Rdot": "\u1E58",
+    "/Rdotaccent": "\u1E58",
+    "/Rdotbelow": "\u1E5A",
+    "/Rdotbelowmacron": "\u1E5C",
+    "/Reharmenian": "\u0550",
+    "/Reverseddottedsigmalunatesymbol": "\u03FF",
+    "/Reversedzecyr": "\u0510",
+    "/Rfraktur": "\u211C",
+    "/Rgravedbl": "\u0210",
+    "/Rhacyr": "\u0516",
+    "/Rho": "\u03A1",
+    "/Rhoasper": "\u1FEC",
+    "/Ringsmall": "\uF6FC",
+    "/Rinsular": "\uA782",
+    "/Rinvertedbreve": "\u0212",
+    "/Rinvertedsmall": "\u0281",
+    "/Ritaliccircle": "\u1F12C",
+    "/Rlinebelow": "\u1E5E",
+    "/Rmacrondot": "\u1E5C",
+    "/Rmonospace": "\uFF32",
+    "/Robliquestroke": "\uA7A6",
+    "/Rparens": "\u1F121",
+    "/Rrotunda": "\uA75A",
+    "/Rscript": "\u211B",
+    "/Rsmall": "\uF772",
+    "/Rsmallinverted": "\u0281",
+    "/Rsmallinvertedsuperior": "\u02B6",
+    "/Rsquare": "\u1F141",
+    "/Rsquareblack": "\u1F181",
+    "/Rstroke": "\u024C",
+    "/Rsupinvertedmod": "\u02B6",
+    "/Rtail": "\u2C64",
+    "/RubElHizbstart": "\u06DE",
+    "/Rumrotunda": "\uA75C",
+    "/Rumsmall": "\uA776",
+    "/S": "\u0053",
+    "/SAsquareblack": "\u1F18D",
+    "/SDsquare": "\u1F14C",
+    "/SF010000": "\u250C",
+    "/SF020000": "\u2514",
+    "/SF030000": "\u2510",
+    "/SF040000": "\u2518",
+    "/SF050000": "\u253C",
+    "/SF060000": "\u252C",
+    "/SF070000": "\u2534",
+    "/SF080000": "\u251C",
+    "/SF090000": "\u2524",
+    "/SF100000": "\u2500",
+    "/SF110000": "\u2502",
+    "/SF190000": "\u2561",
+    "/SF200000": "\u2562",
+    "/SF210000": "\u2556",
+    "/SF220000": "\u2555",
+    "/SF230000": "\u2563",
+    "/SF240000": "\u2551",
+    "/SF250000": "\u2557",
+    "/SF260000": "\u255D",
+    "/SF270000": "\u255C",
+    "/SF280000": "\u255B",
+    "/SF360000": "\u255E",
+    "/SF370000": "\u255F",
+    "/SF380000": "\u255A",
+    "/SF390000": "\u2554",
+    "/SF400000": "\u2569",
+    "/SF410000": "\u2566",
+    "/SF420000": "\u2560",
+    "/SF430000": "\u2550",
+    "/SF440000": "\u256C",
+    "/SF450000": "\u2567",
+    "/SF460000": "\u2568",
+    "/SF470000": "\u2564",
+    "/SF480000": "\u2565",
+    "/SF490000": "\u2559",
+    "/SF500000": "\u2558",
+    "/SF510000": "\u2552",
+    "/SF520000": "\u2553",
+    "/SF530000": "\u256B",
+    "/SF540000": "\u256A",
+    "/SSsquare": "\u1F14D",
+    "/Sacute": "\u015A",
+    "/Sacutedotaccent": "\u1E64",
+    "/Safha": "\u0603",
+    "/Sajdah": "\u06E9",
+    "/Salam": "\uFDF5",
+    "/Salla": "\uFDF9",
+    "/SallaUsedAsKoranicStopSign": "\uFDF0",
+    "/SallallahouAlayheWasallam": "\uFDFA",
+    "/Saltillo": "\uA78B",
+    "/Sampi": "\u03E0",
+    "/Sampiarchaic": "\u0372",
+    "/Sampigreek": "\u03E0",
+    "/San": "\u03FA",
+    "/Sanah": "\u0601",
+    "/Scaron": "\u0160",
+    "/Scarondot": "\u1E66",
+    "/Scarondotaccent": "\u1E66",
+    "/Scaronsmall": "\uF6FD",
+    "/Scedilla": "\u015E",
+    "/Schwa": "\u018F",
+    "/Schwacyr": "\u04D8",
+    "/Schwacyrillic": "\u04D8",
+    "/Schwadieresiscyr": "\u04DA",
+    "/Schwadieresiscyrillic": "\u04DA",
+    "/Scircle": "\u24C8",
+    "/Scircleblack": "\u1F162",
+    "/Scircumflex": "\u015C",
+    "/Scommaaccent": "\u0218",
+    "/Scriptg": "\uA7AC",
+    "/Sdot": "\u1E60",
+    "/Sdotaccent": "\u1E60",
+    "/Sdotbelow": "\u1E62",
+    "/Sdotbelowdotabove": "\u1E68",
+    "/Sdotbelowdotaccent": "\u1E68",
+    "/Seharmenian": "\u054D",
+    "/Semisoftcyr": "\u048C",
+    "/Sevenroman": "\u2166",
+    "/Shaarmenian": "\u0547",
+    "/Shacyr": "\u0428",
+    "/Shacyrillic": "\u0428",
+    "/Shchacyr": "\u0429",
+    "/Shchacyrillic": "\u0429",
+    "/Sheicoptic": "\u03E2",
+    "/SheneGerishin:hb": "\u059E",
+    "/Shhacyr": "\u04BA",
+    "/Shhacyrillic": "\u04BA",
+    "/Shhatailcyr": "\u0526",
+    "/Shimacoptic": "\u03EC",
+    "/Sho": "\u03F7",
+    "/Sigma": "\u03A3",
+    "/Sigmalunatesymbol": "\u03F9",
+    "/Sigmalunatesymboldotted": "\u03FE",
+    "/Sigmareversedlunatesymbol": "\u03FD",
+    "/Sinsular": "\uA784",
+    "/Sixroman": "\u2165",
+    "/Sjekomicyr": "\u050C",
+    "/Smonospace": "\uFF33",
+    "/Sobliquestroke": "\uA7A8",
+    "/Softcyr": "\u042C",
+    "/Softsigncyrillic": "\u042C",
+    "/Sparens": "\u1F122",
+    "/Sshell": "\u1F12A",
+    "/Ssmall": "\uF773",
+    "/Ssquare": "\u1F142",
+    "/Ssquareblack": "\u1F182",
+    "/Sswashtail": "\u2C7E",
+    "/Stigma": "\u03DA",
+    "/Stigmagreek": "\u03DA",
+    "/T": "\u0054",
+    "/Tau": "\u03A4",
+    "/Tbar": "\u0166",
+    "/Tcaron": "\u0164",
+    "/Tcedilla": "\u0162",
+    "/Tcircle": "\u24C9",
+    "/Tcircleblack": "\u1F163",
+    "/Tcircumflexbelow": "\u1E70",
+    "/Tcommaaccent": "\u0162",
+    "/Tdot": "\u1E6A",
+    "/Tdotaccent": "\u1E6A",
+    "/Tdotbelow": "\u1E6C",
+    "/Tecyr": "\u0422",
+    "/Tecyrillic": "\u0422",
+    "/Tedescendercyrillic": "\u04AC",
+    "/Tenroman": "\u2169",
+    "/Tetailcyr": "\u04AC",
+    "/Tetsecyr": "\u04B4",
+    "/Tetsecyrillic": "\u04B4",
+    "/Theta": "\u0398",
+    "/Thetasymbol": "\u03F4",
+    "/Thook": "\u01AC",
+    "/Thorn": "\u00DE",
+    "/Thornsmall": "\uF7FE",
+    "/Thornstroke": "\uA764",
+    "/Thornstrokedescender": "\uA766",
+    "/Threeroman": "\u2162",
+    "/Tildesmall": "\uF6FE",
+    "/Tinsular": "\uA786",
+    "/Tiwnarmenian": "\u054F",
+    "/Tjekomicyr": "\u050E",
+    "/Tlinebelow": "\u1E6E",
+    "/Tmonospace": "\uFF34",
+    "/Toarmenian": "\u0539",
+    "/Tonefive": "\u01BC",
+    "/Tonesix": "\u0184",
+    "/Tonetwo": "\u01A7",
+    "/Tparens": "\u1F123",
+    "/Tresillo": "\uA72A",
+    "/Tretroflexhook": "\u01AE",
+    "/Tsecyr": "\u0426",
+    "/Tsecyrillic": "\u0426",
+    "/Tshecyr": "\u040B",
+    "/Tshecyrillic": "\u040B",
+    "/Tsmall": "\uF774",
+    "/Tsquare": "\u1F143",
+    "/Tsquareblack": "\u1F183",
+    "/Tturned": "\uA7B1",
+    "/Twelveroman": "\u216B",
+    "/Twithdiagonalstroke": "\u023E",
+    "/Tworoman": "\u2161",
+    "/Tz": "\uA728",
+    "/U": "\u0055",
+    "/Uacute": "\u00DA",
+    "/Uacutedblcyr": "\u04F2",
+    "/Uacutesmall": "\uF7FA",
+    "/Ubar": "\u0244",
+    "/Ubreve": "\u016C",
+    "/Ucaron": "\u01D3",
+    "/Ucircle": "\u24CA",
+    "/Ucircleblack": "\u1F164",
+    "/Ucircumflex": "\u00DB",
+    "/Ucircumflexbelow": "\u1E76",
+    "/Ucircumflexsmall": "\uF7FB",
+    "/Ucyr": "\u0423",
+    "/Ucyrillic": "\u0423",
+    "/Udblacute": "\u0170",
+    "/Udblgrave": "\u0214",
+    "/Udieresis": "\u00DC",
+    "/Udieresisacute": "\u01D7",
+    "/Udieresisbelow": "\u1E72",
+    "/Udieresiscaron": "\u01D9",
+    "/Udieresiscyr": "\u04F0",
+    "/Udieresiscyrillic": "\u04F0",
+    "/Udieresisgrave": "\u01DB",
+    "/Udieresismacron": "\u01D5",
+    "/Udieresissmall": "\uF7FC",
+    "/Udotbelow": "\u1EE4",
+    "/Ugrave": "\u00D9",
+    "/Ugravedbl": "\u0214",
+    "/Ugravesmall": "\uF7F9",
+    "/Uhoi": "\u1EE6",
+    "/Uhookabove": "\u1EE6",
+    "/Uhorn": "\u01AF",
+    "/Uhornacute": "\u1EE8",
+    "/Uhorndotbelow": "\u1EF0",
+    "/Uhorngrave": "\u1EEA",
+    "/Uhornhoi": "\u1EEC",
+    "/Uhornhookabove": "\u1EEC",
+    "/Uhorntilde": "\u1EEE",
+    "/Uhungarumlaut": "\u0170",
+    "/Uhungarumlautcyrillic": "\u04F2",
+    "/Uinvertedbreve": "\u0216",
+    "/Ukcyr": "\u0478",
+    "/Ukcyrillic": "\u0478",
+    "/Umacron": "\u016A",
+    "/Umacroncyr": "\u04EE",
+    "/Umacroncyrillic": "\u04EE",
+    "/Umacrondieresis": "\u1E7A",
+    "/Umonospace": "\uFF35",
+    "/Uogonek": "\u0172",
+    "/Uparens": "\u1F124",
+    "/Upsilon": "\u03A5",
+    "/Upsilon1": "\u03D2",
+    "/Upsilonacute": "\u1FEB",
+    "/Upsilonacutehooksymbol": "\u03D3",
+    "/Upsilonacutehooksymbolgreek": "\u03D3",
+    "/Upsilonadieresishooksymbol": "\u03D4",
+    "/Upsilonafrican": "\u01B1",
+    "/Upsilonasper": "\u1F59",
+    "/Upsilonasperacute": "\u1F5D",
+    "/Upsilonaspergrave": "\u1F5B",
+    "/Upsilonaspertilde": "\u1F5F",
+    "/Upsilonbreve": "\u1FE8",
+    "/Upsilondieresis": "\u03AB",
+    "/Upsilondieresishooksymbolgreek": "\u03D4",
+    "/Upsilongrave": "\u1FEA",
+    "/Upsilonhooksymbol": "\u03D2",
+    "/Upsilontonos": "\u038E",
+    "/Upsilonwithmacron": "\u1FE9",
+    "/Uring": "\u016E",
+    "/Ushortcyr": "\u040E",
+    "/Ushortcyrillic": "\u040E",
+    "/Usmall": "\uF775",
+    "/Usquare": "\u1F144",
+    "/Usquareblack": "\u1F184",
+    "/Ustraightcyr": "\u04AE",
+    "/Ustraightcyrillic": "\u04AE",
+    "/Ustraightstrokecyr": "\u04B0",
+    "/Ustraightstrokecyrillic": "\u04B0",
+    "/Utilde": "\u0168",
+    "/Utildeacute": "\u1E78",
+    "/Utildebelow": "\u1E74",
+    "/V": "\u0056",
+    "/Vcircle": "\u24CB",
+    "/Vcircleblack": "\u1F165",
+    "/Vdiagonalstroke": "\uA75E",
+    "/Vdotbelow": "\u1E7E",
+    "/Vecyr": "\u0412",
+    "/Vecyrillic": "\u0412",
+    "/Vend": "\uA768",
+    "/Vewarmenian": "\u054E",
+    "/Vhook": "\u01B2",
+    "/Visigothicz": "\uA762",
+    "/Vmod": "\u2C7D",
+    "/Vmonospace": "\uFF36",
+    "/Voarmenian": "\u0548",
+    "/Volapukae": "\uA79A",
+    "/Volapukoe": "\uA79C",
+    "/Volapukue": "\uA79E",
+    "/Vparens": "\u1F125",
+    "/Vsmall": "\uF776",
+    "/Vsquare": "\u1F145",
+    "/Vsquareblack": "\u1F185",
+    "/Vtilde": "\u1E7C",
+    "/Vturned": "\u0245",
+    "/Vwelsh": "\u1EFC",
+    "/Vy": "\uA760",
+    "/W": "\u0057",
+    "/WZcircle": "\u1F12E",
+    "/Wacute": "\u1E82",
+    "/Wasallam": "\uFDF8",
+    "/Wcircle": "\u24CC",
+    "/Wcircleblack": "\u1F166",
+    "/Wcircumflex": "\u0174",
+    "/Wdieresis": "\u1E84",
+    "/Wdot": "\u1E86",
+    "/Wdotaccent": "\u1E86",
+    "/Wdotbelow": "\u1E88",
+    "/Wecyr": "\u051C",
+    "/Wgrave": "\u1E80",
+    "/Whook": "\u2C72",
+    "/Wmonospace": "\uFF37",
+    "/Wparens": "\u1F126",
+    "/Wsmall": "\uF777",
+    "/Wsquare": "\u1F146",
+    "/Wsquareblack": "\u1F186",
+    "/Wynn": "\u01F7",
+    "/X": "\u0058",
+    "/Xatailcyr": "\u04B2",
+    "/Xcircle": "\u24CD",
+    "/Xcircleblack": "\u1F167",
+    "/Xdieresis": "\u1E8C",
+    "/Xdot": "\u1E8A",
+    "/Xdotaccent": "\u1E8A",
+    "/Xeharmenian": "\u053D",
+    "/Xi": "\u039E",
+    "/Xmonospace": "\uFF38",
+    "/Xparens": "\u1F127",
+    "/Xsmall": "\uF778",
+    "/Xsquare": "\u1F147",
+    "/Xsquareblack": "\u1F187",
+    "/Y": "\u0059",
+    "/Yacute": "\u00DD",
+    "/Yacutesmall": "\uF7FD",
+    "/Yacyr": "\u042F",
+    "/Yaecyr": "\u0518",
+    "/Yatcyr": "\u0462",
+    "/Yatcyrillic": "\u0462",
+    "/Ycircle": "\u24CE",
+    "/Ycircleblack": "\u1F168",
+    "/Ycircumflex": "\u0176",
+    "/Ydieresis": "\u0178",
+    "/Ydieresissmall": "\uF7FF",
+    "/Ydot": "\u1E8E",
+    "/Ydotaccent": "\u1E8E",
+    "/Ydotbelow": "\u1EF4",
+    "/Yericyrillic": "\u042B",
+    "/Yerudieresiscyrillic": "\u04F8",
+    "/Ygrave": "\u1EF2",
+    "/Yhoi": "\u1EF6",
+    "/Yhook": "\u01B3",
+    "/Yhookabove": "\u1EF6",
+    "/Yiarmenian": "\u0545",
+    "/Yicyrillic": "\u0407",
+    "/Yiwnarmenian": "\u0552",
+    "/Ylongcyr": "\u042B",
+    "/Ylongdieresiscyr": "\u04F8",
+    "/Yloop": "\u1EFE",
+    "/Ymacron": "\u0232",
+    "/Ymonospace": "\uFF39",
+    "/Yogh": "\u021C",
+    "/Yot": "\u037F",
+    "/Yparens": "\u1F128",
+    "/Ysmall": "\uF779",
+    "/Ysquare": "\u1F148",
+    "/Ysquareblack": "\u1F188",
+    "/Ystroke": "\u024E",
+    "/Ytilde": "\u1EF8",
+    "/Yturnedsans": "\u2144",
+    "/Yucyr": "\u042E",
+    "/Yukrcyr": "\u0407",
+    "/Yusbigcyr": "\u046A",
+    "/Yusbigcyrillic": "\u046A",
+    "/Yusbigiotifiedcyr": "\u046C",
+    "/Yusbigiotifiedcyrillic": "\u046C",
+    "/Yuslittlecyr": "\u0466",
+    "/Yuslittlecyrillic": "\u0466",
+    "/Yuslittleiotifiedcyr": "\u0468",
+    "/Yuslittleiotifiedcyrillic": "\u0468",
+    "/Z": "\u005A",
+    "/Zaarmenian": "\u0536",
+    "/Zacute": "\u0179",
+    "/Zcaron": "\u017D",
+    "/Zcaronsmall": "\uF6FF",
+    "/Zcircle": "\u24CF",
+    "/Zcircleblack": "\u1F169",
+    "/Zcircumflex": "\u1E90",
+    "/Zdblstruck": "\u2124",
+    "/Zdescender": "\u2C6B",
+    "/Zdot": "\u017B",
+    "/Zdotaccent": "\u017B",
+    "/Zdotbelow": "\u1E92",
+    "/Zecyr": "\u0417",
+    "/Zecyrillic": "\u0417",
+    "/Zedescendercyrillic": "\u0498",
+    "/Zedieresiscyr": "\u04DE",
+    "/Zedieresiscyrillic": "\u04DE",
+    "/Zeta": "\u0396",
+    "/Zetailcyr": "\u0498",
+    "/Zfraktur": "\u2128",
+    "/Zhearmenian": "\u053A",
+    "/Zhebrevecyr": "\u04C1",
+    "/Zhebrevecyrillic": "\u04C1",
+    "/Zhecyr": "\u0416",
+    "/Zhecyrillic": "\u0416",
+    "/Zhedescendercyrillic": "\u0496",
+    "/Zhedieresiscyr": "\u04DC",
+    "/Zhedieresiscyrillic": "\u04DC",
+    "/Zhetailcyr": "\u0496",
+    "/Zhook": "\u0224",
+    "/Zjekomicyr": "\u0504",
+    "/Zlinebelow": "\u1E94",
+    "/Zmonospace": "\uFF3A",
+    "/Zparens": "\u1F129",
+    "/Zsmall": "\uF77A",
+    "/Zsquare": "\u1F149",
+    "/Zsquareblack": "\u1F189",
+    "/Zstroke": "\u01B5",
+    "/Zswashtail": "\u2C7F",
+    "/a": "\u0061",
+    "/a.inferior": "\u2090",
+    "/aHonRAA": "\u0613",
+    "/aa": "\uA733",
+    "/aabengali": "\u0986",
+    "/aacute": "\u00E1",
+    "/aadeva": "\u0906",
+    "/aagujarati": "\u0A86",
+    "/aagurmukhi": "\u0A06",
+    "/aamatragurmukhi": "\u0A3E",
+    "/aarusquare": "\u3303",
+    "/aavowelsignbengali": "\u09BE",
+    "/aavowelsigndeva": "\u093E",
+    "/aavowelsigngujarati": "\u0ABE",
+    "/abbreviationmarkarmenian": "\u055F",
+    "/abbreviationsigndeva": "\u0970",
+    "/abengali": "\u0985",
+    "/abopomofo": "\u311A",
+    "/abreve": "\u0103",
+    "/abreveacute": "\u1EAF",
+    "/abrevecyr": "\u04D1",
+    "/abrevecyrillic": "\u04D1",
+    "/abrevedotbelow": "\u1EB7",
+    "/abrevegrave": "\u1EB1",
+    "/abrevehoi": "\u1EB3",
+    "/abrevehookabove": "\u1EB3",
+    "/abrevetilde": "\u1EB5",
+    "/absquareblack": "\u1F18E",
+    "/acaron": "\u01CE",
+    "/accountof": "\u2100",
+    "/accurrent": "\u23E6",
+    "/acircle": "\u24D0",
+    "/acirclekatakana": "\u32D0",
+    "/acircumflex": "\u00E2",
+    "/acircumflexacute": "\u1EA5",
+    "/acircumflexdotbelow": "\u1EAD",
+    "/acircumflexgrave": "\u1EA7",
+    "/acircumflexhoi": "\u1EA9",
+    "/acircumflexhookabove": "\u1EA9",
+    "/acircumflextilde": "\u1EAB",
+    "/activatearabicformshaping": "\u206D",
+    "/activatesymmetricswapping": "\u206B",
+    "/acute": "\u00B4",
+    "/acutebelowcmb": "\u0317",
+    "/acutecmb": "\u0301",
+    "/acutecomb": "\u0301",
+    "/acutedblmiddlemod": "\u02F6",
+    "/acutedeva": "\u0954",
+    "/acutelowmod": "\u02CF",
+    "/acutemod": "\u02CA",
+    "/acutetonecmb": "\u0341",
+    "/acyr": "\u0430",
+    "/acyrillic": "\u0430",
+    "/adblgrave": "\u0201",
+    "/addakgurmukhi": "\u0A71",
+    "/addressedsubject": "\u2101",
+    "/adegadegpada": "\uA9CB",
+    "/adegpada": "\uA9CA",
+    "/adeva": "\u0905",
+    "/adieresis": "\u00E4",
+    "/adieresiscyr": "\u04D3",
+    "/adieresiscyrillic": "\u04D3",
+    "/adieresismacron": "\u01DF",
+    "/adishakti": "\u262C",
+    "/admissionTickets": "\u1F39F",
+    "/adot": "\u0227",
+    "/adotbelow": "\u1EA1",
+    "/adotmacron": "\u01E1",
+    "/ae": "\u00E6",
+    "/aeacute": "\u01FD",
+    "/aekorean": "\u3150",
+    "/aemacron": "\u01E3",
+    "/aerialTramway": "\u1F6A1",
+    "/afghani": "\u060B",
+    "/afii00208": "\u2015",
+    "/afii08941": "\u20A4",
+    "/afii10017": "\u0410",
+    "/afii10018": "\u0411",
+    "/afii10019": "\u0412",
+    "/afii10020": "\u0413",
+    "/afii10021": "\u0414",
+    "/afii10022": "\u0415",
+    "/afii10023": "\u0401",
+    "/afii10024": "\u0416",
+    "/afii10025": "\u0417",
+    "/afii10026": "\u0418",
+    "/afii10027": "\u0419",
+    "/afii10028": "\u041A",
+    "/afii10029": "\u041B",
+    "/afii10030": "\u041C",
+    "/afii10031": "\u041D",
+    "/afii10032": "\u041E",
+    "/afii10033": "\u041F",
+    "/afii10034": "\u0420",
+    "/afii10035": "\u0421",
+    "/afii10036": "\u0422",
+    "/afii10037": "\u0423",
+    "/afii10038": "\u0424",
+    "/afii10039": "\u0425",
+    "/afii10040": "\u0426",
+    "/afii10041": "\u0427",
+    "/afii10042": "\u0428",
+    "/afii10043": "\u0429",
+    "/afii10044": "\u042A",
+    "/afii10045": "\u042B",
+    "/afii10046": "\u042C",
+    "/afii10047": "\u042D",
+    "/afii10048": "\u042E",
+    "/afii10049": "\u042F",
+    "/afii10050": "\u0490",
+    "/afii10051": "\u0402",
+    "/afii10052": "\u0403",
+    "/afii10053": "\u0404",
+    "/afii10054": "\u0405",
+    "/afii10055": "\u0406",
+    "/afii10056": "\u0407",
+    "/afii10057": "\u0408",
+    "/afii10058": "\u0409",
+    "/afii10059": "\u040A",
+    "/afii10060": "\u040B",
+    "/afii10061": "\u040C",
+    "/afii10062": "\u040E",
+    "/afii10063": "\uF6C4",
+    "/afii10064": "\uF6C5",
+    "/afii10065": "\u0430",
+    "/afii10066": "\u0431",
+    "/afii10067": "\u0432",
+    "/afii10068": "\u0433",
+    "/afii10069": "\u0434",
+    "/afii10070": "\u0435",
+    "/afii10071": "\u0451",
+    "/afii10072": "\u0436",
+    "/afii10073": "\u0437",
+    "/afii10074": "\u0438",
+    "/afii10075": "\u0439",
+    "/afii10076": "\u043A",
+    "/afii10077": "\u043B",
+    "/afii10078": "\u043C",
+    "/afii10079": "\u043D",
+    "/afii10080": "\u043E",
+    "/afii10081": "\u043F",
+    "/afii10082": "\u0440",
+    "/afii10083": "\u0441",
+    "/afii10084": "\u0442",
+    "/afii10085": "\u0443",
+    "/afii10086": "\u0444",
+    "/afii10087": "\u0445",
+    "/afii10088": "\u0446",
+    "/afii10089": "\u0447",
+    "/afii10090": "\u0448",
+    "/afii10091": "\u0449",
+    "/afii10092": "\u044A",
+    "/afii10093": "\u044B",
+    "/afii10094": "\u044C",
+    "/afii10095": "\u044D",
+    "/afii10096": "\u044E",
+    "/afii10097": "\u044F",
+    "/afii10098": "\u0491",
+    "/afii10099": "\u0452",
+    "/afii10100": "\u0453",
+    "/afii10101": "\u0454",
+    "/afii10102": "\u0455",
+    "/afii10103": "\u0456",
+    "/afii10104": "\u0457",
+    "/afii10105": "\u0458",
+    "/afii10106": "\u0459",
+    "/afii10107": "\u045A",
+    "/afii10108": "\u045B",
+    "/afii10109": "\u045C",
+    "/afii10110": "\u045E",
+    "/afii10145": "\u040F",
+    "/afii10146": "\u0462",
+    "/afii10147": "\u0472",
+    "/afii10148": "\u0474",
+    "/afii10192": "\uF6C6",
+    "/afii10193": "\u045F",
+    "/afii10194": "\u0463",
+    "/afii10195": "\u0473",
+    "/afii10196": "\u0475",
+    "/afii10831": "\uF6C7",
+    "/afii10832": "\uF6C8",
+    "/afii10846": "\u04D9",
+    "/afii299": "\u200E",
+    "/afii300": "\u200F",
+    "/afii301": "\u200D",
+    "/afii57381": "\u066A",
+    "/afii57388": "\u060C",
+    "/afii57392": "\u0660",
+    "/afii57393": "\u0661",
+    "/afii57394": "\u0662",
+    "/afii57395": "\u0663",
+    "/afii57396": "\u0664",
+    "/afii57397": "\u0665",
+    "/afii57398": "\u0666",
+    "/afii57399": "\u0667",
+    "/afii57400": "\u0668",
+    "/afii57401": "\u0669",
+    "/afii57403": "\u061B",
+    "/afii57407": "\u061F",
+    "/afii57409": "\u0621",
+    "/afii57410": "\u0622",
+    "/afii57411": "\u0623",
+    "/afii57412": "\u0624",
+    "/afii57413": "\u0625",
+    "/afii57414": "\u0626",
+    "/afii57415": "\u0627",
+    "/afii57416": "\u0628",
+    "/afii57417": "\u0629",
+    "/afii57418": "\u062A",
+    "/afii57419": "\u062B",
+    "/afii57420": "\u062C",
+    "/afii57421": "\u062D",
+    "/afii57422": "\u062E",
+    "/afii57423": "\u062F",
+    "/afii57424": "\u0630",
+    "/afii57425": "\u0631",
+    "/afii57426": "\u0632",
+    "/afii57427": "\u0633",
+    "/afii57428": "\u0634",
+    "/afii57429": "\u0635",
+    "/afii57430": "\u0636",
+    "/afii57431": "\u0637",
+    "/afii57432": "\u0638",
+    "/afii57433": "\u0639",
+    "/afii57434": "\u063A",
+    "/afii57440": "\u0640",
+    "/afii57441": "\u0641",
+    "/afii57442": "\u0642",
+    "/afii57443": "\u0643",
+    "/afii57444": "\u0644",
+    "/afii57445": "\u0645",
+    "/afii57446": "\u0646",
+    "/afii57448": "\u0648",
+    "/afii57449": "\u0649",
+    "/afii57450": "\u064A",
+    "/afii57451": "\u064B",
+    "/afii57452": "\u064C",
+    "/afii57453": "\u064D",
+    "/afii57454": "\u064E",
+    "/afii57455": "\u064F",
+    "/afii57456": "\u0650",
+    "/afii57457": "\u0651",
+    "/afii57458": "\u0652",
+    "/afii57470": "\u0647",
+    "/afii57505": "\u06A4",
+    "/afii57506": "\u067E",
+    "/afii57507": "\u0686",
+    "/afii57508": "\u0698",
+    "/afii57509": "\u06AF",
+    "/afii57511": "\u0679",
+    "/afii57512": "\u0688",
+    "/afii57513": "\u0691",
+    "/afii57514": "\u06BA",
+    "/afii57519": "\u06D2",
+    "/afii57534": "\u06D5",
+    "/afii57636": "\u20AA",
+    "/afii57645": "\u05BE",
+    "/afii57658": "\u05C3",
+    "/afii57664": "\u05D0",
+    "/afii57665": "\u05D1",
+    "/afii57666": "\u05D2",
+    "/afii57667": "\u05D3",
+    "/afii57668": "\u05D4",
+    "/afii57669": "\u05D5",
+    "/afii57670": "\u05D6",
+    "/afii57671": "\u05D7",
+    "/afii57672": "\u05D8",
+    "/afii57673": "\u05D9",
+    "/afii57674": "\u05DA",
+    "/afii57675": "\u05DB",
+    "/afii57676": "\u05DC",
+    "/afii57677": "\u05DD",
+    "/afii57678": "\u05DE",
+    "/afii57679": "\u05DF",
+    "/afii57680": "\u05E0",
+    "/afii57681": "\u05E1",
+    "/afii57682": "\u05E2",
+    "/afii57683": "\u05E3",
+    "/afii57684": "\u05E4",
+    "/afii57685": "\u05E5",
+    "/afii57686": "\u05E6",
+    "/afii57687": "\u05E7",
+    "/afii57688": "\u05E8",
+    "/afii57689": "\u05E9",
+    "/afii57690": "\u05EA",
+    "/afii57694": "\uFB2A",
+    "/afii57695": "\uFB2B",
+    "/afii57700": "\uFB4B",
+    "/afii57705": "\uFB1F",
+    "/afii57716": "\u05F0",
+    "/afii57717": "\u05F1",
+    "/afii57718": "\u05F2",
+    "/afii57723": "\uFB35",
+    "/afii57793": "\u05B4",
+    "/afii57794": "\u05B5",
+    "/afii57795": "\u05B6",
+    "/afii57796": "\u05BB",
+    "/afii57797": "\u05B8",
+    "/afii57798": "\u05B7",
+    "/afii57799": "\u05B0",
+    "/afii57800": "\u05B2",
+    "/afii57801": "\u05B1",
+    "/afii57802": "\u05B3",
+    "/afii57803": "\u05C2",
+    "/afii57804": "\u05C1",
+    "/afii57806": "\u05B9",
+    "/afii57807": "\u05BC",
+    "/afii57839": "\u05BD",
+    "/afii57841": "\u05BF",
+    "/afii57842": "\u05C0",
+    "/afii57929": "\u02BC",
+    "/afii61248": "\u2105",
+    "/afii61289": "\u2113",
+    "/afii61352": "\u2116",
+    "/afii61573": "\u202C",
+    "/afii61574": "\u202D",
+    "/afii61575": "\u202E",
+    "/afii61664": "\u200C",
+    "/afii63167": "\u066D",
+    "/afii64937": "\u02BD",
+    "/agrave": "\u00E0",
+    "/agravedbl": "\u0201",
+    "/agujarati": "\u0A85",
+    "/agurmukhi": "\u0A05",
+    "/ahiragana": "\u3042",
+    "/ahoi": "\u1EA3",
+    "/ahookabove": "\u1EA3",
+    "/aibengali": "\u0990",
+    "/aibopomofo": "\u311E",
+    "/aideva": "\u0910",
+    "/aiecyr": "\u04D5",
+    "/aiecyrillic": "\u04D5",
+    "/aigujarati": "\u0A90",
+    "/aigurmukhi": "\u0A10",
+    "/aimatragurmukhi": "\u0A48",
+    "/ain.fina": "\uFECA",
+    "/ain.init": "\uFECB",
+    "/ain.init_alefmaksura.fina": "\uFCF7",
+    "/ain.init_jeem.fina": "\uFC29",
+    "/ain.init_jeem.medi": "\uFCBA",
+    "/ain.init_jeem.medi_meem.medi": "\uFDC4",
+    "/ain.init_meem.fina": "\uFC2A",
+    "/ain.init_meem.medi": "\uFCBB",
+    "/ain.init_meem.medi_meem.medi": "\uFD77",
+    "/ain.init_yeh.fina": "\uFCF8",
+    "/ain.isol": "\uFEC9",
+    "/ain.medi": "\uFECC",
+    "/ain.medi_alefmaksura.fina": "\uFD13",
+    "/ain.medi_jeem.medi_meem.fina": "\uFD75",
+    "/ain.medi_meem.medi_alefmaksura.fina": "\uFD78",
+    "/ain.medi_meem.medi_meem.fina": "\uFD76",
+    "/ain.medi_meem.medi_yeh.fina": "\uFDB6",
+    "/ain.medi_yeh.fina": "\uFD14",
+    "/ainThreeDotsDownAbove": "\u075E",
+    "/ainTwoDotsAbove": "\u075D",
+    "/ainTwoDotsVerticallyAbove": "\u075F",
+    "/ainarabic": "\u0639",
+    "/ainfinalarabic": "\uFECA",
+    "/aininitialarabic": "\uFECB",
+    "/ainmedialarabic": "\uFECC",
+    "/ainthreedotsabove": "\u06A0",
+    "/ainvertedbreve": "\u0203",
+    "/airplaneArriving": "\u1F6EC",
+    "/airplaneDeparture": "\u1F6EB",
+    "/aivowelsignbengali": "\u09C8",
+    "/aivowelsigndeva": "\u0948",
+    "/aivowelsigngujarati": "\u0AC8",
+    "/akatakana": "\u30A2",
+    "/akatakanahalfwidth": "\uFF71",
+    "/akorean": "\u314F",
+    "/aktieselskab": "\u214D",
+    "/alarmclock": "\u23F0",
+    "/alef": "\u05D0",
+    "/alef.fina": "\uFE8E",
+    "/alef.init_fathatan.fina": "\uFD3D",
+    "/alef.isol": "\uFE8D",
+    "/alef.medi_fathatan.fina": "\uFD3C",
+    "/alef:hb": "\u05D0",
+    "/alefDigitThreeAbove": "\u0774",
+    "/alefDigitTwoAbove": "\u0773",
+    "/alefLamYehabove": "\u0616",
+    "/alefabove": "\u0670",
+    "/alefarabic": "\u0627",
+    "/alefdageshhebrew": "\uFB30",
+    "/aleffinalarabic": "\uFE8E",
+    "/alefhamza": "\u0623",
+    "/alefhamza.fina": "\uFE84",
+    "/alefhamza.isol": "\uFE83",
+    "/alefhamzaabovearabic": "\u0623",
+    "/alefhamzaabovefinalarabic": "\uFE84",
+    "/alefhamzabelow": "\u0625",
+    "/alefhamzabelow.fina": "\uFE88",
+    "/alefhamzabelow.isol": "\uFE87",
+    "/alefhamzabelowarabic": "\u0625",
+    "/alefhamzabelowfinalarabic": "\uFE88",
+    "/alefhebrew": "\u05D0",
+    "/alefhighhamza": "\u0675",
+    "/aleflamedhebrew": "\uFB4F",
+    "/alefmadda": "\u0622",
+    "/alefmadda.fina": "\uFE82",
+    "/alefmadda.isol": "\uFE81",
+    "/alefmaddaabovearabic": "\u0622",
+    "/alefmaddaabovefinalarabic": "\uFE82",
+    "/alefmaksura": "\u0649",
+    "/alefmaksura.fina": "\uFEF0",
+    "/alefmaksura.init_superscriptalef.fina": "\uFC5D",
+    "/alefmaksura.isol": "\uFEEF",
+    "/alefmaksura.medi_superscriptalef.fina": "\uFC90",
+    "/alefmaksuraarabic": "\u0649",
+    "/alefmaksurafinalarabic": "\uFEF0",
+    "/alefmaksurainitialarabic": "\uFEF3",
+    "/alefmaksuramedialarabic": "\uFEF4",
+    "/alefpatahhebrew": "\uFB2E",
+    "/alefqamatshebrew": "\uFB2F",
+    "/alefwasla": "\u0671",
+    "/alefwasla.fina": "\uFB51",
+    "/alefwasla.isol": "\uFB50",
+    "/alefwavyhamza": "\u0672",
+    "/alefwavyhamzabelow": "\u0673",
+    "/alefwide:hb": "\uFB21",
+    "/alefwithmapiq:hb": "\uFB30",
+    "/alefwithpatah:hb": "\uFB2E",
+    "/alefwithqamats:hb": "\uFB2F",
+    "/alembic": "\u2697",
+    "/aleph": "\u2135",
+    "/alienMonster": "\u1F47E",
+    "/allaroundprofile": "\u232E",
+    "/allequal": "\u224C",
+    "/allianceideographiccircled": "\u32AF",
+    "/allianceideographicparen": "\u323F",
+    "/almostequalorequal": "\u224A",
+    "/alpha": "\u03B1",
+    "/alphaacute": "\u1F71",
+    "/alphaacuteiotasub": "\u1FB4",
+    "/alphaasper": "\u1F01",
+    "/alphaasperacute": "\u1F05",
+    "/alphaasperacuteiotasub": "\u1F85",
+    "/alphaaspergrave": "\u1F03",
+    "/alphaaspergraveiotasub": "\u1F83",
+    "/alphaasperiotasub": "\u1F81",
+    "/alphaaspertilde": "\u1F07",
+    "/alphaaspertildeiotasub": "\u1F87",
+    "/alphabreve": "\u1FB0",
+    "/alphafunc": "\u237A",
+    "/alphagrave": "\u1F70",
+    "/alphagraveiotasub": "\u1FB2",
+    "/alphaiotasub": "\u1FB3",
+    "/alphalenis": "\u1F00",
+    "/alphalenisacute": "\u1F04",
+    "/alphalenisacuteiotasub": "\u1F84",
+    "/alphalenisgrave": "\u1F02",
+    "/alphalenisgraveiotasub": "\u1F82",
+    "/alphalenisiotasub": "\u1F80",
+    "/alphalenistilde": "\u1F06",
+    "/alphalenistildeiotasub": "\u1F86",
+    "/alphatilde": "\u1FB6",
+    "/alphatildeiotasub": "\u1FB7",
+    "/alphatonos": "\u03AC",
+    "/alphaturned": "\u0252",
+    "/alphaunderlinefunc": "\u2376",
+    "/alphawithmacron": "\u1FB1",
+    "/alternateonewayleftwaytraffic": "\u26D5",
+    "/alternative": "\u2387",
+    "/amacron": "\u0101",
+    "/ambulance": "\u1F691",
+    "/americanFootball": "\u1F3C8",
+    "/amfullwidth": "\u33C2",
+    "/amonospace": "\uFF41",
+    "/amountofcheck": "\u2447",
+    "/ampersand": "\u0026",
+    "/ampersandSindhi": "\u06FD",
+    "/ampersandmonospace": "\uFF06",
+    "/ampersandsmall": "\uF726",
+    "/ampersandturned": "\u214B",
+    "/amphora": "\u1F3FA",
+    "/amsquare": "\u33C2",
+    "/anbopomofo": "\u3122",
+    "/anchor": "\u2693",
+    "/ancoradown": "\u2E14",
+    "/ancoraup": "\u2E15",
+    "/andappada": "\uA9C3",
+    "/angbopomofo": "\u3124",
+    "/anger": "\u1F4A2",
+    "/angkhankhuthai": "\u0E5A",
+    "/angle": "\u2220",
+    "/anglearcright": "\u22BE",
+    "/anglebracketleft": "\u3008",
+    "/anglebracketleftvertical": "\uFE3F",
+    "/anglebracketright": "\u3009",
+    "/anglebracketrightvertical": "\uFE40",
+    "/angledottedright": "\u2E16",
+    "/angleleft": "\u2329",
+    "/anglemarkerdottedsubstitutionright": "\u2E01",
+    "/anglemarkersubstitutionright": "\u2E00",
+    "/angleright": "\u232A",
+    "/anglezigzagarrowdownright": "\u237C",
+    "/angryFace": "\u1F620",
+    "/angstrom": "\u212B",
+    "/anguishedFace": "\u1F627",
+    "/ankh": "\u2625",
+    "/anoteleia": "\u0387",
+    "/anpeasquare": "\u3302",
+    "/ant": "\u1F41C",
+    "/antennaBars": "\u1F4F6",
+    "/anticlockwiseDownwardsAndUpwardsOpenCircleArrows": "\u1F504",
+    "/anudattadeva": "\u0952",
+    "/anusvarabengali": "\u0982",
+    "/anusvaradeva": "\u0902",
+    "/anusvaragujarati": "\u0A82",
+    "/ao": "\uA735",
+    "/aogonek": "\u0105",
+    "/aovermfullwidth": "\u33DF",
+    "/apaatosquare": "\u3300",
+    "/aparen": "\u249C",
+    "/aparenthesized": "\u249C",
+    "/apostrophearmenian": "\u055A",
+    "/apostrophedblmod": "\u02EE",
+    "/apostrophemod": "\u02BC",
+    "/apple": "\uF8FF",
+    "/approaches": "\u2250",
+    "/approacheslimit": "\u2250",
+    "/approxequal": "\u2248",
+    "/approxequalorimage": "\u2252",
+    "/approximatelybutnotactuallyequal": "\u2246",
+    "/approximatelyequal": "\u2245",
+    "/approximatelyequalorimage": "\u2252",
+    "/apriltelegraph": "\u32C3",
+    "/aquarius": "\u2652",
+    "/ar:ae": "\u06D5",
+    "/ar:ain": "\u0639",
+    "/ar:alef": "\u0627",
+    "/ar:comma": "\u060C",
+    "/ar:cuberoot": "\u0606",
+    "/ar:decimalseparator": "\u066B",
+    "/ar:e": "\u06D0",
+    "/ar:eight": "\u0668",
+    "/ar:feh": "\u0641",
+    "/ar:five": "\u0665",
+    "/ar:four": "\u0664",
+    "/ar:fourthroot": "\u0607",
+    "/ar:kaf": "\u0643",
+    "/ar:ng": "\u06AD",
+    "/ar:nine": "\u0669",
+    "/ar:numbersign": "\u0600",
+    "/ar:oe": "\u06C6",
+    "/ar:one": "\u0661",
+    "/ar:peh": "\u067E",
+    "/ar:percent": "\u066A",
+    "/ar:perthousand": "\u060A",
+    "/ar:question": "\u061F",
+    "/ar:reh": "\u0631",
+    "/ar:semicolon": "\u061B",
+    "/ar:seven": "\u0667",
+    "/ar:shadda": "\u0651",
+    "/ar:six": "\u0666",
+    "/ar:sukun": "\u0652",
+    "/ar:three": "\u0663",
+    "/ar:two": "\u0662",
+    "/ar:u": "\u06C7",
+    "/ar:ve": "\u06CB",
+    "/ar:yu": "\u06C8",
+    "/ar:zero": "\u0660",
+    "/araeaekorean": "\u318E",
+    "/araeakorean": "\u318D",
+    "/arc": "\u2312",
+    "/archaicmepigraphic": "\uA7FF",
+    "/aries": "\u2648",
+    "/arighthalfring": "\u1E9A",
+    "/aring": "\u00E5",
+    "/aringacute": "\u01FB",
+    "/aringbelow": "\u1E01",
+    "/armn:Ayb": "\u0531",
+    "/armn:Ben": "\u0532",
+    "/armn:Ca": "\u053E",
+    "/armn:Cha": "\u0549",
+    "/armn:Cheh": "\u0543",
+    "/armn:Co": "\u0551",
+    "/armn:DRAMSIGN": "\u058F",
+    "/armn:Da": "\u0534",
+    "/armn:Ech": "\u0535",
+    "/armn:Eh": "\u0537",
+    "/armn:Et": "\u0538",
+    "/armn:Feh": "\u0556",
+    "/armn:Ghad": "\u0542",
+    "/armn:Gim": "\u0533",
+    "/armn:Ho": "\u0540",
+    "/armn:Ini": "\u053B",
+    "/armn:Ja": "\u0541",
+    "/armn:Jheh": "\u054B",
+    "/armn:Keh": "\u0554",
+    "/armn:Ken": "\u053F",
+    "/armn:Liwn": "\u053C",
+    "/armn:Men": "\u0544",
+    "/armn:Now": "\u0546",
+    "/armn:Oh": "\u0555",
+    "/armn:Peh": "\u054A",
+    "/armn:Piwr": "\u0553",
+    "/armn:Ra": "\u054C",
+    "/armn:Reh": "\u0550",
+    "/armn:Seh": "\u054D",
+    "/armn:Sha": "\u0547",
+    "/armn:Tiwn": "\u054F",
+    "/armn:To": "\u0539",
+    "/armn:Vew": "\u054E",
+    "/armn:Vo": "\u0548",
+    "/armn:Xeh": "\u053D",
+    "/armn:Yi": "\u0545",
+    "/armn:Yiwn": "\u0552",
+    "/armn:Za": "\u0536",
+    "/armn:Zhe": "\u053A",
+    "/armn:abbreviationmark": "\u055F",
+    "/armn:apostrophe": "\u055A",
+    "/armn:ayb": "\u0561",
+    "/armn:ben": "\u0562",
+    "/armn:ca": "\u056E",
+    "/armn:cha": "\u0579",
+    "/armn:cheh": "\u0573",
+    "/armn:co": "\u0581",
+    "/armn:comma": "\u055D",
+    "/armn:da": "\u0564",
+    "/armn:ech": "\u0565",
+    "/armn:ech_yiwn": "\u0587",
+    "/armn:eh": "\u0567",
+    "/armn:emphasismark": "\u055B",
+    "/armn:et": "\u0568",
+    "/armn:exclam": "\u055C",
+    "/armn:feh": "\u0586",
+    "/armn:ghad": "\u0572",
+    "/armn:gim": "\u0563",
+    "/armn:ho": "\u0570",
+    "/armn:hyphen": "\u058A",
+    "/armn:ini": "\u056B",
+    "/armn:ja": "\u0571",
+    "/armn:jheh": "\u057B",
+    "/armn:keh": "\u0584",
+    "/armn:ken": "\u056F",
+    "/armn:leftfacingeternitysign": "\u058E",
+    "/armn:liwn": "\u056C",
+    "/armn:men": "\u0574",
+    "/armn:men_ech": "\uFB14",
+    "/armn:men_ini": "\uFB15",
+    "/armn:men_now": "\uFB13",
+    "/armn:men_xeh": "\uFB17",
+    "/armn:now": "\u0576",
+    "/armn:oh": "\u0585",
+    "/armn:peh": "\u057A",
+    "/armn:period": "\u0589",
+    "/armn:piwr": "\u0583",
+    "/armn:question": "\u055E",
+    "/armn:ra": "\u057C",
+    "/armn:reh": "\u0580",
+    "/armn:rightfacingeternitysign": "\u058D",
+    "/armn:ringhalfleft": "\u0559",
+    "/armn:seh": "\u057D",
+    "/armn:sha": "\u0577",
+    "/armn:tiwn": "\u057F",
+    "/armn:to": "\u0569",
+    "/armn:vew": "\u057E",
+    "/armn:vew_now": "\uFB16",
+    "/armn:vo": "\u0578",
+    "/armn:xeh": "\u056D",
+    "/armn:yi": "\u0575",
+    "/armn:yiwn": "\u0582",
+    "/armn:za": "\u0566",
+    "/armn:zhe": "\u056A",
+    "/arrowNE": "\u2197",
+    "/arrowNW": "\u2196",
+    "/arrowSE": "\u2198",
+    "/arrowSW": "\u2199",
+    "/arrowanticlockwiseopencircle": "\u21BA",
+    "/arrowanticlockwisesemicircle": "\u21B6",
+    "/arrowboth": "\u2194",
+    "/arrowclockwiseopencircle": "\u21BB",
+    "/arrowclockwisesemicircle": "\u21B7",
+    "/arrowdashdown": "\u21E3",
+    "/arrowdashleft": "\u21E0",
+    "/arrowdashright": "\u21E2",
+    "/arrowdashup": "\u21E1",
+    "/arrowdblboth": "\u21D4",
+    "/arrowdbldown": "\u21D3",
+    "/arrowdblleft": "\u21D0",
+    "/arrowdblright": "\u21D2",
+    "/arrowdblup": "\u21D1",
+    "/arrowdown": "\u2193",
+    "/arrowdowndashed": "\u21E3",
+    "/arrowdownfrombar": "\u21A7",
+    "/arrowdownleft": "\u2199",
+    "/arrowdownright": "\u2198",
+    "/arrowdowntwoheaded": "\u21A1",
+    "/arrowdownwhite": "\u21E9",
+    "/arrowdownzigzag": "\u21AF",
+    "/arrowheaddown": "\u2304",
+    "/arrowheaddownlowmod": "\u02EF",
+    "/arrowheaddownmod": "\u02C5",
+    "/arrowheadleftlowmod": "\u02F1",
+    "/arrowheadleftmod": "\u02C2",
+    "/arrowheadrightlowmod": "\u02F2",
+    "/arrowheadrightmod": "\u02C3",
+    "/arrowheadtwobarsuphorizontal": "\u2324",
+    "/arrowheadup": "\u2303",
+    "/arrowheaduplowmod": "\u02F0",
+    "/arrowheadupmod": "\u02C4",
+    "/arrowhorizex": "\uF8E7",
+    "/arrowleft": "\u2190",
+    "/arrowleftdashed": "\u21E0",
+    "/arrowleftdbl": "\u21D0",
+    "/arrowleftdblstroke": "\u21CD",
+    "/arrowleftdowncorner": "\u21B5",
+    "/arrowleftdowntip": "\u21B2",
+    "/arrowleftfrombar": "\u21A4",
+    "/arrowlefthook": "\u21A9",
+    "/arrowleftloop": "\u21AB",
+    "/arrowleftlowmod": "\u02FF",
+    "/arrowleftoverright": "\u21C6",
+    "/arrowleftoverrighttobar": "\u21B9",
+    "/arrowleftright": "\u2194",
+    "/arrowleftrightstroke": "\u21AE",
+    "/arrowleftrightwave": "\u21AD",
+    "/arrowleftsquiggle": "\u21DC",
+    "/arrowleftstroke": "\u219A",
+    "/arrowlefttail": "\u21A2",
+    "/arrowlefttobar": "\u21E4",
+    "/arrowlefttwoheaded": "\u219E",
+    "/arrowleftuptip": "\u21B0",
+    "/arrowleftwave": "\u219C",
+    "/arrowleftwhite": "\u21E6",
+    "/arrowlongNWtobar": "\u21B8",
+    "/arrowright": "\u2192",
+    "/arrowrightdashed": "\u21E2",
+    "/arrowrightdblstroke": "\u21CF",
+    "/arrowrightdowncorner": "\u21B4",
+    "/arrowrightdowntip": "\u21B3",
+    "/arrowrightfrombar": "\u21A6",
+    "/arrowrightheavy": "\u279E",
+    "/arrowrighthook": "\u21AA",
+    "/arrowrightloop": "\u21AC",
+    "/arrowrightoverleft": "\u21C4",
+    "/arrowrightsmallcircle": "\u21F4",
+    "/arrowrightsquiggle": "\u21DD",
+    "/arrowrightstroke": "\u219B",
+    "/arrowrighttail": "\u21A3",
+    "/arrowrighttobar": "\u21E5",
+    "/arrowrighttwoheaded": "\u21A0",
+    "/arrowrightwave": "\u219D",
+    "/arrowrightwhite": "\u21E8",
+    "/arrowspaireddown": "\u21CA",
+    "/arrowspairedleft": "\u21C7",
+    "/arrowspairedright": "\u21C9",
+    "/arrowspairedup": "\u21C8",
+    "/arrowtableft": "\u21E4",
+    "/arrowtabright": "\u21E5",
+    "/arrowup": "\u2191",
+    "/arrowupdashed": "\u21E1",
+    "/arrowupdn": "\u2195",
+    "/arrowupdnbse": "\u21A8",
+    "/arrowupdown": "\u2195",
+    "/arrowupdownbase": "\u21A8",
+    "/arrowupdownwithbase": "\u21A8",
+    "/arrowupfrombar": "\u21A5",
+    "/arrowupleft": "\u2196",
+    "/arrowupleftofdown": "\u21C5",
+    "/arrowupright": "\u2197",
+    "/arrowuprighttip": "\u21B1",
+    "/arrowuptwoheaded": "\u219F",
+    "/arrowupwhite": "\u21E7",
+    "/arrowvertex": "\uF8E6",
+    "/articulatedLorry": "\u1F69B",
+    "/artistPalette": "\u1F3A8",
+    "/aruhuasquare": "\u3301",
+    "/asciicircum": "\u005E",
+    "/asciicircummonospace": "\uFF3E",
+    "/asciitilde": "\u007E",
+    "/asciitildemonospace": "\uFF5E",
+    "/ascript": "\u0251",
+    "/ascriptturned": "\u0252",
+    "/asmallhiragana": "\u3041",
+    "/asmallkatakana": "\u30A1",
+    "/asmallkatakanahalfwidth": "\uFF67",
+    "/asper": "\u1FFE",
+    "/asperacute": "\u1FDE",
+    "/aspergrave": "\u1FDD",
+    "/aspertilde": "\u1FDF",
+    "/assertion": "\u22A6",
+    "/asterisk": "\u002A",
+    "/asteriskaltonearabic": "\u066D",
+    "/asteriskarabic": "\u066D",
+    "/asteriskmath": "\u2217",
+    "/asteriskmonospace": "\uFF0A",
+    "/asterisksmall": "\uFE61",
+    "/asterism": "\u2042",
+    "/astonishedFace": "\u1F632",
+    "/astroke": "\u2C65",
+    "/astronomicaluranus": "\u26E2",
+    "/asuperior": "\uF6E9",
+    "/asympticallyequal": "\u2243",
+    "/asymptoticallyequal": "\u2243",
+    "/at": "\u0040",
+    "/athleticShoe": "\u1F45F",
+    "/atilde": "\u00E3",
+    "/atmonospace": "\uFF20",
+    "/atnachHafukh:hb": "\u05A2",
+    "/atom": "\u269B",
+    "/atsmall": "\uFE6B",
+    "/attentionideographiccircled": "\u329F",
+    "/aturned": "\u0250",
+    "/au": "\uA737",
+    "/aubengali": "\u0994",
+    "/aubergine": "\u1F346",
+    "/aubopomofo": "\u3120",
+    "/audeva": "\u0914",
+    "/aufullwidth": "\u3373",
+    "/augujarati": "\u0A94",
+    "/augurmukhi": "\u0A14",
+    "/augusttelegraph": "\u32C7",
+    "/aulengthmarkbengali": "\u09D7",
+    "/aumatragurmukhi": "\u0A4C",
+    "/austral": "\u20B3",
+    "/automatedTellerMachine": "\u1F3E7",
+    "/automobile": "\u1F697",
+    "/auvowelsignbengali": "\u09CC",
+    "/auvowelsigndeva": "\u094C",
+    "/auvowelsigngujarati": "\u0ACC",
+    "/av": "\uA739",
+    "/avagrahadeva": "\u093D",
+    "/avhorizontalbar": "\uA73B",
+    "/ay": "\uA73D",
+    "/aybarmenian": "\u0561",
+    "/ayin": "\u05E2",
+    "/ayin:hb": "\u05E2",
+    "/ayinalt:hb": "\uFB20",
+    "/ayinaltonehebrew": "\uFB20",
+    "/ayinhebrew": "\u05E2",
+    "/azla:hb": "\u059C",
+    "/b": "\u0062",
+    "/baarerusquare": "\u332D",
+    "/babengali": "\u09AC",
+    "/babyAngel": "\u1F47C",
+    "/babyBottle": "\u1F37C",
+    "/babyChick": "\u1F424",
+    "/backLeftwardsArrowAbove": "\u1F519",
+    "/backOfEnvelope": "\u1F582",
+    "/backslash": "\u005C",
+    "/backslashbarfunc": "\u2340",
+    "/backslashdbl": "\u244A",
+    "/backslashmonospace": "\uFF3C",
+    "/bactrianCamel": "\u1F42B",
+    "/badeva": "\u092C",
+    "/badmintonRacquetAndShuttlecock": "\u1F3F8",
+    "/bagdelimitersshapeleft": "\u27C5",
+    "/bagdelimitersshaperight": "\u27C6",
+    "/baggageClaim": "\u1F6C4",
+    "/bagujarati": "\u0AAC",
+    "/bagurmukhi": "\u0A2C",
+    "/bahiragana": "\u3070",
+    "/bahtthai": "\u0E3F",
+    "/bakatakana": "\u30D0",
+    "/balloon": "\u1F388",
+    "/ballotBoldScriptX": "\u1F5F6",
+    "/ballotBoxBallot": "\u1F5F3",
+    "/ballotBoxBoldCheck": "\u1F5F9",
+    "/ballotBoxBoldScriptX": "\u1F5F7",
+    "/ballotBoxScriptX": "\u1F5F5",
+    "/ballotScriptX": "\u1F5F4",
+    "/bamurda": "\uA9A8",
+    "/banana": "\u1F34C",
+    "/bank": "\u1F3E6",
+    "/banknoteDollarSign": "\u1F4B5",
+    "/banknoteEuroSign": "\u1F4B6",
+    "/banknotePoundSign": "\u1F4B7",
+    "/banknoteYenSign": "\u1F4B4",
+    "/bar": "\u007C",
+    "/barChart": "\u1F4CA",
+    "/barberPole": "\u1F488",
+    "/barfullwidth": "\u3374",
+    "/barmonospace": "\uFF5C",
+    "/barquillverticalleft": "\u2E20",
+    "/barquillverticalright": "\u2E21",
+    "/baseball": "\u26BE",
+    "/basketballAndHoop": "\u1F3C0",
+    "/bath": "\u1F6C0",
+    "/bathtub": "\u1F6C1",
+    "/battery": "\u1F50B",
+    "/bbopomofo": "\u3105",
+    "/bcircle": "\u24D1",
+    "/bdot": "\u1E03",
+    "/bdotaccent": "\u1E03",
+    "/bdotbelow": "\u1E05",
+    "/beachUmbrella": "\u1F3D6",
+    "/beamedAscendingMusicalNotes": "\u1F39C",
+    "/beamedDescendingMusicalNotes": "\u1F39D",
+    "/beamedeighthnotes": "\u266B",
+    "/beamedsixteenthnotes": "\u266C",
+    "/beamfunc": "\u2336",
+    "/bearFace": "\u1F43B",
+    "/beatingHeart": "\u1F493",
+    "/because": "\u2235",
+    "/becyr": "\u0431",
+    "/becyrillic": "\u0431",
+    "/bed": "\u1F6CF",
+    "/beeh": "\u067B",
+    "/beeh.fina": "\uFB53",
+    "/beeh.init": "\uFB54",
+    "/beeh.isol": "\uFB52",
+    "/beeh.medi": "\uFB55",
+    "/beerMug": "\u1F37A",
+    "/beetasquare": "\u333C",
+    "/beh": "\u0628",
+    "/beh.fina": "\uFE90",
+    "/beh.init": "\uFE91",
+    "/beh.init_alefmaksura.fina": "\uFC09",
+    "/beh.init_hah.fina": "\uFC06",
+    "/beh.init_hah.medi": "\uFC9D",
+    "/beh.init_heh.medi": "\uFCA0",
+    "/beh.init_jeem.fina": "\uFC05",
+    "/beh.init_jeem.medi": "\uFC9C",
+    "/beh.init_khah.fina": "\uFC07",
+    "/beh.init_khah.medi": "\uFC9E",
+    "/beh.init_meem.fina": "\uFC08",
+    "/beh.init_meem.medi": "\uFC9F",
+    "/beh.init_yeh.fina": "\uFC0A",
+    "/beh.isol": "\uFE8F",
+    "/beh.medi": "\uFE92",
+    "/beh.medi_alefmaksura.fina": "\uFC6E",
+    "/beh.medi_hah.medi_yeh.fina": "\uFDC2",
+    "/beh.medi_heh.medi": "\uFCE2",
+    "/beh.medi_khah.medi_yeh.fina": "\uFD9E",
+    "/beh.medi_meem.fina": "\uFC6C",
+    "/beh.medi_meem.medi": "\uFCE1",
+    "/beh.medi_noon.fina": "\uFC6D",
+    "/beh.medi_reh.fina": "\uFC6A",
+    "/beh.medi_yeh.fina": "\uFC6F",
+    "/beh.medi_zain.fina": "\uFC6B",
+    "/behDotBelowThreeDotsAbove": "\u0751",
+    "/behInvertedSmallVBelow": "\u0755",
+    "/behSmallV": "\u0756",
+    "/behThreeDotsHorizontallyBelow": "\u0750",
+    "/behThreeDotsUpBelow": "\u0752",
+    "/behThreeDotsUpBelowTwoDotsAbove": "\u0753",
+    "/behTwoDotsBelowDotAbove": "\u0754",
+    "/beharabic": "\u0628",
+    "/beheh": "\u0680",
+    "/beheh.fina": "\uFB5B",
+    "/beheh.init": "\uFB5C",
+    "/beheh.isol": "\uFB5A",
+    "/beheh.medi": "\uFB5D",
+    "/behfinalarabic": "\uFE90",
+    "/behinitialarabic": "\uFE91",
+    "/behiragana": "\u3079",
+    "/behmedialarabic": "\uFE92",
+    "/behmeeminitialarabic": "\uFC9F",
+    "/behmeemisolatedarabic": "\uFC08",
+    "/behnoonfinalarabic": "\uFC6D",
+    "/bekatakana": "\u30D9",
+    "/bellCancellationStroke": "\u1F515",
+    "/bellhopBell": "\u1F6CE",
+    "/beltbuckle": "\u2444",
+    "/benarmenian": "\u0562",
+    "/beng:a": "\u0985",
+    "/beng:aa": "\u0986",
+    "/beng:aasign": "\u09BE",
+    "/beng:abbreviationsign": "\u09FD",
+    "/beng:ai": "\u0990",
+    "/beng:aisign": "\u09C8",
+    "/beng:anji": "\u0980",
+    "/beng:anusvara": "\u0982",
+    "/beng:au": "\u0994",
+    "/beng:aulengthmark": "\u09D7",
+    "/beng:ausign": "\u09CC",
+    "/beng:avagraha": "\u09BD",
+    "/beng:ba": "\u09AC",
+    "/beng:bha": "\u09AD",
+    "/beng:ca": "\u099A",
+    "/beng:candrabindu": "\u0981",
+    "/beng:cha": "\u099B",
+    "/beng:currencyoneless": "\u09F8",
+    "/beng:da": "\u09A6",
+    "/beng:dda": "\u09A1",
+    "/beng:ddha": "\u09A2",
+    "/beng:dha": "\u09A7",
+    "/beng:e": "\u098F",
+    "/beng:eight": "\u09EE",
+    "/beng:esign": "\u09C7",
+    "/beng:five": "\u09EB",
+    "/beng:four": "\u09EA",
+    "/beng:fourcurrencynumerator": "\u09F7",
+    "/beng:ga": "\u0997",
+    "/beng:gandamark": "\u09FB",
+    "/beng:gha": "\u0998",
+    "/beng:ha": "\u09B9",
+    "/beng:i": "\u0987",
+    "/beng:ii": "\u0988",
+    "/beng:iisign": "\u09C0",
+    "/beng:isign": "\u09BF",
+    "/beng:isshar": "\u09FA",
+    "/beng:ja": "\u099C",
+    "/beng:jha": "\u099D",
+    "/beng:ka": "\u0995",
+    "/beng:kha": "\u0996",
+    "/beng:khandata": "\u09CE",
+    "/beng:la": "\u09B2",
+    "/beng:llvocal": "\u09E1",
+    "/beng:llvocalsign": "\u09E3",
+    "/beng:lvocal": "\u098C",
+    "/beng:lvocalsign": "\u09E2",
+    "/beng:ma": "\u09AE",
+    "/beng:na": "\u09A8",
+    "/beng:nga": "\u0999",
+    "/beng:nine": "\u09EF",
+    "/beng:nna": "\u09A3",
+    "/beng:nukta": "\u09BC",
+    "/beng:nya": "\u099E",
+    "/beng:o": "\u0993",
+    "/beng:one": "\u09E7",
+    "/beng:onecurrencynumerator": "\u09F4",
+    "/beng:osign": "\u09CB",
+    "/beng:pa": "\u09AA",
+    "/beng:pha": "\u09AB",
+    "/beng:ra": "\u09B0",
+    "/beng:ralowdiagonal": "\u09F1",
+    "/beng:ramiddiagonal": "\u09F0",
+    "/beng:rha": "\u09DD",
+    "/beng:rra": "\u09DC",
+    "/beng:rrvocal": "\u09E0",
+    "/beng:rrvocalsign": "\u09C4",
+    "/beng:rupee": "\u09F3",
+    "/beng:rupeemark": "\u09F2",
+    "/beng:rvocal": "\u098B",
+    "/beng:rvocalsign": "\u09C3",
+    "/beng:sa": "\u09B8",
+    "/beng:seven": "\u09ED",
+    "/beng:sha": "\u09B6",
+    "/beng:six": "\u09EC",
+    "/beng:sixteencurrencydenominator": "\u09F9",
+    "/beng:ssa": "\u09B7",
+    "/beng:ta": "\u09A4",
+    "/beng:tha": "\u09A5",
+    "/beng:three": "\u09E9",
+    "/beng:threecurrencynumerator": "\u09F6",
+    "/beng:tta": "\u099F",
+    "/beng:ttha": "\u09A0",
+    "/beng:two": "\u09E8",
+    "/beng:twocurrencynumerator": "\u09F5",
+    "/beng:u": "\u0989",
+    "/beng:usign": "\u09C1",
+    "/beng:uu": "\u098A",
+    "/beng:uusign": "\u09C2",
+    "/beng:vedicanusvara": "\u09FC",
+    "/beng:virama": "\u09CD",
+    "/beng:visarga": "\u0983",
+    "/beng:ya": "\u09AF",
+    "/beng:yya": "\u09DF",
+    "/beng:zero": "\u09E6",
+    "/bentoBox": "\u1F371",
+    "/benzenering": "\u232C",
+    "/benzeneringcircle": "\u23E3",
+    "/bet": "\u05D1",
+    "/bet:hb": "\u05D1",
+    "/beta": "\u03B2",
+    "/betasymbol": "\u03D0",
+    "/betasymbolgreek": "\u03D0",
+    "/betdagesh": "\uFB31",
+    "/betdageshhebrew": "\uFB31",
+    "/bethebrew": "\u05D1",
+    "/betrafehebrew": "\uFB4C",
+    "/between": "\u226C",
+    "/betwithdagesh:hb": "\uFB31",
+    "/betwithrafe:hb": "\uFB4C",
+    "/bflourish": "\uA797",
+    "/bhabengali": "\u09AD",
+    "/bhadeva": "\u092D",
+    "/bhagujarati": "\u0AAD",
+    "/bhagurmukhi": "\u0A2D",
+    "/bhook": "\u0253",
+    "/bicycle": "\u1F6B2",
+    "/bicyclist": "\u1F6B4",
+    "/bihiragana": "\u3073",
+    "/bikatakana": "\u30D3",
+    "/bikini": "\u1F459",
+    "/bilabialclick": "\u0298",
+    "/billiards": "\u1F3B1",
+    "/bindigurmukhi": "\u0A02",
+    "/biohazard": "\u2623",
+    "/bird": "\u1F426",
+    "/birthdayCake": "\u1F382",
+    "/birusquare": "\u3331",
+    "/bishopblack": "\u265D",
+    "/bishopwhite": "\u2657",
+    "/bitcoin": "\u20BF",
+    "/blackDownPointingBackhandIndex": "\u1F5A3",
+    "/blackDroplet": "\u1F322",
+    "/blackFolder": "\u1F5BF",
+    "/blackHardShellFloppyDisk": "\u1F5AA",
+    "/blackHeart": "\u1F5A4",
+    "/blackLeftPointingBackhandIndex": "\u1F59C",
+    "/blackPennant": "\u1F3F2",
+    "/blackPushpin": "\u1F588",
+    "/blackRightPointingBackhandIndex": "\u1F59D",
+    "/blackRosette": "\u1F3F6",
+    "/blackSkullAndCrossbones": "\u1F571",
+    "/blackSquareButton": "\u1F532",
+    "/blackTouchtoneTelephone": "\u1F57F",
+    "/blackUpPointingBackhandIndex": "\u1F5A2",
+    "/blackcircle": "\u25CF",
+    "/blackcircleforrecord": "\u23FA",
+    "/blackdiamond": "\u25C6",
+    "/blackdownpointingtriangle": "\u25BC",
+    "/blackforstopsquare": "\u23F9",
+    "/blackleftpointingpointer": "\u25C4",
+    "/blackleftpointingtriangle": "\u25C0",
+    "/blacklenticularbracketleft": "\u3010",
+    "/blacklenticularbracketleftvertical": "\uFE3B",
+    "/blacklenticularbracketright": "\u3011",
+    "/blacklenticularbracketrightvertical": "\uFE3C",
+    "/blacklowerlefttriangle": "\u25E3",
+    "/blacklowerrighttriangle": "\u25E2",
+    "/blackmediumpointingtriangledown": "\u23F7",
+    "/blackmediumpointingtriangleleft": "\u23F4",
+    "/blackmediumpointingtriangleright": "\u23F5",
+    "/blackmediumpointingtriangleup": "\u23F6",
+    "/blackpointingdoubletrianglebarverticalleft": "\u23EE",
+    "/blackpointingdoubletrianglebarverticalright": "\u23ED",
+    "/blackpointingdoubletriangledown": "\u23EC",
+    "/blackpointingdoubletriangleleft": "\u23EA",
+    "/blackpointingdoubletriangleright": "\u23E9",
+    "/blackpointingdoubletriangleup": "\u23EB",
+    "/blackpointingtriangledoublebarverticalright": "\u23EF",
+    "/blackrectangle": "\u25AC",
+    "/blackrightpointingpointer": "\u25BA",
+    "/blackrightpointingtriangle": "\u25B6",
+    "/blacksmallsquare": "\u25AA",
+    "/blacksmilingface": "\u263B",
+    "/blacksquare": "\u25A0",
+    "/blackstar": "\u2605",
+    "/blackupperlefttriangle": "\u25E4",
+    "/blackupperrighttriangle": "\u25E5",
+    "/blackuppointingsmalltriangle": "\u25B4",
+    "/blackuppointingtriangle": "\u25B2",
+    "/blackwardsbulletleft": "\u204C",
+    "/blackwardsbulletright": "\u204D",
+    "/blank": "\u2423",
+    "/blinebelow": "\u1E07",
+    "/block": "\u2588",
+    "/blossom": "\u1F33C",
+    "/blowfish": "\u1F421",
+    "/blueBook": "\u1F4D8",
+    "/blueHeart": "\u1F499",
+    "/bmonospace": "\uFF42",
+    "/boar": "\u1F417",
+    "/board": "\u2328",
+    "/bobaimaithai": "\u0E1A",
+    "/bohiragana": "\u307C",
+    "/bokatakana": "\u30DC",
+    "/bomb": "\u1F4A3",
+    "/book": "\u1F56E",
+    "/bookmark": "\u1F516",
+    "/bookmarkTabs": "\u1F4D1",
+    "/books": "\u1F4DA",
+    "/bopo:a": "\u311A",
+    "/bopo:ai": "\u311E",
+    "/bopo:an": "\u3122",
+    "/bopo:ang": "\u3124",
+    "/bopo:au": "\u3120",
+    "/bopo:b": "\u3105",
+    "/bopo:c": "\u3118",
+    "/bopo:ch": "\u3114",
+    "/bopo:d": "\u3109",
+    "/bopo:e": "\u311C",
+    "/bopo:eh": "\u311D",
+    "/bopo:ei": "\u311F",
+    "/bopo:en": "\u3123",
+    "/bopo:eng": "\u3125",
+    "/bopo:er": "\u3126",
+    "/bopo:f": "\u3108",
+    "/bopo:g": "\u310D",
+    "/bopo:gn": "\u312C",
+    "/bopo:h": "\u310F",
+    "/bopo:i": "\u3127",
+    "/bopo:ih": "\u312D",
+    "/bopo:iu": "\u3129",
+    "/bopo:j": "\u3110",
+    "/bopo:k": "\u310E",
+    "/bopo:l": "\u310C",
+    "/bopo:m": "\u3107",
+    "/bopo:n": "\u310B",
+    "/bopo:ng": "\u312B",
+    "/bopo:o": "\u311B",
+    "/bopo:ou": "\u3121",
+    "/bopo:owithdotabove": "\u312E",
+    "/bopo:p": "\u3106",
+    "/bopo:q": "\u3111",
+    "/bopo:r": "\u3116",
+    "/bopo:s": "\u3119",
+    "/bopo:sh": "\u3115",
+    "/bopo:t": "\u310A",
+    "/bopo:u": "\u3128",
+    "/bopo:v": "\u312A",
+    "/bopo:x": "\u3112",
+    "/bopo:z": "\u3117",
+    "/bopo:zh": "\u3113",
+    "/borutosquare": "\u333E",
+    "/bottlePoppingCork": "\u1F37E",
+    "/bouquet": "\u1F490",
+    "/bouquetOfFlowers": "\u1F395",
+    "/bowAndArrow": "\u1F3F9",
+    "/bowlOfHygieia": "\u1F54F",
+    "/bowling": "\u1F3B3",
+    "/boxlineverticalleft": "\u23B8",
+    "/boxlineverticalright": "\u23B9",
+    "/boy": "\u1F466",
+    "/boys": "\u1F6C9",
+    "/bparen": "\u249D",
+    "/bparenthesized": "\u249D",
+    "/bqfullwidth": "\u33C3",
+    "/bqsquare": "\u33C3",
+    "/braceex": "\uF8F4",
+    "/braceleft": "\u007B",
+    "/braceleftbt": "\uF8F3",
+    "/braceleftmid": "\uF8F2",
+    "/braceleftmonospace": "\uFF5B",
+    "/braceleftsmall": "\uFE5B",
+    "/bracelefttp": "\uF8F1",
+    "/braceleftvertical": "\uFE37",
+    "/braceright": "\u007D",
+    "/bracerightbt": "\uF8FE",
+    "/bracerightmid": "\uF8FD",
+    "/bracerightmonospace": "\uFF5D",
+    "/bracerightsmall": "\uFE5C",
+    "/bracerighttp": "\uF8FC",
+    "/bracerightvertical": "\uFE38",
+    "/bracketangledblleft": "\u27EA",
+    "/bracketangledblright": "\u27EB",
+    "/bracketangleleft": "\u27E8",
+    "/bracketangleright": "\u27E9",
+    "/bracketbottomcurly": "\u23DF",
+    "/bracketbottomsquare": "\u23B5",
+    "/bracketcornerupleftsquare": "\u23A1",
+    "/bracketcorneruprightsquare": "\u23A4",
+    "/bracketdottedsubstitutionleft": "\u2E04",
+    "/bracketdottedsubstitutionright": "\u2E05",
+    "/bracketextensioncurly": "\u23AA",
+    "/bracketextensionleftsquare": "\u23A2",
+    "/bracketextensionrightsquare": "\u23A5",
+    "/brackethalfbottomleft": "\u2E24",
+    "/brackethalfbottomright": "\u2E25",
+    "/brackethalftopleft": "\u2E22",
+    "/brackethalftopright": "\u2E23",
+    "/brackethookupleftcurly": "\u23A7",
+    "/brackethookuprightcurly": "\u23AB",
+    "/bracketleft": "\u005B",
+    "/bracketleftbt": "\uF8F0",
+    "/bracketleftex": "\uF8EF",
+    "/bracketleftmonospace": "\uFF3B",
+    "/bracketleftsquarequill": "\u2045",
+    "/bracketlefttp": "\uF8EE",
+    "/bracketlowercornerleftsquare": "\u23A3",
+    "/bracketlowercornerrightsquare": "\u23A6",
+    "/bracketlowerhookleftcurly": "\u23A9",
+    "/bracketlowerhookrightcurly": "\u23AD",
+    "/bracketmiddlepieceleftcurly": "\u23A8",
+    "/bracketmiddlepiecerightcurly": "\u23AC",
+    "/bracketoverbrackettopbottomsquare": "\u23B6",
+    "/bracketparaphraselowleft": "\u2E1C",
+    "/bracketparaphraselowright": "\u2E1D",
+    "/bracketraisedleft": "\u2E0C",
+    "/bracketraisedright": "\u2E0D",
+    "/bracketright": "\u005D",
+    "/bracketrightbt": "\uF8FB",
+    "/bracketrightex": "\uF8FA",
+    "/bracketrightmonospace": "\uFF3D",
+    "/bracketrightsquarequill": "\u2046",
+    "/bracketrighttp": "\uF8F9",
+    "/bracketsectionupleftlowerrightcurly": "\u23B0",
+    "/bracketsectionuprightlowerleftcurly": "\u23B1",
+    "/bracketshellbottom": "\u23E1",
+    "/bracketshelltop": "\u23E0",
+    "/bracketshellwhiteleft": "\u27EC",
+    "/bracketshellwhiteright": "\u27ED",
+    "/bracketsubstitutionleft": "\u2E02",
+    "/bracketsubstitutionright": "\u2E03",
+    "/brackettopcurly": "\u23DE",
+    "/brackettopsquare": "\u23B4",
+    "/brackettranspositionleft": "\u2E09",
+    "/brackettranspositionright": "\u2E0A",
+    "/bracketwhitesquareleft": "\u27E6",
+    "/bracketwhitesquareright": "\u27E7",
+    "/branchbankidentification": "\u2446",
+    "/bread": "\u1F35E",
+    "/breve": "\u02D8",
+    "/brevebelowcmb": "\u032E",
+    "/brevecmb": "\u0306",
+    "/breveinvertedbelowcmb": "\u032F",
+    "/breveinvertedcmb": "\u0311",
+    "/breveinverteddoublecmb": "\u0361",
+    "/brevemetrical": "\u23D1",
+    "/brideVeil": "\u1F470",
+    "/bridgeAtNight": "\u1F309",
+    "/bridgebelowcmb": "\u032A",
+    "/bridgeinvertedbelowcmb": "\u033A",
+    "/briefcase": "\u1F4BC",
+    "/brll:blank": "\u2800",
+    "/brokenHeart": "\u1F494",
+    "/brokenbar": "\u00A6",
+    "/brokencirclenorthwestarrow": "\u238B",
+    "/bstroke": "\u0180",
+    "/bsuperior": "\uF6EA",
+    "/btopbar": "\u0183",
+    "/bug": "\u1F41B",
+    "/buhiragana": "\u3076",
+    "/buildingConstruction": "\u1F3D7",
+    "/bukatakana": "\u30D6",
+    "/bullet": "\u2022",
+    "/bulletinverse": "\u25D8",
+    "/bulletoperator": "\u2219",
+    "/bullhorn": "\u1F56B",
+    "/bullhornSoundWaves": "\u1F56C",
+    "/bullseye": "\u25CE",
+    "/burrito": "\u1F32F",
+    "/bus": "\u1F68C",
+    "/busStop": "\u1F68F",
+    "/bussyerusquare": "\u3334",
+    "/bustInSilhouette": "\u1F464",
+    "/bustsInSilhouette": "\u1F465",
+    "/c": "\u0063",
+    "/caarmenian": "\u056E",
+    "/cabengali": "\u099A",
+    "/cactus": "\u1F335",
+    "/cacute": "\u0107",
+    "/cadauna": "\u2106",
+    "/cadeva": "\u091A",
+    "/caduceus": "\u2624",
+    "/cagujarati": "\u0A9A",
+    "/cagurmukhi": "\u0A1A",
+    "/cakraconsonant": "\uA9BF",
+    "/calendar": "\u1F4C5",
+    "/calfullwidth": "\u3388",
+    "/callideographicparen": "\u323A",
+    "/calsquare": "\u3388",
+    "/camera": "\u1F4F7",
+    "/cameraFlash": "\u1F4F8",
+    "/camping": "\u1F3D5",
+    "/camurda": "\uA996",
+    "/cancellationX": "\u1F5D9",
+    "/cancer": "\u264B",
+    "/candle": "\u1F56F",
+    "/candrabindubengali": "\u0981",
+    "/candrabinducmb": "\u0310",
+    "/candrabindudeva": "\u0901",
+    "/candrabindugujarati": "\u0A81",
+    "/candy": "\u1F36C",
+    "/canoe": "\u1F6F6",
+    "/capitulum": "\u2E3F",
+    "/capricorn": "\u2651",
+    "/capslock": "\u21EA",
+    "/cardFileBox": "\u1F5C3",
+    "/cardIndex": "\u1F4C7",
+    "/cardIndexDividers": "\u1F5C2",
+    "/careof": "\u2105",
+    "/caret": "\u2038",
+    "/caretinsertionpoint": "\u2041",
+    "/carettildedownfunc": "\u2371",
+    "/carettildeupfunc": "\u2372",
+    "/caron": "\u02C7",
+    "/caronbelowcmb": "\u032C",
+    "/caroncmb": "\u030C",
+    "/carouselHorse": "\u1F3A0",
+    "/carpStreamer": "\u1F38F",
+    "/carriagereturn": "\u21B5",
+    "/carsliding": "\u26D0",
+    "/castle": "\u26EB",
+    "/cat": "\u1F408",
+    "/catFace": "\u1F431",
+    "/catFaceWithTearsOfJoy": "\u1F639",
+    "/catFaceWithWrySmile": "\u1F63C",
+    "/caution": "\u2621",
+    "/cbar": "\uA793",
+    "/cbopomofo": "\u3118",
+    "/ccaron": "\u010D",
+    "/ccedilla": "\u00E7",
+    "/ccedillaacute": "\u1E09",
+    "/ccfullwidth": "\u33C4",
+    "/ccircle": "\u24D2",
+    "/ccircumflex": "\u0109",
+    "/ccurl": "\u0255",
+    "/cdfullwidth": "\u33C5",
+    "/cdot": "\u010B",
+    "/cdotaccent": "\u010B",
+    "/cdotreversed": "\uA73F",
+    "/cdsquare": "\u33C5",
+    "/cecak": "\uA981",
+    "/cecaktelu": "\uA9B3",
+    "/cedi": "\u20B5",
+    "/cedilla": "\u00B8",
+    "/cedillacmb": "\u0327",
+    "/ceilingleft": "\u2308",
+    "/ceilingright": "\u2309",
+    "/celticCross": "\u1F548",
+    "/cent": "\u00A2",
+    "/centigrade": "\u2103",
+    "/centinferior": "\uF6DF",
+    "/centmonospace": "\uFFE0",
+    "/centoldstyle": "\uF7A2",
+    "/centreddotwhitediamond": "\u27D0",
+    "/centreideographiccircled": "\u32A5",
+    "/centreline": "\u2104",
+    "/centrelineverticalsquarewhite": "\u2385",
+    "/centsuperior": "\uF6E0",
+    "/ceres": "\u26B3",
+    "/chaarmenian": "\u0579",
+    "/chabengali": "\u099B",
+    "/chadeva": "\u091B",
+    "/chagujarati": "\u0A9B",
+    "/chagurmukhi": "\u0A1B",
+    "/chains": "\u26D3",
+    "/chair": "\u2441",
+    "/chamkocircle": "\u327C",
+    "/charactertie": "\u2040",
+    "/chartDownwardsTrend": "\u1F4C9",
+    "/chartUpwardsTrend": "\u1F4C8",
+    "/chartUpwardsTrendAndYenSign": "\u1F4B9",
+    "/chbopomofo": "\u3114",
+    "/cheabkhasiancyrillic": "\u04BD",
+    "/cheabkhcyr": "\u04BD",
+    "/cheabkhtailcyr": "\u04BF",
+    "/checkbox": "\u2610",
+    "/checkboxchecked": "\u2611",
+    "/checkboxx": "\u2612",
+    "/checkmark": "\u2713",
+    "/checyr": "\u0447",
+    "/checyrillic": "\u0447",
+    "/chedescenderabkhasiancyrillic": "\u04BF",
+    "/chedescendercyrillic": "\u04B7",
+    "/chedieresiscyr": "\u04F5",
+    "/chedieresiscyrillic": "\u04F5",
+    "/cheeringMegaphone": "\u1F4E3",
+    "/cheharmenian": "\u0573",
+    "/chekhakascyr": "\u04CC",
+    "/chekhakassiancyrillic": "\u04CC",
+    "/chequeredFlag": "\u1F3C1",
+    "/cherries": "\u1F352",
+    "/cherryBlossom": "\u1F338",
+    "/chestnut": "\u1F330",
+    "/chetailcyr": "\u04B7",
+    "/chevertcyr": "\u04B9",
+    "/cheverticalstrokecyrillic": "\u04B9",
+    "/chi": "\u03C7",
+    "/chicken": "\u1F414",
+    "/chieuchacirclekorean": "\u3277",
+    "/chieuchaparenkorean": "\u3217",
+    "/chieuchcirclekorean": "\u3269",
+    "/chieuchkorean": "\u314A",
+    "/chieuchparenkorean": "\u3209",
+    "/childrenCrossing": "\u1F6B8",
+    "/chipmunk": "\u1F43F",
+    "/chirho": "\u2627",
+    "/chiron": "\u26B7",
+    "/chochangthai": "\u0E0A",
+    "/chochanthai": "\u0E08",
+    "/chochingthai": "\u0E09",
+    "/chochoethai": "\u0E0C",
+    "/chocolateBar": "\u1F36B",
+    "/chook": "\u0188",
+    "/christmasTree": "\u1F384",
+    "/church": "\u26EA",
+    "/cieucacirclekorean": "\u3276",
+    "/cieucaparenkorean": "\u3216",
+    "/cieuccirclekorean": "\u3268",
+    "/cieuckorean": "\u3148",
+    "/cieucparenkorean": "\u3208",
+    "/cieucuparenkorean": "\u321C",
+    "/cinema": "\u1F3A6",
+    "/circle": "\u25CB",
+    "/circleallbutupperquadrantleftblack": "\u25D5",
+    "/circlebackslashfunc": "\u2349",
+    "/circleblack": "\u25CF",
+    "/circledCrossPommee": "\u1F540",
+    "/circledInformationSource": "\u1F6C8",
+    "/circledasteriskoperator": "\u229B",
+    "/circledbarnotchhorizontal": "\u2389",
+    "/circledcrossinglanes": "\u26D2",
+    "/circleddash": "\u229D",
+    "/circleddivisionslash": "\u2298",
+    "/circleddotoperator": "\u2299",
+    "/circledequals": "\u229C",
+    "/circlediaeresisfunc": "\u2365",
+    "/circledminus": "\u2296",
+    "/circledot": "\u2299",
+    "/circledotrightwhite": "\u2686",
+    "/circledotted": "\u25CC",
+    "/circledringoperator": "\u229A",
+    "/circledtriangledown": "\u238A",
+    "/circlehalfleftblack": "\u25D0",
+    "/circlehalfrightblack": "\u25D1",
+    "/circleinversewhite": "\u25D9",
+    "/circlejotfunc": "\u233E",
+    "/circlelowerhalfblack": "\u25D2",
+    "/circlelowerquadrantleftwhite": "\u25F5",
+    "/circlelowerquadrantrightwhite": "\u25F6",
+    "/circlemultiply": "\u2297",
+    "/circleot": "\u2299",
+    "/circleplus": "\u2295",
+    "/circlepostalmark": "\u3036",
+    "/circlestarfunc": "\u235F",
+    "/circlestilefunc": "\u233D",
+    "/circlestroketwodotsaboveheavy": "\u26E3",
+    "/circletwodotsblackwhite": "\u2689",
+    "/circletwodotswhite": "\u2687",
+    "/circleunderlinefunc": "\u235C",
+    "/circleupperhalfblack": "\u25D3",
+    "/circleupperquadrantleftwhite": "\u25F4",
+    "/circleupperquadrantrightblack": "\u25D4",
+    "/circleupperquadrantrightwhite": "\u25F7",
+    "/circleverticalfill": "\u25CD",
+    "/circlewhite": "\u25CB",
+    "/circlewhitedotrightblack": "\u2688",
+    "/circlewithlefthalfblack": "\u25D0",
+    "/circlewithrighthalfblack": "\u25D1",
+    "/circumflex": "\u02C6",
+    "/circumflexbelowcmb": "\u032D",
+    "/circumflexcmb": "\u0302",
+    "/circumflexlow": "\uA788",
+    "/circusTent": "\u1F3AA",
+    "/cityscape": "\u1F3D9",
+    "/cityscapeAtDusk": "\u1F306",
+    "/cjk:ideographiccomma": "\u3001",
+    "/cjk:tortoiseshellbracketleft": "\u3014",
+    "/cjk:tortoiseshellbracketright": "\u3015",
+    "/clamshellMobilePhone": "\u1F581",
+    "/clapperBoard": "\u1F3AC",
+    "/clappingHandsSign": "\u1F44F",
+    "/classicalBuilding": "\u1F3DB",
+    "/clear": "\u2327",
+    "/clearscreen": "\u239A",
+    "/clickalveolar": "\u01C2",
+    "/clickbilabial": "\u0298",
+    "/clickdental": "\u01C0",
+    "/clicklateral": "\u01C1",
+    "/clickretroflex": "\u01C3",
+    "/clinkingBeerMugs": "\u1F37B",
+    "/clipboard": "\u1F4CB",
+    "/clockFaceEight-thirty": "\u1F563",
+    "/clockFaceEightOclock": "\u1F557",
+    "/clockFaceEleven-thirty": "\u1F566",
+    "/clockFaceElevenOclock": "\u1F55A",
+    "/clockFaceFive-thirty": "\u1F560",
+    "/clockFaceFiveOclock": "\u1F554",
+    "/clockFaceFour-thirty": "\u1F55F",
+    "/clockFaceFourOclock": "\u1F553",
+    "/clockFaceNine-thirty": "\u1F564",
+    "/clockFaceNineOclock": "\u1F558",
+    "/clockFaceOne-thirty": "\u1F55C",
+    "/clockFaceOneOclock": "\u1F550",
+    "/clockFaceSeven-thirty": "\u1F562",
+    "/clockFaceSevenOclock": "\u1F556",
+    "/clockFaceSix-thirty": "\u1F561",
+    "/clockFaceSixOclock": "\u1F555",
+    "/clockFaceTen-thirty": "\u1F565",
+    "/clockFaceTenOclock": "\u1F559",
+    "/clockFaceThree-thirty": "\u1F55E",
+    "/clockFaceThreeOclock": "\u1F552",
+    "/clockFaceTwelve-thirty": "\u1F567",
+    "/clockFaceTwelveOclock": "\u1F55B",
+    "/clockFaceTwo-thirty": "\u1F55D",
+    "/clockFaceTwoOclock": "\u1F551",
+    "/clockwiseDownwardsAndUpwardsOpenCircleArrows": "\u1F503",
+    "/clockwiseRightAndLeftSemicircleArrows": "\u1F5D8",
+    "/clockwiseRightwardsAndLeftwardsOpenCircleArrows": "\u1F501",
+    "/clockwiseRightwardsAndLeftwardsOpenCircleArrowsCircledOneOverlay": "\u1F502",
+    "/closedBook": "\u1F4D5",
+    "/closedLockKey": "\u1F510",
+    "/closedMailboxLoweredFlag": "\u1F4EA",
+    "/closedMailboxRaisedFlag": "\u1F4EB",
+    "/closedUmbrella": "\u1F302",
+    "/closedentryleft": "\u26DC",
+    "/closeup": "\u2050",
+    "/cloud": "\u2601",
+    "/cloudLightning": "\u1F329",
+    "/cloudRain": "\u1F327",
+    "/cloudSnow": "\u1F328",
+    "/cloudTornado": "\u1F32A",
+    "/clsquare": "\u1F191",
+    "/club": "\u2663",
+    "/clubblack": "\u2663",
+    "/clubsuitblack": "\u2663",
+    "/clubsuitwhite": "\u2667",
+    "/clubwhite": "\u2667",
+    "/cm2fullwidth": "\u33A0",
+    "/cm3fullwidth": "\u33A4",
+    "/cmb:a": "\u0363",
+    "/cmb:aaboveflat": "\u1DD3",
+    "/cmb:aboveogonek": "\u1DCE",
+    "/cmb:acute": "\u0301",
+    "/cmb:acutebelow": "\u0317",
+    "/cmb:acutegraveacute": "\u1DC9",
+    "/cmb:acutemacron": "\u1DC7",
+    "/cmb:acutetone": "\u0341",
+    "/cmb:adieresis": "\u1DF2",
+    "/cmb:ae": "\u1DD4",
+    "/cmb:almostequalabove": "\u034C",
+    "/cmb:almostequaltobelow": "\u1DFD",
+    "/cmb:alpha": "\u1DE7",
+    "/cmb:ao": "\u1DD5",
+    "/cmb:arrowheadleftbelow": "\u0354",
+    "/cmb:arrowheadrightabove": "\u0350",
+    "/cmb:arrowheadrightarrowheadupbelow": "\u0356",
+    "/cmb:arrowheadrightbelow": "\u0355",
+    "/cmb:arrowleftrightbelow": "\u034D",
+    "/cmb:arrowrightdoublebelow": "\u0362",
+    "/cmb:arrowupbelow": "\u034E",
+    "/cmb:asteriskbelow": "\u0359",
+    "/cmb:av": "\u1DD6",
+    "/cmb:b": "\u1DE8",
+    "/cmb:belowbreve": "\u032E",
+    "/cmb:beta": "\u1DE9",
+    "/cmb:breve": "\u0306",
+    "/cmb:brevemacron": "\u1DCB",
+    "/cmb:bridgeabove": "\u0346",
+    "/cmb:bridgebelow": "\u032A",
+    "/cmb:c": "\u0368",
+    "/cmb:candrabindu": "\u0310",
+    "/cmb:caron": "\u030C",
+    "/cmb:caronbelow": "\u032C",
+    "/cmb:ccedilla": "\u1DD7",
+    "/cmb:cedilla": "\u0327",
+    "/cmb:circumflex": "\u0302",
+    "/cmb:circumflexbelow": "\u032D",
+    "/cmb:commaaccentbelow": "\u0326",
+    "/cmb:commaturnedabove": "\u0312",
+    "/cmb:d": "\u0369",
+    "/cmb:dblarchinvertedbelow": "\u032B",
+    "/cmb:dbloverline": "\u033F",
+    "/cmb:dblverticallineabove": "\u030E",
+    "/cmb:dblverticallinebelow": "\u0348",
+    "/cmb:deletionmark": "\u1DFB",
+    "/cmb:dialytikatonos": "\u0344",
+    "/cmb:dieresis": "\u0308",
+    "/cmb:dieresisbelow": "\u0324",
+    "/cmb:dotaboveleft": "\u1DF8",
+    "/cmb:dotaccent": "\u0307",
+    "/cmb:dotbelowcomb": "\u0323",
+    "/cmb:dotrightabove": "\u0358",
+    "/cmb:dottedacute": "\u1DC1",
+    "/cmb:dottedgrave": "\u1DC0",
+    "/cmb:doubleabovecircumflex": "\u1DCD",
+    "/cmb:doublebelowbreve": "\u035C",
+    "/cmb:doublebreve": "\u035D",
+    "/cmb:doubleinvertedbelowbreve": "\u1DFC",
+    "/cmb:doubleringbelow": "\u035A",
+    "/cmb:downtackbelow": "\u031E",
+    "/cmb:e": "\u0364",
+    "/cmb:equalbelow": "\u0347",
+    "/cmb:esh": "\u1DEF",
+    "/cmb:eth": "\u1DD9",
+    "/cmb:f": "\u1DEB",
+    "/cmb:fermata": "\u0352",
+    "/cmb:g": "\u1DDA",
+    "/cmb:graphemejoiner": "\u034F",
+    "/cmb:grave": "\u0300",
+    "/cmb:graveacutegrave": "\u1DC8",
+    "/cmb:gravebelow": "\u0316",
+    "/cmb:gravedouble": "\u030F",
+    "/cmb:gravemacron": "\u1DC5",
+    "/cmb:gravetone": "\u0340",
+    "/cmb:gsmall": "\u1DDB",
+    "/cmb:h": "\u036A",
+    "/cmb:halfleftringabove": "\u0351",
+    "/cmb:halfleftringbelow": "\u031C",
+    "/cmb:halfrightringabove": "\u0357",
+    "/cmb:halfrightringbelow": "\u0339",
+    "/cmb:homotheticabove": "\u034B",
+    "/cmb:hookabove": "\u0309",
+    "/cmb:horn": "\u031B",
+    "/cmb:hungarumlaut": "\u030B",
+    "/cmb:i": "\u0365",
+    "/cmb:insulard": "\u1DD8",
+    "/cmb:invertedbelowbreve": "\u032F",
+    "/cmb:invertedbreve": "\u0311",
+    "/cmb:invertedbridgebelow": "\u033A",
+    "/cmb:inverteddoublebreve": "\u0361",
+    "/cmb:iotasub": "\u0345",
+    "/cmb:isbelow": "\u1DD0",
+    "/cmb:k": "\u1DDC",
+    "/cmb:kavykaaboveleft": "\u1DF7",
+    "/cmb:kavykaaboveright": "\u1DF6",
+    "/cmb:koronis": "\u0343",
+    "/cmb:l": "\u1DDD",
+    "/cmb:leftangleabove": "\u031A",
+    "/cmb:leftanglebelow": "\u0349",
+    "/cmb:leftarrowheadabove": "\u1DFE",
+    "/cmb:lefttackbelow": "\u0318",
+    "/cmb:lineverticalabove": "\u030D",
+    "/cmb:lineverticalbelow": "\u0329",
+    "/cmb:longs": "\u1DE5",
+    "/cmb:lowline": "\u0332",
+    "/cmb:lowlinedouble": "\u0333",
+    "/cmb:lsmall": "\u1DDE",
+    "/cmb:lwithdoublemiddletilde": "\u1DEC",
+    "/cmb:m": "\u036B",
+    "/cmb:macron": "\u0304",
+    "/cmb:macronacute": "\u1DC4",
+    "/cmb:macronbelow": "\u0331",
+    "/cmb:macronbreve": "\u1DCC",
+    "/cmb:macrondouble": "\u035E",
+    "/cmb:macrondoublebelow": "\u035F",
+    "/cmb:macrongrave": "\u1DC6",
+    "/cmb:minusbelow": "\u0320",
+    "/cmb:msmall": "\u1DDF",
+    "/cmb:n": "\u1DE0",
+    "/cmb:nottildeabove": "\u034A",
+    "/cmb:nsmall": "\u1DE1",
+    "/cmb:o": "\u0366",
+    "/cmb:odieresis": "\u1DF3",
+    "/cmb:ogonek": "\u0328",
+    "/cmb:overlaystrokelong": "\u0336",
+    "/cmb:overlaystrokeshort": "\u0335",
+    "/cmb:overline": "\u0305",
+    "/cmb:owithlightcentralizationstroke": "\u1DED",
+    "/cmb:p": "\u1DEE",
+    "/cmb:palatalizedhookbelow": "\u0321",
+    "/cmb:perispomeni": "\u0342",
+    "/cmb:plusbelow": "\u031F",
+    "/cmb:r": "\u036C",
+    "/cmb:rbelow": "\u1DCA",
+    "/cmb:retroflexhookbelow": "\u0322",
+    "/cmb:reversedcommaabove": "\u0314",
+    "/cmb:rightarrowheadanddownarrowheadbelow": "\u1DFF",
+    "/cmb:righttackbelow": "\u0319",
+    "/cmb:ringabove": "\u030A",
+    "/cmb:ringbelow": "\u0325",
+    "/cmb:rrotunda": "\u1DE3",
+    "/cmb:rsmall": "\u1DE2",
+    "/cmb:s": "\u1DE4",
+    "/cmb:schwa": "\u1DEA",
+    "/cmb:seagullbelow": "\u033C",
+    "/cmb:snakebelow": "\u1DC2",
+    "/cmb:soliduslongoverlay": "\u0338",
+    "/cmb:solidusshortoverlay": "\u0337",
+    "/cmb:squarebelow": "\u033B",
+    "/cmb:suspensionmark": "\u1DC3",
+    "/cmb:t": "\u036D",
+    "/cmb:tilde": "\u0303",
+    "/cmb:tildebelow": "\u0330",
+    "/cmb:tildedouble": "\u0360",
+    "/cmb:tildeoverlay": "\u0334",
+    "/cmb:tildevertical": "\u033E",
+    "/cmb:turnedabove": "\u0313",
+    "/cmb:turnedcommaabove": "\u0315",
+    "/cmb:u": "\u0367",
+    "/cmb:udieresis": "\u1DF4",
+    "/cmb:uptackabove": "\u1DF5",
+    "/cmb:uptackbelow": "\u031D",
+    "/cmb:urabove": "\u1DD1",
+    "/cmb:usabove": "\u1DD2",
+    "/cmb:uwithlightcentralizationstroke": "\u1DF0",
+    "/cmb:v": "\u036E",
+    "/cmb:w": "\u1DF1",
+    "/cmb:wideinvertedbridgebelow": "\u1DF9",
+    "/cmb:x": "\u036F",
+    "/cmb:xabove": "\u033D",
+    "/cmb:xbelow": "\u0353",
+    "/cmb:z": "\u1DE6",
+    "/cmb:zigzagabove": "\u035B",
+    "/cmb:zigzagbelow": "\u1DCF",
+    "/cmcubedsquare": "\u33A4",
+    "/cmfullwidth": "\u339D",
+    "/cmonospace": "\uFF43",
+    "/cmsquaredsquare": "\u33A0",
+    "/cntr:acknowledge": "\u2406",
+    "/cntr:backspace": "\u2408",
+    "/cntr:bell": "\u2407",
+    "/cntr:blank": "\u2422",
+    "/cntr:cancel": "\u2418",
+    "/cntr:carriagereturn": "\u240D",
+    "/cntr:datalinkescape": "\u2410",
+    "/cntr:delete": "\u2421",
+    "/cntr:deleteformtwo": "\u2425",
+    "/cntr:devicecontrolfour": "\u2414",
+    "/cntr:devicecontrolone": "\u2411",
+    "/cntr:devicecontrolthree": "\u2413",
+    "/cntr:devicecontroltwo": "\u2412",
+    "/cntr:endofmedium": "\u2419",
+    "/cntr:endoftext": "\u2403",
+    "/cntr:endoftransmission": "\u2404",
+    "/cntr:endoftransmissionblock": "\u2417",
+    "/cntr:enquiry": "\u2405",
+    "/cntr:escape": "\u241B",
+    "/cntr:fileseparator": "\u241C",
+    "/cntr:formfeed": "\u240C",
+    "/cntr:groupseparator": "\u241D",
+    "/cntr:horizontaltab": "\u2409",
+    "/cntr:linefeed": "\u240A",
+    "/cntr:negativeacknowledge": "\u2415",
+    "/cntr:newline": "\u2424",
+    "/cntr:null": "\u2400",
+    "/cntr:openbox": "\u2423",
+    "/cntr:recordseparator": "\u241E",
+    "/cntr:shiftin": "\u240F",
+    "/cntr:shiftout": "\u240E",
+    "/cntr:space": "\u2420",
+    "/cntr:startofheading": "\u2401",
+    "/cntr:startoftext": "\u2402",
+    "/cntr:substitute": "\u241A",
+    "/cntr:substituteformtwo": "\u2426",
+    "/cntr:synchronousidle": "\u2416",
+    "/cntr:unitseparator": "\u241F",
+    "/cntr:verticaltab": "\u240B",
+    "/coarmenian": "\u0581",
+    "/cocktailGlass": "\u1F378",
+    "/coffin": "\u26B0",
+    "/cofullwidth": "\u33C7",
+    "/collision": "\u1F4A5",
+    "/colon": "\u003A",
+    "/colonequals": "\u2254",
+    "/colonmod": "\uA789",
+    "/colonmonetary": "\u20A1",
+    "/colonmonospace": "\uFF1A",
+    "/colonraisedmod": "\u02F8",
+    "/colonsign": "\u20A1",
+    "/colonsmall": "\uFE55",
+    "/colontriangularhalfmod": "\u02D1",
+    "/colontriangularmod": "\u02D0",
+    "/comet": "\u2604",
+    "/comma": "\u002C",
+    "/commaabovecmb": "\u0313",
+    "/commaaboverightcmb": "\u0315",
+    "/commaaccent": "\uF6C3",
+    "/commaarabic": "\u060C",
+    "/commaarmenian": "\u055D",
+    "/commabarfunc": "\u236A",
+    "/commainferior": "\uF6E1",
+    "/commamonospace": "\uFF0C",
+    "/commaraised": "\u2E34",
+    "/commareversed": "\u2E41",
+    "/commareversedabovecmb": "\u0314",
+    "/commareversedmod": "\u02BD",
+    "/commasmall": "\uFE50",
+    "/commasuperior": "\uF6E2",
+    "/commaturnedabovecmb": "\u0312",
+    "/commaturnedmod": "\u02BB",
+    "/commercialat": "\uFE6B",
+    "/commercialminussign": "\u2052",
+    "/compass": "\u263C",
+    "/complement": "\u2201",
+    "/composition": "\u2384",
+    "/compression": "\u1F5DC",
+    "/con": "\uA76F",
+    "/confettiBall": "\u1F38A",
+    "/confoundedFace": "\u1F616",
+    "/confusedFace": "\u1F615",
+    "/congratulationideographiccircled": "\u3297",
+    "/congratulationideographicparen": "\u3237",
+    "/congruent": "\u2245",
+    "/conicaltaper": "\u2332",
+    "/conjunction": "\u260C",
+    "/consquareupblack": "\u26FE",
+    "/constructionSign": "\u1F6A7",
+    "/constructionWorker": "\u1F477",
+    "/containsasmembersmall": "\u220D",
+    "/containsasnormalsubgroorequalup": "\u22B5",
+    "/containsasnormalsubgroup": "\u22B3",
+    "/containslonghorizontalstroke": "\u22FA",
+    "/containsoverbar": "\u22FD",
+    "/containsoverbarsmall": "\u22FE",
+    "/containssmallverticalbarhorizontalstroke": "\u22FC",
+    "/containsverticalbarhorizontalstroke": "\u22FB",
+    "/continuousunderline": "\u2381",
+    "/contourintegral": "\u222E",
+    "/control": "\u2303",
+    "/controlACK": "\u0006",
+    "/controlBEL": "\u0007",
+    "/controlBS": "\u0008",
+    "/controlCAN": "\u0018",
+    "/controlCR": "\u000D",
+    "/controlDC1": "\u0011",
+    "/controlDC2": "\u0012",
+    "/controlDC3": "\u0013",
+    "/controlDC4": "\u0014",
+    "/controlDEL": "\u007F",
+    "/controlDLE": "\u0010",
+    "/controlEM": "\u0019",
+    "/controlENQ": "\u0005",
+    "/controlEOT": "\u0004",
+    "/controlESC": "\u001B",
+    "/controlETB": "\u0017",
+    "/controlETX": "\u0003",
+    "/controlFF": "\u000C",
+    "/controlFS": "\u001C",
+    "/controlGS": "\u001D",
+    "/controlHT": "\u0009",
+    "/controlKnobs": "\u1F39B",
+    "/controlLF": "\u000A",
+    "/controlNAK": "\u0015",
+    "/controlRS": "\u001E",
+    "/controlSI": "\u000F",
+    "/controlSO": "\u000E",
+    "/controlSOT": "\u0002",
+    "/controlSTX": "\u0001",
+    "/controlSUB": "\u001A",
+    "/controlSYN": "\u0016",
+    "/controlUS": "\u001F",
+    "/controlVT": "\u000B",
+    "/convavediamondwhite": "\u27E1",
+    "/convenienceStore": "\u1F3EA",
+    "/cookedRice": "\u1F35A",
+    "/cookie": "\u1F36A",
+    "/cooking": "\u1F373",
+    "/coolsquare": "\u1F192",
+    "/coproductarray": "\u2210",
+    "/copyideographiccircled": "\u32A2",
+    "/copyright": "\u00A9",
+    "/copyrightsans": "\uF8E9",
+    "/copyrightserif": "\uF6D9",
+    "/cornerbottomleft": "\u231E",
+    "/cornerbottomright": "\u231F",
+    "/cornerbracketleft": "\u300C",
+    "/cornerbracketlefthalfwidth": "\uFF62",
+    "/cornerbracketleftvertical": "\uFE41",
+    "/cornerbracketright": "\u300D",
+    "/cornerbracketrighthalfwidth": "\uFF63",
+    "/cornerbracketrightvertical": "\uFE42",
+    "/cornerdotupleft": "\u27D4",
+    "/cornertopleft": "\u231C",
+    "/cornertopright": "\u231D",
+    "/coroniseditorial": "\u2E0E",
+    "/corporationsquare": "\u337F",
+    "/correctideographiccircled": "\u32A3",
+    "/corresponds": "\u2258",
+    "/cosquare": "\u33C7",
+    "/couchAndLamp": "\u1F6CB",
+    "/counterbore": "\u2334",
+    "/countersink": "\u2335",
+    "/coupleHeart": "\u1F491",
+    "/coverkgfullwidth": "\u33C6",
+    "/coverkgsquare": "\u33C6",
+    "/cow": "\u1F404",
+    "/cowFace": "\u1F42E",
+    "/cpalatalhook": "\uA794",
+    "/cparen": "\u249E",
+    "/cparenthesized": "\u249E",
+    "/creditCard": "\u1F4B3",
+    "/crescentMoon": "\u1F319",
+    "/creversed": "\u2184",
+    "/cricketBatAndBall": "\u1F3CF",
+    "/crocodile": "\u1F40A",
+    "/cropbottomleft": "\u230D",
+    "/cropbottomright": "\u230C",
+    "/croptopleft": "\u230F",
+    "/croptopright": "\u230E",
+    "/crossPommee": "\u1F542",
+    "/crossPommeeHalf-circleBelow": "\u1F541",
+    "/crossedFlags": "\u1F38C",
+    "/crossedswords": "\u2694",
+    "/crossinglanes": "\u26CC",
+    "/crossmod": "\u02DF",
+    "/crossofjerusalem": "\u2629",
+    "/crossoflorraine": "\u2628",
+    "/crossonshieldblack": "\u26E8",
+    "/crown": "\u1F451",
+    "/crrn:rupee": "\u20A8",
+    "/cruzeiro": "\u20A2",
+    "/cryingCatFace": "\u1F63F",
+    "/cryingFace": "\u1F622",
+    "/crystalBall": "\u1F52E",
+    "/cstretched": "\u0297",
+    "/cstroke": "\u023C",
+    "/cuatrillo": "\uA72D",
+    "/cuatrillocomma": "\uA72F",
+    "/curlyand": "\u22CF",
+    "/curlylogicaland": "\u22CF",
+    "/curlylogicalor": "\u22CE",
+    "/curlyor": "\u22CE",
+    "/currency": "\u00A4",
+    "/currencyExchange": "\u1F4B1",
+    "/curryAndRice": "\u1F35B",
+    "/custard": "\u1F36E",
+    "/customeraccountnumber": "\u2449",
+    "/customs": "\u1F6C3",
+    "/cyclone": "\u1F300",
+    "/cylindricity": "\u232D",
+    "/cyrBreve": "\uF6D1",
+    "/cyrFlex": "\uF6D2",
+    "/cyrbreve": "\uF6D4",
+    "/cyrflex": "\uF6D5",
+    "/d": "\u0064",
+    "/daarmenian": "\u0564",
+    "/daasusquare": "\u3324",
+    "/dabengali": "\u09A6",
+    "/dad": "\u0636",
+    "/dad.fina": "\uFEBE",
+    "/dad.init": "\uFEBF",
+    "/dad.init_alefmaksura.fina": "\uFD07",
+    "/dad.init_hah.fina": "\uFC23",
+    "/dad.init_hah.medi": "\uFCB5",
+    "/dad.init_jeem.fina": "\uFC22",
+    "/dad.init_jeem.medi": "\uFCB4",
+    "/dad.init_khah.fina": "\uFC24",
+    "/dad.init_khah.medi": "\uFCB6",
+    "/dad.init_khah.medi_meem.medi": "\uFD70",
+    "/dad.init_meem.fina": "\uFC25",
+    "/dad.init_meem.medi": "\uFCB7",
+    "/dad.init_reh.fina": "\uFD10",
+    "/dad.init_yeh.fina": "\uFD08",
+    "/dad.isol": "\uFEBD",
+    "/dad.medi": "\uFEC0",
+    "/dad.medi_alefmaksura.fina": "\uFD23",
+    "/dad.medi_hah.medi_alefmaksura.fina": "\uFD6E",
+    "/dad.medi_hah.medi_yeh.fina": "\uFDAB",
+    "/dad.medi_khah.medi_meem.fina": "\uFD6F",
+    "/dad.medi_reh.fina": "\uFD2C",
+    "/dad.medi_yeh.fina": "\uFD24",
+    "/dadarabic": "\u0636",
+    "/daddotbelow": "\u06FB",
+    "/dadeva": "\u0926",
+    "/dadfinalarabic": "\uFEBE",
+    "/dadinitialarabic": "\uFEBF",
+    "/dadmedialarabic": "\uFEC0",
+    "/dafullwidth": "\u3372",
+    "/dagesh": "\u05BC",
+    "/dagesh:hb": "\u05BC",
+    "/dageshhebrew": "\u05BC",
+    "/dagger": "\u2020",
+    "/daggerKnife": "\u1F5E1",
+    "/daggerdbl": "\u2021",
+    "/daggerwithguardleft": "\u2E36",
+    "/daggerwithguardright": "\u2E37",
+    "/dagujarati": "\u0AA6",
+    "/dagurmukhi": "\u0A26",
+    "/dahal": "\u068C",
+    "/dahal.fina": "\uFB85",
+    "/dahal.isol": "\uFB84",
+    "/dahiragana": "\u3060",
+    "/dakatakana": "\u30C0",
+    "/dal": "\u062F",
+    "/dal.fina": "\uFEAA",
+    "/dal.isol": "\uFEA9",
+    "/dalInvertedSmallVBelow": "\u075A",
+    "/dalTwoDotsVerticallyBelowSmallTah": "\u0759",
+    "/dalarabic": "\u062F",
+    "/daldotbelow": "\u068A",
+    "/daldotbelowtahsmall": "\u068B",
+    "/daldownthreedotsabove": "\u068F",
+    "/dalet": "\u05D3",
+    "/dalet:hb": "\u05D3",
+    "/daletdagesh": "\uFB33",
+    "/daletdageshhebrew": "\uFB33",
+    "/dalethatafpatah": "\u05D3",
+    "/dalethatafpatahhebrew": "\u05D3",
+    "/dalethatafsegol": "\u05D3",
+    "/dalethatafsegolhebrew": "\u05D3",
+    "/dalethebrew": "\u05D3",
+    "/dalethiriq": "\u05D3",
+    "/dalethiriqhebrew": "\u05D3",
+    "/daletholam": "\u05D3",
+    "/daletholamhebrew": "\u05D3",
+    "/daletpatah": "\u05D3",
+    "/daletpatahhebrew": "\u05D3",
+    "/daletqamats": "\u05D3",
+    "/daletqamatshebrew": "\u05D3",
+    "/daletqubuts": "\u05D3",
+    "/daletqubutshebrew": "\u05D3",
+    "/daletsegol": "\u05D3",
+    "/daletsegolhebrew": "\u05D3",
+    "/daletsheva": "\u05D3",
+    "/daletshevahebrew": "\u05D3",
+    "/dalettsere": "\u05D3",
+    "/dalettserehebrew": "\u05D3",
+    "/daletwide:hb": "\uFB22",
+    "/daletwithdagesh:hb": "\uFB33",
+    "/dalfinalarabic": "\uFEAA",
+    "/dalfourdotsabove": "\u0690",
+    "/dalinvertedV": "\u06EE",
+    "/dalring": "\u0689",
+    "/damahaprana": "\uA9A3",
+    "/damma": "\u064F",
+    "/dammaIsol": "\uFE78",
+    "/dammaMedi": "\uFE79",
+    "/dammaarabic": "\u064F",
+    "/dammalowarabic": "\u064F",
+    "/dammareversed": "\u065D",
+    "/dammasmall": "\u0619",
+    "/dammatan": "\u064C",
+    "/dammatanIsol": "\uFE72",
+    "/dammatanaltonearabic": "\u064C",
+    "/dammatanarabic": "\u064C",
+    "/dancer": "\u1F483",
+    "/danda": "\u0964",
+    "/dango": "\u1F361",
+    "/darga:hb": "\u05A7",
+    "/dargahebrew": "\u05A7",
+    "/dargalefthebrew": "\u05A7",
+    "/darkShade": "\u2593",
+    "/darkSunglasses": "\u1F576",
+    "/dashwithupturnleft": "\u2E43",
+    "/dasiacmbcyr": "\u0485",
+    "/dasiapneumatacyrilliccmb": "\u0485",
+    "/dateseparator": "\u060D",
+    "/dayeighteentelegraph": "\u33F1",
+    "/dayeighttelegraph": "\u33E7",
+    "/dayeleventelegraph": "\u33EA",
+    "/dayfifteentelegraph": "\u33EE",
+    "/dayfivetelegraph": "\u33E4",
+    "/dayfourteentelegraph": "\u33ED",
+    "/dayfourtelegraph": "\u33E3",
+    "/daynineteentelegraph": "\u33F2",
+    "/dayninetelegraph": "\u33E8",
+    "/dayonetelegraph": "\u33E0",
+    "/dayseventeentelegraph": "\u33F0",
+    "/dayseventelegraph": "\u33E6",
+    "/daysixteentelegraph": "\u33EF",
+    "/daysixtelegraph": "\u33E5",
+    "/daytentelegraph": "\u33E9",
+    "/daythirteentelegraph": "\u33EC",
+    "/daythirtyonetelegraph": "\u33FE",
+    "/daythirtytelegraph": "\u33FD",
+    "/daythreetelegraph": "\u33E2",
+    "/daytwelvetelegraph": "\u33EB",
+    "/daytwentyeighttelegraph": "\u33FB",
+    "/daytwentyfivetelegraph": "\u33F8",
+    "/daytwentyfourtelegraph": "\u33F7",
+    "/daytwentyninetelegraph": "\u33FC",
+    "/daytwentyonetelegraph": "\u33F4",
+    "/daytwentyseventelegraph": "\u33FA",
+    "/daytwentysixtelegraph": "\u33F9",
+    "/daytwentytelegraph": "\u33F3",
+    "/daytwentythreetelegraph": "\u33F6",
+    "/daytwentytwotelegraph": "\u33F5",
+    "/daytwotelegraph": "\u33E1",
+    "/dbdigraph": "\u0238",
+    "/dbfullwidth": "\u33C8",
+    "/dblGrave": "\uF6D3",
+    "/dblanglebracketleft": "\u300A",
+    "/dblanglebracketleftvertical": "\uFE3D",
+    "/dblanglebracketright": "\u300B",
+    "/dblanglebracketrightvertical": "\uFE3E",
+    "/dblarchinvertedbelowcmb": "\u032B",
+    "/dblarrowNE": "\u21D7",
+    "/dblarrowNW": "\u21D6",
+    "/dblarrowSE": "\u21D8",
+    "/dblarrowSW": "\u21D9",
+    "/dblarrowdown": "\u21D3",
+    "/dblarrowleft": "\u21D4",
+    "/dblarrowleftright": "\u21D4",
+    "/dblarrowleftrightstroke": "\u21CE",
+    "/dblarrowleftstroke": "\u21CD",
+    "/dblarrowright": "\u21D2",
+    "/dblarrowrightstroke": "\u21CF",
+    "/dblarrowup": "\u21D1",
+    "/dblarrowupdown": "\u21D5",
+    "/dbldanda": "\u0965",
+    "/dbldnhorz": "\u2566",
+    "/dbldnleft": "\u2557",
+    "/dbldnright": "\u2554",
+    "/dblgrave": "\uF6D6",
+    "/dblgravecmb": "\u030F",
+    "/dblhorz": "\u2550",
+    "/dblintegral": "\u222C",
+    "/dbllowline": "\u2017",
+    "/dbllowlinecmb": "\u0333",
+    "/dbloverlinecmb": "\u033F",
+    "/dblprimemod": "\u02BA",
+    "/dblstrokearrowdown": "\u21DF",
+    "/dblstrokearrowup": "\u21DE",
+    "/dbluphorz": "\u2569",
+    "/dblupleft": "\u255D",
+    "/dblupright": "\u255A",
+    "/dblvert": "\u2551",
+    "/dblverthorz": "\u256C",
+    "/dblverticalbar": "\u2016",
+    "/dblverticallineabovecmb": "\u030E",
+    "/dblvertleft": "\u2563",
+    "/dblvertright": "\u2560",
+    "/dbopomofo": "\u3109",
+    "/dbsquare": "\u33C8",
+    "/dcaron": "\u010F",
+    "/dcedilla": "\u1E11",
+    "/dchecyr": "\u052D",
+    "/dcircle": "\u24D3",
+    "/dcircumflexbelow": "\u1E13",
+    "/dcroat": "\u0111",
+    "/dcurl": "\u0221",
+    "/ddabengali": "\u09A1",
+    "/ddadeva": "\u0921",
+    "/ddagujarati": "\u0AA1",
+    "/ddagurmukhi": "\u0A21",
+    "/ddahal": "\u068D",
+    "/ddahal.fina": "\uFB83",
+    "/ddahal.isol": "\uFB82",
+    "/ddal": "\u0688",
+    "/ddal.fina": "\uFB89",
+    "/ddal.isol": "\uFB88",
+    "/ddalarabic": "\u0688",
+    "/ddalfinalarabic": "\uFB89",
+    "/ddamahaprana": "\uA99E",
+    "/ddblstruckitalic": "\u2146",
+    "/dddhadeva": "\u095C",
+    "/ddhabengali": "\u09A2",
+    "/ddhadeva": "\u0922",
+    "/ddhagujarati": "\u0AA2",
+    "/ddhagurmukhi": "\u0A22",
+    "/ddot": "\u1E0B",
+    "/ddotaccent": "\u1E0B",
+    "/ddotbelow": "\u1E0D",
+    "/decembertelegraph": "\u32CB",
+    "/deciduousTree": "\u1F333",
+    "/decimalexponent": "\u23E8",
+    "/decimalseparatorarabic": "\u066B",
+    "/decimalseparatorpersian": "\u066B",
+    "/decreaseFontSize": "\u1F5DB",
+    "/decyr": "\u0434",
+    "/decyrillic": "\u0434",
+    "/degree": "\u00B0",
+    "/degreecelsius": "\u2103",
+    "/degreefahrenheit": "\u2109",
+    "/dehi:hb": "\u05AD",
+    "/dehihebrew": "\u05AD",
+    "/dehiragana": "\u3067",
+    "/deicoptic": "\u03EF",
+    "/dekatakana": "\u30C7",
+    "/dekomicyr": "\u0501",
+    "/deldiaeresisfunc": "\u2362",
+    "/deleteleft": "\u232B",
+    "/deleteright": "\u2326",
+    "/deliveryTruck": "\u1F69A",
+    "/delstilefunc": "\u2352",
+    "/delta": "\u03B4",
+    "/deltaequal": "\u225C",
+    "/deltastilefunc": "\u234B",
+    "/deltaturned": "\u018D",
+    "/deltaunderlinefunc": "\u2359",
+    "/deltildefunc": "\u236B",
+    "/denominatorminusonenumeratorbengali": "\u09F8",
+    "/dentistrybottomverticalleft": "\u23CC",
+    "/dentistrybottomverticalright": "\u23BF",
+    "/dentistrycircledownhorizontal": "\u23C1",
+    "/dentistrycircleuphorizontal": "\u23C2",
+    "/dentistrycirclevertical": "\u23C0",
+    "/dentistrydownhorizontal": "\u23C9",
+    "/dentistrytopverticalleft": "\u23CB",
+    "/dentistrytopverticalright": "\u23BE",
+    "/dentistrytriangledownhorizontal": "\u23C4",
+    "/dentistrytriangleuphorizontal": "\u23C5",
+    "/dentistrytrianglevertical": "\u23C3",
+    "/dentistryuphorizontal": "\u23CA",
+    "/dentistrywavedownhorizontal": "\u23C7",
+    "/dentistrywaveuphorizontal": "\u23C8",
+    "/dentistrywavevertical": "\u23C6",
+    "/departmentStore": "\u1F3EC",
+    "/derelictHouseBuilding": "\u1F3DA",
+    "/desert": "\u1F3DC",
+    "/desertIsland": "\u1F3DD",
+    "/desisquare": "\u3325",
+    "/desktopComputer": "\u1F5A5",
+    "/desktopWindow": "\u1F5D4",
+    "/deva:a": "\u0905",
+    "/deva:aa": "\u0906",
+    "/deva:aasign": "\u093E",
+    "/deva:abbreviation": "\u0970",
+    "/deva:acandra": "\u0972",
+    "/deva:acute": "\u0954",
+    "/deva:ai": "\u0910",
+    "/deva:aisign": "\u0948",
+    "/deva:anudatta": "\u0952",
+    "/deva:anusvara": "\u0902",
+    "/deva:ashort": "\u0904",
+    "/deva:au": "\u0914",
+    "/deva:ausign": "\u094C",
+    "/deva:avagraha": "\u093D",
+    "/deva:aw": "\u0975",
+    "/deva:awsign": "\u094F",
+    "/deva:ba": "\u092C",
+    "/deva:bba": "\u097F",
+    "/deva:bha": "\u092D",
+    "/deva:ca": "\u091A",
+    "/deva:candrabindu": "\u0901",
+    "/deva:candrabinduinverted": "\u0900",
+    "/deva:cha": "\u091B",
+    "/deva:da": "\u0926",
+    "/deva:danda": "\u0964",
+    "/deva:dbldanda": "\u0965",
+    "/deva:dda": "\u0921",
+    "/deva:ddda": "\u097E",
+    "/deva:dddha": "\u095C",
+    "/deva:ddha": "\u0922",
+    "/deva:dha": "\u0927",
+    "/deva:dothigh": "\u0971",
+    "/deva:e": "\u090F",
+    "/deva:ecandra": "\u090D",
+    "/deva:eight": "\u096E",
+    "/deva:eshort": "\u090E",
+    "/deva:esign": "\u0947",
+    "/deva:esigncandra": "\u0945",
+    "/deva:esignprishthamatra": "\u094E",
+    "/deva:esignshort": "\u0946",
+    "/deva:fa": "\u095E",
+    "/deva:five": "\u096B",
+    "/deva:four": "\u096A",
+    "/deva:ga": "\u0917",
+    "/deva:gga": "\u097B",
+    "/deva:gha": "\u0918",
+    "/deva:ghha": "\u095A",
+    "/deva:glottalstop": "\u097D",
+    "/deva:grave": "\u0953",
+    "/deva:ha": "\u0939",
+    "/deva:i": "\u0907",
+    "/deva:ii": "\u0908",
+    "/deva:iisign": "\u0940",
+    "/deva:isign": "\u093F",
+    "/deva:ja": "\u091C",
+    "/deva:jha": "\u091D",
+    "/deva:jja": "\u097C",
+    "/deva:ka": "\u0915",
+    "/deva:kha": "\u0916",
+    "/deva:khha": "\u0959",
+    "/deva:la": "\u0932",
+    "/deva:lla": "\u0933",
+    "/deva:llla": "\u0934",
+    "/deva:llvocal": "\u0961",
+    "/deva:llvocalsign": "\u0963",
+    "/deva:lvocal": "\u090C",
+    "/deva:lvocalsign": "\u0962",
+    "/deva:ma": "\u092E",
+    "/deva:marwaridda": "\u0978",
+    "/deva:na": "\u0928",
+    "/deva:nga": "\u0919",
+    "/deva:nine": "\u096F",
+    "/deva:nna": "\u0923",
+    "/deva:nnna": "\u0929",
+    "/deva:nukta": "\u093C",
+    "/deva:nya": "\u091E",
+    "/deva:o": "\u0913",
+    "/deva:ocandra": "\u0911",
+    "/deva:oe": "\u0973",
+    "/deva:oesign": "\u093A",
+    "/deva:om": "\u0950",
+    "/deva:one": "\u0967",
+    "/deva:ooe": "\u0974",
+    "/deva:ooesign": "\u093B",
+    "/deva:oshort": "\u0912",
+    "/deva:osign": "\u094B",
+    "/deva:osigncandra": "\u0949",
+    "/deva:osignshort": "\u094A",
+    "/deva:pa": "\u092A",
+    "/deva:pha": "\u092B",
+    "/deva:qa": "\u0958",
+    "/deva:ra": "\u0930",
+    "/deva:rha": "\u095D",
+    "/deva:rra": "\u0931",
+    "/deva:rrvocal": "\u0960",
+    "/deva:rrvocalsign": "\u0944",
+    "/deva:rvocal": "\u090B",
+    "/deva:rvocalsign": "\u0943",
+    "/deva:sa": "\u0938",
+    "/deva:seven": "\u096D",
+    "/deva:sha": "\u0936",
+    "/deva:signelongcandra": "\u0955",
+    "/deva:six": "\u096C",
+    "/deva:ssa": "\u0937",
+    "/deva:ta": "\u0924",
+    "/deva:tha": "\u0925",
+    "/deva:three": "\u0969",
+    "/deva:tta": "\u091F",
+    "/deva:ttha": "\u0920",
+    "/deva:two": "\u0968",
+    "/deva:u": "\u0909",
+    "/deva:udatta": "\u0951",
+    "/deva:ue": "\u0976",
+    "/deva:uesign": "\u0956",
+    "/deva:usign": "\u0941",
+    "/deva:uu": "\u090A",
+    "/deva:uue": "\u0977",
+    "/deva:uuesign": "\u0957",
+    "/deva:uusign": "\u0942",
+    "/deva:va": "\u0935",
+    "/deva:virama": "\u094D",
+    "/deva:visarga": "\u0903",
+    "/deva:ya": "\u092F",
+    "/deva:yaheavy": "\u097A",
+    "/deva:yya": "\u095F",
+    "/deva:za": "\u095B",
+    "/deva:zero": "\u0966",
+    "/deva:zha": "\u0979",
+    "/dezh": "\u02A4",
+    "/dfemaledbl": "\u26A2",
+    "/dhabengali": "\u09A7",
+    "/dhadeva": "\u0927",
+    "/dhagujarati": "\u0AA7",
+    "/dhagurmukhi": "\u0A27",
+    "/dhook": "\u0257",
+    "/diaeresisgreaterfunc": "\u2369",
+    "/dialytikatonos": "\u0385",
+    "/dialytikatonoscmb": "\u0344",
+    "/diametersign": "\u2300",
+    "/diamond": "\u2666",
+    "/diamondShapeADotInside": "\u1F4A0",
+    "/diamondinsquarewhite": "\u26CB",
+    "/diamondoperator": "\u22C4",
+    "/diamondsuitwhite": "\u2662",
+    "/diamondunderlinefunc": "\u235A",
+    "/diamondwhitewithdiamondsmallblack": "\u25C8",
+    "/diefive": "\u2684",
+    "/diefour": "\u2683",
+    "/dieone": "\u2680",
+    "/dieresis": "\u00A8",
+    "/dieresisacute": "\uF6D7",
+    "/dieresisbelowcmb": "\u0324",
+    "/dieresiscmb": "\u0308",
+    "/dieresisgrave": "\uF6D8",
+    "/dieresistilde": "\u1FC1",
+    "/dieresistonos": "\u0385",
+    "/dieselLocomotive": "\u1F6F2",
+    "/diesix": "\u2685",
+    "/diethree": "\u2682",
+    "/dietwo": "\u2681",
+    "/differencebetween": "\u224F",
+    "/digamma": "\u03DD",
+    "/digammapamphylian": "\u0377",
+    "/digramgreateryang": "\u268C",
+    "/digramgreateryin": "\u268F",
+    "/digramlesseryang": "\u268E",
+    "/digramlesseryin": "\u268D",
+    "/dihiragana": "\u3062",
+    "/dikatakana": "\u30C2",
+    "/dimensionorigin": "\u2331",
+    "/dingbatSAns-serifzerocircle": "\u1F10B",
+    "/dingbatSAns-serifzerocircleblack": "\u1F10C",
+    "/dinsular": "\uA77A",
+    "/directHit": "\u1F3AF",
+    "/directcurrentformtwo": "\u2393",
+    "/dirgamurevowel": "\uA9BB",
+    "/disabledcar": "\u26CD",
+    "/disappointedButRelievedFace": "\u1F625",
+    "/disappointedFace": "\u1F61E",
+    "/discontinuousunderline": "\u2382",
+    "/dittomark": "\u3003",
+    "/divide": "\u00F7",
+    "/divides": "\u2223",
+    "/divisionslash": "\u2215",
+    "/divisiontimes": "\u22C7",
+    "/divorce": "\u26AE",
+    "/dizzy": "\u1F4AB",
+    "/dizzyFace": "\u1F635",
+    "/djecyr": "\u0452",
+    "/djecyrillic": "\u0452",
+    "/djekomicyr": "\u0503",
+    "/dkshade": "\u2593",
+    "/dlfullwidth": "\u3397",
+    "/dlinebelow": "\u1E0F",
+    "/dlogicalorsquare": "\u27CF",
+    "/dlogicalsquare": "\u27CE",
+    "/dlsquare": "\u3397",
+    "/dm2fullwidth": "\u3378",
+    "/dm3fullwidth": "\u3379",
+    "/dmacron": "\u0111",
+    "/dmaledbl": "\u26A3",
+    "/dmfullwidth": "\u3377",
+    "/dmonospace": "\uFF44",
+    "/dnblock": "\u2584",
+    "/dndblhorzsng": "\u2565",
+    "/dndblleftsng": "\u2556",
+    "/dndblrightsng": "\u2553",
+    "/dngb:airplane": "\u2708",
+    "/dngb:arrowfeatheredblackNE": "\u27B6",
+    "/dngb:arrowfeatheredblackSE": "\u27B4",
+    "/dngb:arrowfeatheredblackheavyNE": "\u27B9",
+    "/dngb:arrowfeatheredblackheavySE": "\u27B7",
+    "/dngb:arrowheadrightblack": "\u27A4",
+    "/dngb:arrowheadrightthreeDbottomlight": "\u27A3",
+    "/dngb:arrowheadrightthreeDtoplight": "\u27A2",
+    "/dngb:arrowheavyNE": "\u279A",
+    "/dngb:arrowheavySE": "\u2798",
+    "/dngb:arrowrightbacktiltedshadowedwhite": "\u27AB",
+    "/dngb:arrowrightblack": "\u27A1",
+    "/dngb:arrowrightcircledwhiteheavy": "\u27B2",
+    "/dngb:arrowrightcurvedownblackheavy": "\u27A5",
+    "/dngb:arrowrightcurveupblackheavy": "\u27A6",
+    "/dngb:arrowrightfeatheredblack": "\u27B5",
+    "/dngb:arrowrightfeatheredblackheavy": "\u27B8",
+    "/dngb:arrowrightfeatheredwhite": "\u27B3",
+    "/dngb:arrowrightfronttiltedshadowedwhite": "\u27AC",
+    "/dngb:arrowrightheavy": "\u2799",
+    "/dngb:arrowrightleftshadedwhite": "\u27AA",
+    "/dngb:arrowrightoutlinedopen": "\u27BE",
+    "/dngb:arrowrightpointed": "\u279B",
+    "/dngb:arrowrightpointedblackheavy": "\u27A8",
+    "/dngb:arrowrightrightshadedwhite": "\u27A9",
+    "/dngb:arrowrightroundheavy": "\u279C",
+    "/dngb:arrowrightsquatblack": "\u27A7",
+    "/dngb:arrowrighttriangle": "\u279D",
+    "/dngb:arrowrighttriangledashed": "\u279F",
+    "/dngb:arrowrighttriangledashedheavy": "\u27A0",
+    "/dngb:arrowrighttriangleheavy": "\u279E",
+    "/dngb:arrowrightwedge": "\u27BC",
+    "/dngb:arrowrightwedgeheavy": "\u27BD",
+    "/dngb:arrowrightwideheavy": "\u2794",
+    "/dngb:arrowshadowrightlowerwhiteheavy": "\u27AD",
+    "/dngb:arrowshadowrightnotchedlowerwhite": "\u27AF",
+    "/dngb:arrowshadowrightnotchedupperwhite": "\u27B1",
+    "/dngb:arrowshadowrightupperwhiteheavy": "\u27AE",
+    "/dngb:arrowteardropright": "\u27BA",
+    "/dngb:arrowteardroprightheavy": "\u27BB",
+    "/dngb:asteriskballoon": "\u2749",
+    "/dngb:asteriskballoonfour": "\u2723",
+    "/dngb:asteriskballoonheavyfour": "\u2724",
+    "/dngb:asteriskcentreopen": "\u2732",
+    "/dngb:asteriskclubfour": "\u2725",
+    "/dngb:asteriskheavy": "\u2731",
+    "/dngb:asteriskpointedsixteen": "\u273A",
+    "/dngb:asteriskteardrop": "\u273B",
+    "/dngb:asteriskteardropcentreopen": "\u273C",
+    "/dngb:asteriskteardropfour": "\u2722",
+    "/dngb:asteriskteardropheavy": "\u273D",
+    "/dngb:asteriskteardroppinwheelheavy": "\u2743",
+    "/dngb:asteriskteardroppropellereight": "\u274A",
+    "/dngb:asteriskteardroppropellerheavyeight": "\u274B",
+    "/dngb:ballotx": "\u2717",
+    "/dngb:ballotxheavy": "\u2718",
+    "/dngb:bracketleftpointedangleheavyornament": "\u2770",
+    "/dngb:bracketleftpointedanglemediumornament": "\u276C",
+    "/dngb:bracketrightpointedangleheavyornament": "\u2771",
+    "/dngb:bracketrightpointedanglemediumornament": "\u276D",
+    "/dngb:bracketshellleftlightornament": "\u2772",
+    "/dngb:bracketshellrightlightornament": "\u2773",
+    "/dngb:check": "\u2713",
+    "/dngb:checkheavy": "\u2714",
+    "/dngb:checkwhiteheavy": "\u2705",
+    "/dngb:chevronsnowflakeheavy": "\u2746",
+    "/dngb:circleshadowedwhite": "\u274D",
+    "/dngb:commaheavydoubleornament": "\u275E",
+    "/dngb:commaheavydoubleturnedornament": "\u275D",
+    "/dngb:commaheavyornament": "\u275C",
+    "/dngb:commaheavyturnedornament": "\u275B",
+    "/dngb:compasstarpointedblackeight": "\u2737",
+    "/dngb:compasstarpointedblackheavyeight": "\u2738",
+    "/dngb:cross": "\u274C",
+    "/dngb:crosscentreopen": "\u271B",
+    "/dngb:crosscentreopenheavy": "\u271C",
+    "/dngb:curlybracketleftmediumornament": "\u2774",
+    "/dngb:curlybracketrightmediumornament": "\u2775",
+    "/dngb:curlyloop": "\u27B0",
+    "/dngb:curlyloopdouble": "\u27BF",
+    "/dngb:curvedstemparagraphsignornament": "\u2761",
+    "/dngb:diamondminusxblackwhite": "\u2756",
+    "/dngb:divisionsignheavy": "\u2797",
+    "/dngb:eightnegativecircled": "\u277D",
+    "/dngb:eightsanscircled": "\u2787",
+    "/dngb:eightsansnegativecircled": "\u2791",
+    "/dngb:envelope": "\u2709",
+    "/dngb:exclamationheavy": "\u2757",
+    "/dngb:exclamationheavyornament": "\u2762",
+    "/dngb:exclamationwhiteornament": "\u2755",
+    "/dngb:fivenegativecircled": "\u277A",
+    "/dngb:fivesanscircled": "\u2784",
+    "/dngb:fivesansnegativecircled": "\u278E",
+    "/dngb:floralheart": "\u2766",
+    "/dngb:floralheartbulletrotated": "\u2767",
+    "/dngb:floretteblack": "\u273F",
+    "/dngb:floretteoutlinedpetalledblackeight": "\u2741",
+    "/dngb:florettepetalledblackwhitesix": "\u273E",
+    "/dngb:florettewhite": "\u2740",
+    "/dngb:fournegativecircled": "\u2779",
+    "/dngb:foursanscircled": "\u2783",
+    "/dngb:foursansnegativecircled": "\u278D",
+    "/dngb:greekcrossheavy": "\u271A",
+    "/dngb:greekcrossoutlined": "\u2719",
+    "/dngb:heartblackheavy": "\u2764",
+    "/dngb:heartbulletrotatedblackheavy": "\u2765",
+    "/dngb:heartexclamationheavyornament": "\u2763",
+    "/dngb:hvictory": "\u270C",
+    "/dngb:hwriting": "\u270D",
+    "/dngb:latincross": "\u271D",
+    "/dngb:latincrossoutlined": "\u271F",
+    "/dngb:latincrossshadowedwhite": "\u271E",
+    "/dngb:lowcommaheavydoubleornament": "\u2760",
+    "/dngb:lowcommaheavyornament": "\u275F",
+    "/dngb:maltesecross": "\u2720",
+    "/dngb:minussignheavy": "\u2796",
+    "/dngb:multiplicationx": "\u2715",
+    "/dngb:multiplicationxheavy": "\u2716",
+    "/dngb:nibblack": "\u2712",
+    "/dngb:nibwhite": "\u2711",
+    "/dngb:ninenegativecircled": "\u277E",
+    "/dngb:ninesanscircled": "\u2788",
+    "/dngb:ninesansnegativecircled": "\u2792",
+    "/dngb:onenegativecircled": "\u2776",
+    "/dngb:onesanscircled": "\u2780",
+    "/dngb:onesansnegativecircled": "\u278A",
+    "/dngb:parenthesisleftflattenedmediumornament": "\u276A",
+    "/dngb:parenthesisleftmediumornament": "\u2768",
+    "/dngb:parenthesisrightflattenedmediumornament": "\u276B",
+    "/dngb:parenthesisrightmediumornament": "\u2769",
+    "/dngb:pencil": "\u270F",
+    "/dngb:pencillowerright": "\u270E",
+    "/dngb:pencilupperright": "\u2710",
+    "/dngb:plussignheavy": "\u2795",
+    "/dngb:questionblackornament": "\u2753",
+    "/dngb:questionwhiteornament": "\u2754",
+    "/dngb:quotationleftpointedangleheavyornament": "\u276E",
+    "/dngb:quotationrightpointedangleheavyornament": "\u276F",
+    "/dngb:raisedfist": "\u270A",
+    "/dngb:raisedh": "\u270B",
+    "/dngb:safetyscissorsblack": "\u2700",
+    "/dngb:scissorsblack": "\u2702",
+    "/dngb:scissorslowerblade": "\u2703",
+    "/dngb:scissorsupperblade": "\u2701",
+    "/dngb:scissorswhite": "\u2704",
+    "/dngb:sevennegativecircled": "\u277C",
+    "/dngb:sevensanscircled": "\u2786",
+    "/dngb:sevensansnegativecircled": "\u2790",
+    "/dngb:sixnegativecircled": "\u277B",
+    "/dngb:sixsanscircled": "\u2785",
+    "/dngb:sixsansnegativecircled": "\u278F",
+    "/dngb:snowflake": "\u2744",
+    "/dngb:snowflaketight": "\u2745",
+    "/dngb:sparkle": "\u2747",
+    "/dngb:sparkleheavy": "\u2748",
+    "/dngb:sparkles": "\u2728",
+    "/dngb:spokedasteriskeight": "\u2733",
+    "/dngb:squaredcrossnegative": "\u274E",
+    "/dngb:squarelowerrightshadowedwhite": "\u2751",
+    "/dngb:squareshadowlowerrightwhite": "\u274F",
+    "/dngb:squareshadowupperrightwhite": "\u2750",
+    "/dngb:squareupperrightshadowedwhite": "\u2752",
+    "/dngb:starcentreblackwhite": "\u272C",
+    "/dngb:starcentreopenblack": "\u272B",
+    "/dngb:starcentreopenpointedcircledeight": "\u2742",
+    "/dngb:starcircledwhite": "\u272A",
+    "/dngb:starofdavid": "\u2721",
+    "/dngb:staroutlinedblack": "\u272D",
+    "/dngb:staroutlinedblackheavy": "\u272E",
+    "/dngb:staroutlinedstresswhite": "\u2729",
+    "/dngb:starpinwheel": "\u272F",
+    "/dngb:starpointedblackeight": "\u2734",
+    "/dngb:starpointedblackfour": "\u2726",
+    "/dngb:starpointedblacksix": "\u2736",
+    "/dngb:starpointedblacktwelve": "\u2739",
+    "/dngb:starpointedpinwheeleight": "\u2735",
+    "/dngb:starpointedwhitefour": "\u2727",
+    "/dngb:starshadowedwhite": "\u2730",
+    "/dngb:tapedrive": "\u2707",
+    "/dngb:telephonelocationsign": "\u2706",
+    "/dngb:tennegativecircled": "\u277F",
+    "/dngb:tensanscircled": "\u2789",
+    "/dngb:tensansnegativecircled": "\u2793",
+    "/dngb:threenegativecircled": "\u2778",
+    "/dngb:threesanscircled": "\u2782",
+    "/dngb:threesansnegativecircled": "\u278C",
+    "/dngb:twonegativecircled": "\u2777",
+    "/dngb:twosanscircled": "\u2781",
+    "/dngb:twosansnegativecircled": "\u278B",
+    "/dngb:verticalbarheavy": "\u275A",
+    "/dngb:verticalbarlight": "\u2758",
+    "/dngb:verticalbarmedium": "\u2759",
+    "/dnheavyhorzlight": "\u2530",
+    "/dnheavyleftlight": "\u2512",
+    "/dnheavyleftuplight": "\u2527",
+    "/dnheavyrightlight": "\u250E",
+    "/dnheavyrightuplight": "\u251F",
+    "/dnheavyuphorzlight": "\u2541",
+    "/dnlighthorzheavy": "\u252F",
+    "/dnlightleftheavy": "\u2511",
+    "/dnlightleftupheavy": "\u2529",
+    "/dnlightrightheavy": "\u250D",
+    "/dnlightrightupheavy": "\u2521",
+    "/dnlightuphorzheavy": "\u2547",
+    "/dnsnghorzdbl": "\u2564",
+    "/dnsngleftdbl": "\u2555",
+    "/dnsngrightdbl": "\u2552",
+    "/doNotLitter": "\u1F6AF",
+    "/dochadathai": "\u0E0E",
+    "/document": "\u1F5CE",
+    "/documentPicture": "\u1F5BB",
+    "/documentText": "\u1F5B9",
+    "/documentTextAndPicture": "\u1F5BA",
+    "/dodekthai": "\u0E14",
+    "/doesnotcontainasnormalsubgroorequalup": "\u22ED",
+    "/doesnotcontainasnormalsubgroup": "\u22EB",
+    "/doesnotdivide": "\u2224",
+    "/doesnotforce": "\u22AE",
+    "/doesnotprecede": "\u2280",
+    "/doesnotprecedeorequal": "\u22E0",
+    "/doesnotprove": "\u22AC",
+    "/doesnotsucceed": "\u2281",
+    "/doesnotsucceedorequal": "\u22E1",
+    "/dog": "\u1F415",
+    "/dogFace": "\u1F436",
+    "/dohiragana": "\u3069",
+    "/dokatakana": "\u30C9",
+    "/dollar": "\u0024",
+    "/dollarinferior": "\uF6E3",
+    "/dollarmonospace": "\uFF04",
+    "/dollaroldstyle": "\uF724",
+    "/dollarsmall": "\uFE69",
+    "/dollarsuperior": "\uF6E4",
+    "/dolphin": "\u1F42C",
+    "/dominohorizontal_00_00": "\u1F031",
+    "/dominohorizontal_00_01": "\u1F032",
+    "/dominohorizontal_00_02": "\u1F033",
+    "/dominohorizontal_00_03": "\u1F034",
+    "/dominohorizontal_00_04": "\u1F035",
+    "/dominohorizontal_00_05": "\u1F036",
+    "/dominohorizontal_00_06": "\u1F037",
+    "/dominohorizontal_01_00": "\u1F038",
+    "/dominohorizontal_01_01": "\u1F039",
+    "/dominohorizontal_01_02": "\u1F03A",
+    "/dominohorizontal_01_03": "\u1F03B",
+    "/dominohorizontal_01_04": "\u1F03C",
+    "/dominohorizontal_01_05": "\u1F03D",
+    "/dominohorizontal_01_06": "\u1F03E",
+    "/dominohorizontal_02_00": "\u1F03F",
+    "/dominohorizontal_02_01": "\u1F040",
+    "/dominohorizontal_02_02": "\u1F041",
+    "/dominohorizontal_02_03": "\u1F042",
+    "/dominohorizontal_02_04": "\u1F043",
+    "/dominohorizontal_02_05": "\u1F044",
+    "/dominohorizontal_02_06": "\u1F045",
+    "/dominohorizontal_03_00": "\u1F046",
+    "/dominohorizontal_03_01": "\u1F047",
+    "/dominohorizontal_03_02": "\u1F048",
+    "/dominohorizontal_03_03": "\u1F049",
+    "/dominohorizontal_03_04": "\u1F04A",
+    "/dominohorizontal_03_05": "\u1F04B",
+    "/dominohorizontal_03_06": "\u1F04C",
+    "/dominohorizontal_04_00": "\u1F04D",
+    "/dominohorizontal_04_01": "\u1F04E",
+    "/dominohorizontal_04_02": "\u1F04F",
+    "/dominohorizontal_04_03": "\u1F050",
+    "/dominohorizontal_04_04": "\u1F051",
+    "/dominohorizontal_04_05": "\u1F052",
+    "/dominohorizontal_04_06": "\u1F053",
+    "/dominohorizontal_05_00": "\u1F054",
+    "/dominohorizontal_05_01": "\u1F055",
+    "/dominohorizontal_05_02": "\u1F056",
+    "/dominohorizontal_05_03": "\u1F057",
+    "/dominohorizontal_05_04": "\u1F058",
+    "/dominohorizontal_05_05": "\u1F059",
+    "/dominohorizontal_05_06": "\u1F05A",
+    "/dominohorizontal_06_00": "\u1F05B",
+    "/dominohorizontal_06_01": "\u1F05C",
+    "/dominohorizontal_06_02": "\u1F05D",
+    "/dominohorizontal_06_03": "\u1F05E",
+    "/dominohorizontal_06_04": "\u1F05F",
+    "/dominohorizontal_06_05": "\u1F060",
+    "/dominohorizontal_06_06": "\u1F061",
+    "/dominohorizontalback": "\u1F030",
+    "/dominovertical_00_00": "\u1F063",
+    "/dominovertical_00_01": "\u1F064",
+    "/dominovertical_00_02": "\u1F065",
+    "/dominovertical_00_03": "\u1F066",
+    "/dominovertical_00_04": "\u1F067",
+    "/dominovertical_00_05": "\u1F068",
+    "/dominovertical_00_06": "\u1F069",
+    "/dominovertical_01_00": "\u1F06A",
+    "/dominovertical_01_01": "\u1F06B",
+    "/dominovertical_01_02": "\u1F06C",
+    "/dominovertical_01_03": "\u1F06D",
+    "/dominovertical_01_04": "\u1F06E",
+    "/dominovertical_01_05": "\u1F06F",
+    "/dominovertical_01_06": "\u1F070",
+    "/dominovertical_02_00": "\u1F071",
+    "/dominovertical_02_01": "\u1F072",
+    "/dominovertical_02_02": "\u1F073",
+    "/dominovertical_02_03": "\u1F074",
+    "/dominovertical_02_04": "\u1F075",
+    "/dominovertical_02_05": "\u1F076",
+    "/dominovertical_02_06": "\u1F077",
+    "/dominovertical_03_00": "\u1F078",
+    "/dominovertical_03_01": "\u1F079",
+    "/dominovertical_03_02": "\u1F07A",
+    "/dominovertical_03_03": "\u1F07B",
+    "/dominovertical_03_04": "\u1F07C",
+    "/dominovertical_03_05": "\u1F07D",
+    "/dominovertical_03_06": "\u1F07E",
+    "/dominovertical_04_00": "\u1F07F",
+    "/dominovertical_04_01": "\u1F080",
+    "/dominovertical_04_02": "\u1F081",
+    "/dominovertical_04_03": "\u1F082",
+    "/dominovertical_04_04": "\u1F083",
+    "/dominovertical_04_05": "\u1F084",
+    "/dominovertical_04_06": "\u1F085",
+    "/dominovertical_05_00": "\u1F086",
+    "/dominovertical_05_01": "\u1F087",
+    "/dominovertical_05_02": "\u1F088",
+    "/dominovertical_05_03": "\u1F089",
+    "/dominovertical_05_04": "\u1F08A",
+    "/dominovertical_05_05": "\u1F08B",
+    "/dominovertical_05_06": "\u1F08C",
+    "/dominovertical_06_00": "\u1F08D",
+    "/dominovertical_06_01": "\u1F08E",
+    "/dominovertical_06_02": "\u1F08F",
+    "/dominovertical_06_03": "\u1F090",
+    "/dominovertical_06_04": "\u1F091",
+    "/dominovertical_06_05": "\u1F092",
+    "/dominovertical_06_06": "\u1F093",
+    "/dominoverticalback": "\u1F062",
+    "/dong": "\u20AB",
+    "/door": "\u1F6AA",
+    "/dorusquare": "\u3326",
+    "/dot": "\u27D1",
+    "/dotaccent": "\u02D9",
+    "/dotaccentcmb": "\u0307",
+    "/dotbelowcmb": "\u0323",
+    "/dotbelowcomb": "\u0323",
+    "/dotkatakana": "\u30FB",
+    "/dotlessbeh": "\u066E",
+    "/dotlessfeh": "\u06A1",
+    "/dotlessi": "\u0131",
+    "/dotlessj": "\uF6BE",
+    "/dotlessjstroke": "\u025F",
+    "/dotlessjstrokehook": "\u0284",
+    "/dotlesskhahabove": "\u06E1",
+    "/dotlessqaf": "\u066F",
+    "/dotlower:hb": "\u05C5",
+    "/dotmath": "\u22C5",
+    "/dotminus": "\u2238",
+    "/dotplus": "\u2214",
+    "/dotraised": "\u2E33",
+    "/dots1": "\u2801",
+    "/dots12": "\u2803",
+    "/dots123": "\u2807",
+    "/dots1234": "\u280F",
+    "/dots12345": "\u281F",
+    "/dots123456": "\u283F",
+    "/dots1234567": "\u287F",
+    "/dots12345678": "\u28FF",
+    "/dots1234568": "\u28BF",
+    "/dots123457": "\u285F",
+    "/dots1234578": "\u28DF",
+    "/dots123458": "\u289F",
+    "/dots12346": "\u282F",
+    "/dots123467": "\u286F",
+    "/dots1234678": "\u28EF",
+    "/dots123468": "\u28AF",
+    "/dots12347": "\u284F",
+    "/dots123478": "\u28CF",
+    "/dots12348": "\u288F",
+    "/dots1235": "\u2817",
+    "/dots12356": "\u2837",
+    "/dots123567": "\u2877",
+    "/dots1235678": "\u28F7",
+    "/dots123568": "\u28B7",
+    "/dots12357": "\u2857",
+    "/dots123578": "\u28D7",
+    "/dots12358": "\u2897",
+    "/dots1236": "\u2827",
+    "/dots12367": "\u2867",
+    "/dots123678": "\u28E7",
+    "/dots12368": "\u28A7",
+    "/dots1237": "\u2847",
+    "/dots12378": "\u28C7",
+    "/dots1238": "\u2887",
+    "/dots124": "\u280B",
+    "/dots1245": "\u281B",
+    "/dots12456": "\u283B",
+    "/dots124567": "\u287B",
+    "/dots1245678": "\u28FB",
+    "/dots124568": "\u28BB",
+    "/dots12457": "\u285B",
+    "/dots124578": "\u28DB",
+    "/dots12458": "\u289B",
+    "/dots1246": "\u282B",
+    "/dots12467": "\u286B",
+    "/dots124678": "\u28EB",
+    "/dots12468": "\u28AB",
+    "/dots1247": "\u284B",
+    "/dots12478": "\u28CB",
+    "/dots1248": "\u288B",
+    "/dots125": "\u2813",
+    "/dots1256": "\u2833",
+    "/dots12567": "\u2873",
+    "/dots125678": "\u28F3",
+    "/dots12568": "\u28B3",
+    "/dots1257": "\u2853",
+    "/dots12578": "\u28D3",
+    "/dots1258": "\u2893",
+    "/dots126": "\u2823",
+    "/dots1267": "\u2863",
+    "/dots12678": "\u28E3",
+    "/dots1268": "\u28A3",
+    "/dots127": "\u2843",
+    "/dots1278": "\u28C3",
+    "/dots128": "\u2883",
+    "/dots13": "\u2805",
+    "/dots134": "\u280D",
+    "/dots1345": "\u281D",
+    "/dots13456": "\u283D",
+    "/dots134567": "\u287D",
+    "/dots1345678": "\u28FD",
+    "/dots134568": "\u28BD",
+    "/dots13457": "\u285D",
+    "/dots134578": "\u28DD",
+    "/dots13458": "\u289D",
+    "/dots1346": "\u282D",
+    "/dots13467": "\u286D",
+    "/dots134678": "\u28ED",
+    "/dots13468": "\u28AD",
+    "/dots1347": "\u284D",
+    "/dots13478": "\u28CD",
+    "/dots1348": "\u288D",
+    "/dots135": "\u2815",
+    "/dots1356": "\u2835",
+    "/dots13567": "\u2875",
+    "/dots135678": "\u28F5",
+    "/dots13568": "\u28B5",
+    "/dots1357": "\u2855",
+    "/dots13578": "\u28D5",
+    "/dots1358": "\u2895",
+    "/dots136": "\u2825",
+    "/dots1367": "\u2865",
+    "/dots13678": "\u28E5",
+    "/dots1368": "\u28A5",
+    "/dots137": "\u2845",
+    "/dots1378": "\u28C5",
+    "/dots138": "\u2885",
+    "/dots14": "\u2809",
+    "/dots145": "\u2819",
+    "/dots1456": "\u2839",
+    "/dots14567": "\u2879",
+    "/dots145678": "\u28F9",
+    "/dots14568": "\u28B9",
+    "/dots1457": "\u2859",
+    "/dots14578": "\u28D9",
+    "/dots1458": "\u2899",
+    "/dots146": "\u2829",
+    "/dots1467": "\u2869",
+    "/dots14678": "\u28E9",
+    "/dots1468": "\u28A9",
+    "/dots147": "\u2849",
+    "/dots1478": "\u28C9",
+    "/dots148": "\u2889",
+    "/dots15": "\u2811",
+    "/dots156": "\u2831",
+    "/dots1567": "\u2871",
+    "/dots15678": "\u28F1",
+    "/dots1568": "\u28B1",
+    "/dots157": "\u2851",
+    "/dots1578": "\u28D1",
+    "/dots158": "\u2891",
+    "/dots16": "\u2821",
+    "/dots167": "\u2861",
+    "/dots1678": "\u28E1",
+    "/dots168": "\u28A1",
+    "/dots17": "\u2841",
+    "/dots178": "\u28C1",
+    "/dots18": "\u2881",
+    "/dots2": "\u2802",
+    "/dots23": "\u2806",
+    "/dots234": "\u280E",
+    "/dots2345": "\u281E",
+    "/dots23456": "\u283E",
+    "/dots234567": "\u287E",
+    "/dots2345678": "\u28FE",
+    "/dots234568": "\u28BE",
+    "/dots23457": "\u285E",
+    "/dots234578": "\u28DE",
+    "/dots23458": "\u289E",
+    "/dots2346": "\u282E",
+    "/dots23467": "\u286E",
+    "/dots234678": "\u28EE",
+    "/dots23468": "\u28AE",
+    "/dots2347": "\u284E",
+    "/dots23478": "\u28CE",
+    "/dots2348": "\u288E",
+    "/dots235": "\u2816",
+    "/dots2356": "\u2836",
+    "/dots23567": "\u2876",
+    "/dots235678": "\u28F6",
+    "/dots23568": "\u28B6",
+    "/dots2357": "\u2856",
+    "/dots23578": "\u28D6",
+    "/dots2358": "\u2896",
+    "/dots236": "\u2826",
+    "/dots2367": "\u2866",
+    "/dots23678": "\u28E6",
+    "/dots2368": "\u28A6",
+    "/dots237": "\u2846",
+    "/dots2378": "\u28C6",
+    "/dots238": "\u2886",
+    "/dots24": "\u280A",
+    "/dots245": "\u281A",
+    "/dots2456": "\u283A",
+    "/dots24567": "\u287A",
+    "/dots245678": "\u28FA",
+    "/dots24568": "\u28BA",
+    "/dots2457": "\u285A",
+    "/dots24578": "\u28DA",
+    "/dots2458": "\u289A",
+    "/dots246": "\u282A",
+    "/dots2467": "\u286A",
+    "/dots24678": "\u28EA",
+    "/dots2468": "\u28AA",
+    "/dots247": "\u284A",
+    "/dots2478": "\u28CA",
+    "/dots248": "\u288A",
+    "/dots25": "\u2812",
+    "/dots256": "\u2832",
+    "/dots2567": "\u2872",
+    "/dots25678": "\u28F2",
+    "/dots2568": "\u28B2",
+    "/dots257": "\u2852",
+    "/dots2578": "\u28D2",
+    "/dots258": "\u2892",
+    "/dots26": "\u2822",
+    "/dots267": "\u2862",
+    "/dots2678": "\u28E2",
+    "/dots268": "\u28A2",
+    "/dots27": "\u2842",
+    "/dots278": "\u28C2",
+    "/dots28": "\u2882",
+    "/dots3": "\u2804",
+    "/dots34": "\u280C",
+    "/dots345": "\u281C",
+    "/dots3456": "\u283C",
+    "/dots34567": "\u287C",
+    "/dots345678": "\u28FC",
+    "/dots34568": "\u28BC",
+    "/dots3457": "\u285C",
+    "/dots34578": "\u28DC",
+    "/dots3458": "\u289C",
+    "/dots346": "\u282C",
+    "/dots3467": "\u286C",
+    "/dots34678": "\u28EC",
+    "/dots3468": "\u28AC",
+    "/dots347": "\u284C",
+    "/dots3478": "\u28CC",
+    "/dots348": "\u288C",
+    "/dots35": "\u2814",
+    "/dots356": "\u2834",
+    "/dots3567": "\u2874",
+    "/dots35678": "\u28F4",
+    "/dots3568": "\u28B4",
+    "/dots357": "\u2854",
+    "/dots3578": "\u28D4",
+    "/dots358": "\u2894",
+    "/dots36": "\u2824",
+    "/dots367": "\u2864",
+    "/dots3678": "\u28E4",
+    "/dots368": "\u28A4",
+    "/dots37": "\u2844",
+    "/dots378": "\u28C4",
+    "/dots38": "\u2884",
+    "/dots4": "\u2808",
+    "/dots45": "\u2818",
+    "/dots456": "\u2838",
+    "/dots4567": "\u2878",
+    "/dots45678": "\u28F8",
+    "/dots4568": "\u28B8",
+    "/dots457": "\u2858",
+    "/dots4578": "\u28D8",
+    "/dots458": "\u2898",
+    "/dots46": "\u2828",
+    "/dots467": "\u2868",
+    "/dots4678": "\u28E8",
+    "/dots468": "\u28A8",
+    "/dots47": "\u2848",
+    "/dots478": "\u28C8",
+    "/dots48": "\u2888",
+    "/dots5": "\u2810",
+    "/dots56": "\u2830",
+    "/dots567": "\u2870",
+    "/dots5678": "\u28F0",
+    "/dots568": "\u28B0",
+    "/dots57": "\u2850",
+    "/dots578": "\u28D0",
+    "/dots58": "\u2890",
+    "/dots6": "\u2820",
+    "/dots67": "\u2860",
+    "/dots678": "\u28E0",
+    "/dots68": "\u28A0",
+    "/dots7": "\u2840",
+    "/dots78": "\u28C0",
+    "/dots8": "\u2880",
+    "/dotsquarefour": "\u2E2C",
+    "/dottedcircle": "\u25CC",
+    "/dottedcross": "\u205C",
+    "/dotupper:hb": "\u05C4",
+    "/doublebarvertical": "\u23F8",
+    "/doubleyodpatah": "\uFB1F",
+    "/doubleyodpatahhebrew": "\uFB1F",
+    "/doughnut": "\u1F369",
+    "/doveOfPeace": "\u1F54A",
+    "/downtackbelowcmb": "\u031E",
+    "/downtackmod": "\u02D5",
+    "/downwarrowleftofuparrow": "\u21F5",
+    "/dparen": "\u249F",
+    "/dparenthesized": "\u249F",
+    "/drachma": "\u20AF",
+    "/dragon": "\u1F409",
+    "/dragonFace": "\u1F432",
+    "/draughtskingblack": "\u26C3",
+    "/draughtskingwhite": "\u26C1",
+    "/draughtsmanblack": "\u26C2",
+    "/draughtsmanwhite": "\u26C0",
+    "/dress": "\u1F457",
+    "/driveslow": "\u26DA",
+    "/dromedaryCamel": "\u1F42A",
+    "/droplet": "\u1F4A7",
+    "/dsquare": "\u1F1A5",
+    "/dsuperior": "\uF6EB",
+    "/dtail": "\u0256",
+    "/dtopbar": "\u018C",
+    "/duhiragana": "\u3065",
+    "/dukatakana": "\u30C5",
+    "/dul": "\u068E",
+    "/dul.fina": "\uFB87",
+    "/dul.isol": "\uFB86",
+    "/dum": "\uA771",
+    "/dvd": "\u1F4C0",
+    "/dyeh": "\u0684",
+    "/dyeh.fina": "\uFB73",
+    "/dyeh.init": "\uFB74",
+    "/dyeh.isol": "\uFB72",
+    "/dyeh.medi": "\uFB75",
+    "/dz": "\u01F3",
+    "/dzaltone": "\u02A3",
+    "/dzcaron": "\u01C6",
+    "/dzcurl": "\u02A5",
+    "/dzeabkhasiancyrillic": "\u04E1",
+    "/dzeabkhcyr": "\u04E1",
+    "/dzecyr": "\u0455",
+    "/dzecyrillic": "\u0455",
+    "/dzed": "\u02A3",
+    "/dzedcurl": "\u02A5",
+    "/dzhecyr": "\u045F",
+    "/dzhecyrillic": "\u045F",
+    "/dzjekomicyr": "\u0507",
+    "/dzzhecyr": "\u052B",
+    "/e": "\u0065",
+    "/e-mail": "\u1F4E7",
+    "/e.fina": "\uFBE5",
+    "/e.inferior": "\u2091",
+    "/e.init": "\uFBE6",
+    "/e.isol": "\uFBE4",
+    "/e.medi": "\uFBE7",
+    "/eVfullwidth": "\u32CE",
+    "/eacute": "\u00E9",
+    "/earOfMaize": "\u1F33D",
+    "/earOfRice": "\u1F33E",
+    "/earth": "\u2641",
+    "/earthGlobeAmericas": "\u1F30E",
+    "/earthGlobeAsiaAustralia": "\u1F30F",
+    "/earthGlobeEuropeAfrica": "\u1F30D",
+    "/earthground": "\u23DA",
+    "/earthideographiccircled": "\u328F",
+    "/earthideographicparen": "\u322F",
+    "/eastsyriaccross": "\u2671",
+    "/ebengali": "\u098F",
+    "/ebopomofo": "\u311C",
+    "/ebreve": "\u0115",
+    "/ecandradeva": "\u090D",
+    "/ecandragujarati": "\u0A8D",
+    "/ecandravowelsigndeva": "\u0945",
+    "/ecandravowelsigngujarati": "\u0AC5",
+    "/ecaron": "\u011B",
+    "/ecedilla": "\u0229",
+    "/ecedillabreve": "\u1E1D",
+    "/echarmenian": "\u0565",
+    "/echyiwnarmenian": "\u0587",
+    "/ecircle": "\u24D4",
+    "/ecirclekatakana": "\u32D3",
+    "/ecircumflex": "\u00EA",
+    "/ecircumflexacute": "\u1EBF",
+    "/ecircumflexbelow": "\u1E19",
+    "/ecircumflexdotbelow": "\u1EC7",
+    "/ecircumflexgrave": "\u1EC1",
+    "/ecircumflexhoi": "\u1EC3",
+    "/ecircumflexhookabove": "\u1EC3",
+    "/ecircumflextilde": "\u1EC5",
+    "/ecyrillic": "\u0454",
+    "/edblgrave": "\u0205",
+    "/edblstruckitalic": "\u2147",
+    "/edeva": "\u090F",
+    "/edieresis": "\u00EB",
+    "/edot": "\u0117",
+    "/edotaccent": "\u0117",
+    "/edotbelow": "\u1EB9",
+    "/eegurmukhi": "\u0A0F",
+    "/eekaasquare": "\u3308",
+    "/eematragurmukhi": "\u0A47",
+    "/efcyr": "\u0444",
+    "/efcyrillic": "\u0444",
+    "/egrave": "\u00E8",
+    "/egravedbl": "\u0205",
+    "/egujarati": "\u0A8F",
+    "/egyptain": "\uA725",
+    "/egyptalef": "\uA723",
+    "/eharmenian": "\u0567",
+    "/ehbopomofo": "\u311D",
+    "/ehiragana": "\u3048",
+    "/ehoi": "\u1EBB",
+    "/ehookabove": "\u1EBB",
+    "/eibopomofo": "\u311F",
+    "/eight": "\u0038",
+    "/eight.inferior": "\u2088",
+    "/eight.roman": "\u2167",
+    "/eight.romansmall": "\u2177",
+    "/eight.superior": "\u2078",
+    "/eightarabic": "\u0668",
+    "/eightbengali": "\u09EE",
+    "/eightcircle": "\u2467",
+    "/eightcircledbl": "\u24FC",
+    "/eightcircleinversesansserif": "\u2791",
+    "/eightcomma": "\u1F109",
+    "/eightdeva": "\u096E",
+    "/eighteencircle": "\u2471",
+    "/eighteencircleblack": "\u24F2",
+    "/eighteenparen": "\u2485",
+    "/eighteenparenthesized": "\u2485",
+    "/eighteenperiod": "\u2499",
+    "/eightfar": "\u06F8",
+    "/eightgujarati": "\u0AEE",
+    "/eightgurmukhi": "\u0A6E",
+    "/eighthackarabic": "\u0668",
+    "/eighthangzhou": "\u3028",
+    "/eighthnote": "\u266A",
+    "/eighthnotebeamed": "\u266B",
+    "/eightideographiccircled": "\u3287",
+    "/eightideographicparen": "\u3227",
+    "/eightinferior": "\u2088",
+    "/eightksquare": "\u1F19F",
+    "/eightmonospace": "\uFF18",
+    "/eightoldstyle": "\uF738",
+    "/eightparen": "\u247B",
+    "/eightparenthesized": "\u247B",
+    "/eightperiod": "\u248F",
+    "/eightpersian": "\u06F8",
+    "/eightroman": "\u2177",
+    "/eightsuperior": "\u2078",
+    "/eightthai": "\u0E58",
+    "/eightycirclesquare": "\u324F",
+    "/einvertedbreve": "\u0207",
+    "/eiotifiedcyr": "\u0465",
+    "/eiotifiedcyrillic": "\u0465",
+    "/eject": "\u23CF",
+    "/ekatakana": "\u30A8",
+    "/ekatakanahalfwidth": "\uFF74",
+    "/ekonkargurmukhi": "\u0A74",
+    "/ekorean": "\u3154",
+    "/elcyr": "\u043B",
+    "/elcyrillic": "\u043B",
+    "/electricLightBulb": "\u1F4A1",
+    "/electricPlug": "\u1F50C",
+    "/electricTorch": "\u1F526",
+    "/electricalintersection": "\u23E7",
+    "/electricarrow": "\u2301",
+    "/element": "\u2208",
+    "/elementdotabove": "\u22F5",
+    "/elementlonghorizontalstroke": "\u22F2",
+    "/elementopeningup": "\u27D2",
+    "/elementoverbar": "\u22F6",
+    "/elementoverbarsmall": "\u22F7",
+    "/elementsmall": "\u220A",
+    "/elementsmallverticalbarhorizontalstroke": "\u22F4",
+    "/elementtwoshorizontalstroke": "\u22F9",
+    "/elementunderbar": "\u22F8",
+    "/elementverticalbarhorizontalstroke": "\u22F3",
+    "/elephant": "\u1F418",
+    "/eleven.roman": "\u216A",
+    "/eleven.romansmall": "\u217A",
+    "/elevencircle": "\u246A",
+    "/elevencircleblack": "\u24EB",
+    "/elevenparen": "\u247E",
+    "/elevenparenthesized": "\u247E",
+    "/elevenperiod": "\u2492",
+    "/elevenroman": "\u217A",
+    "/elhookcyr": "\u0513",
+    "/ellipsis": "\u2026",
+    "/ellipsisdiagonaldownright": "\u22F1",
+    "/ellipsisdiagonalupright": "\u22F0",
+    "/ellipsismidhorizontal": "\u22EF",
+    "/ellipsisvertical": "\u22EE",
+    "/elmiddlehookcyr": "\u0521",
+    "/elsharptailcyr": "\u04C6",
+    "/eltailcyr": "\u052F",
+    "/emacron": "\u0113",
+    "/emacronacute": "\u1E17",
+    "/emacrongrave": "\u1E15",
+    "/emcyr": "\u043C",
+    "/emcyrillic": "\u043C",
+    "/emdash": "\u2014",
+    "/emdashdbl": "\u2E3A",
+    "/emdashtpl": "\u2E3B",
+    "/emdashvertical": "\uFE31",
+    "/emojiModifierFitzpatrickType-1-2": "\u1F3FB",
+    "/emojiModifierFitzpatrickType-3": "\u1F3FC",
+    "/emojiModifierFitzpatrickType-4": "\u1F3FD",
+    "/emojiModifierFitzpatrickType-5": "\u1F3FE",
+    "/emojiModifierFitzpatrickType-6": "\u1F3FF",
+    "/emonospace": "\uFF45",
+    "/emphasis": "\u2383",
+    "/emphasismarkarmenian": "\u055B",
+    "/emptyDocument": "\u1F5CB",
+    "/emptyNote": "\u1F5C5",
+    "/emptyNotePad": "\u1F5C7",
+    "/emptyNotePage": "\u1F5C6",
+    "/emptyPage": "\u1F5CC",
+    "/emptyPages": "\u1F5CD",
+    "/emptyset": "\u2205",
+    "/emquad": "\u2001",
+    "/emsharptailcyr": "\u04CE",
+    "/emspace": "\u2003",
+    "/enbopomofo": "\u3123",
+    "/encyr": "\u043D",
+    "/encyrillic": "\u043D",
+    "/endLeftwardsArrowAbove": "\u1F51A",
+    "/endash": "\u2013",
+    "/endashvertical": "\uFE32",
+    "/endescendercyrillic": "\u04A3",
+    "/endpro": "\u220E",
+    "/eng": "\u014B",
+    "/engbopomofo": "\u3125",
+    "/engecyr": "\u04A5",
+    "/enghecyrillic": "\u04A5",
+    "/enhookcyr": "\u04C8",
+    "/enhookcyrillic": "\u04C8",
+    "/enhookleftcyr": "\u0529",
+    "/enmiddlehookcyr": "\u0523",
+    "/enotch": "\u2C78",
+    "/enquad": "\u2000",
+    "/ensharptailcyr": "\u04CA",
+    "/enspace": "\u2002",
+    "/entailcyr": "\u04A3",
+    "/enter": "\u2386",
+    "/enterpriseideographiccircled": "\u32AD",
+    "/enterpriseideographicparen": "\u323D",
+    "/envelopeDownwardsArrowAbove": "\u1F4E9",
+    "/envelopeLightning": "\u1F584",
+    "/eogonek": "\u0119",
+    "/eokorean": "\u3153",
+    "/eopen": "\u025B",
+    "/eopenclosed": "\u029A",
+    "/eopenreversed": "\u025C",
+    "/eopenreversedclosed": "\u025E",
+    "/eopenreversedhook": "\u025D",
+    "/eparen": "\u24A0",
+    "/eparenthesized": "\u24A0",
+    "/epsilon": "\u03B5",
+    "/epsilonacute": "\u1F73",
+    "/epsilonasper": "\u1F11",
+    "/epsilonasperacute": "\u1F15",
+    "/epsilonaspergrave": "\u1F13",
+    "/epsilongrave": "\u1F72",
+    "/epsilonlenis": "\u1F10",
+    "/epsilonlenisacute": "\u1F14",
+    "/epsilonlenisgrave": "\u1F12",
+    "/epsilonlunatesymbol": "\u03F5",
+    "/epsilonreversedlunatesymbol": "\u03F6",
+    "/epsilontonos": "\u03AD",
+    "/epsilonunderlinefunc": "\u2377",
+    "/equal": "\u003D",
+    "/equal.inferior": "\u208C",
+    "/equal.superior": "\u207C",
+    "/equalandparallel": "\u22D5",
+    "/equalbydefinition": "\u225D",
+    "/equalmonospace": "\uFF1D",
+    "/equalorgreater": "\u22DD",
+    "/equalorless": "\u22DC",
+    "/equalorprecedes": "\u22DE",
+    "/equalorsucceeds": "\u22DF",
+    "/equalscolon": "\u2255",
+    "/equalsmall": "\uFE66",
+    "/equalsuperior": "\u207C",
+    "/equiangular": "\u225A",
+    "/equivalence": "\u2261",
+    "/equivalent": "\u224D",
+    "/eranameheiseisquare": "\u337B",
+    "/eranamemeizisquare": "\u337E",
+    "/eranamesyouwasquare": "\u337C",
+    "/eranametaisyousquare": "\u337D",
+    "/eraseleft": "\u232B",
+    "/eraseright": "\u2326",
+    "/erbopomofo": "\u3126",
+    "/ercyr": "\u0440",
+    "/ercyrillic": "\u0440",
+    "/ereversed": "\u0258",
+    "/ereversedcyr": "\u044D",
+    "/ereversedcyrillic": "\u044D",
+    "/ereverseddieresiscyr": "\u04ED",
+    "/ergfullwidth": "\u32CD",
+    "/ertickcyr": "\u048F",
+    "/escript": "\u212F",
+    "/escyr": "\u0441",
+    "/escyrillic": "\u0441",
+    "/esdescendercyrillic": "\u04AB",
+    "/esh": "\u0283",
+    "/eshcurl": "\u0286",
+    "/eshortdeva": "\u090E",
+    "/eshortvowelsigndeva": "\u0946",
+    "/eshreversedloop": "\u01AA",
+    "/eshsquatreversed": "\u0285",
+    "/esmallhiragana": "\u3047",
+    "/esmallkatakana": "\u30A7",
+    "/esmallkatakanahalfwidth": "\uFF6A",
+    "/estailcyr": "\u04AB",
+    "/estimated": "\u212E",
+    "/estimates": "\u2259",
+    "/estroke": "\u0247",
+    "/esukuudosquare": "\u3307",
+    "/esuperior": "\uF6EC",
+    "/et": "\uA76B",
+    "/eta": "\u03B7",
+    "/etaacute": "\u1F75",
+    "/etaacuteiotasub": "\u1FC4",
+    "/etaasper": "\u1F21",
+    "/etaasperacute": "\u1F25",
+    "/etaasperacuteiotasub": "\u1F95",
+    "/etaaspergrave": "\u1F23",
+    "/etaaspergraveiotasub": "\u1F93",
+    "/etaasperiotasub": "\u1F91",
+    "/etaaspertilde": "\u1F27",
+    "/etaaspertildeiotasub": "\u1F97",
+    "/etagrave": "\u1F74",
+    "/etagraveiotasub": "\u1FC2",
+    "/etaiotasub": "\u1FC3",
+    "/etalenis": "\u1F20",
+    "/etalenisacute": "\u1F24",
+    "/etalenisacuteiotasub": "\u1F94",
+    "/etalenisgrave": "\u1F22",
+    "/etalenisgraveiotasub": "\u1F92",
+    "/etalenisiotasub": "\u1F90",
+    "/etalenistilde": "\u1F26",
+    "/etalenistildeiotasub": "\u1F96",
+    "/etarmenian": "\u0568",
+    "/etatilde": "\u1FC6",
+    "/etatildeiotasub": "\u1FC7",
+    "/etatonos": "\u03AE",
+    "/eth": "\u00F0",
+    "/ethi:aaglottal": "\u12A3",
+    "/ethi:aglottal": "\u12A0",
+    "/ethi:ba": "\u1260",
+    "/ethi:baa": "\u1263",
+    "/ethi:be": "\u1265",
+    "/ethi:bee": "\u1264",
+    "/ethi:bi": "\u1262",
+    "/ethi:bo": "\u1266",
+    "/ethi:bu": "\u1261",
+    "/ethi:bwa": "\u1267",
+    "/ethi:ca": "\u1278",
+    "/ethi:caa": "\u127B",
+    "/ethi:ce": "\u127D",
+    "/ethi:cee": "\u127C",
+    "/ethi:cha": "\u1328",
+    "/ethi:chaa": "\u132B",
+    "/ethi:che": "\u132D",
+    "/ethi:chee": "\u132C",
+    "/ethi:chi": "\u132A",
+    "/ethi:cho": "\u132E",
+    "/ethi:chu": "\u1329",
+    "/ethi:chwa": "\u132F",
+    "/ethi:ci": "\u127A",
+    "/ethi:co": "\u127E",
+    "/ethi:colon": "\u1365",
+    "/ethi:comma": "\u1363",
+    "/ethi:cu": "\u1279",
+    "/ethi:cwa": "\u127F",
+    "/ethi:da": "\u12F0",
+    "/ethi:daa": "\u12F3",
+    "/ethi:dda": "\u12F8",
+    "/ethi:ddaa": "\u12FB",
+    "/ethi:dde": "\u12FD",
+    "/ethi:ddee": "\u12FC",
+    "/ethi:ddi": "\u12FA",
+    "/ethi:ddo": "\u12FE",
+    "/ethi:ddu": "\u12F9",
+    "/ethi:ddwa": "\u12FF",
+    "/ethi:de": "\u12F5",
+    "/ethi:dee": "\u12F4",
+    "/ethi:di": "\u12F2",
+    "/ethi:do": "\u12F6",
+    "/ethi:du": "\u12F1",
+    "/ethi:dwa": "\u12F7",
+    "/ethi:eeglottal": "\u12A4",
+    "/ethi:eglottal": "\u12A5",
+    "/ethi:eight": "\u1370",
+    "/ethi:eighty": "\u1379",
+    "/ethi:fa": "\u1348",
+    "/ethi:faa": "\u134B",
+    "/ethi:fe": "\u134D",
+    "/ethi:fee": "\u134C",
+    "/ethi:fi": "\u134A",
+    "/ethi:fifty": "\u1376",
+    "/ethi:five": "\u136D",
+    "/ethi:fo": "\u134E",
+    "/ethi:forty": "\u1375",
+    "/ethi:four": "\u136C",
+    "/ethi:fu": "\u1349",
+    "/ethi:fullstop": "\u1362",
+    "/ethi:fwa": "\u134F",
+    "/ethi:fya": "\u135A",
+    "/ethi:ga": "\u1308",
+    "/ethi:gaa": "\u130B",
+    "/ethi:ge": "\u130D",
+    "/ethi:gee": "\u130C",
+    "/ethi:geminationandvowellengthmarkcmb": "\u135D",
+    "/ethi:geminationmarkcmb": "\u135F",
+    "/ethi:gga": "\u1318",
+    "/ethi:ggaa": "\u131B",
+    "/ethi:gge": "\u131D",
+    "/ethi:ggee": "\u131C",
+    "/ethi:ggi": "\u131A",
+    "/ethi:ggo": "\u131E",
+    "/ethi:ggu": "\u1319",
+    "/ethi:ggwaa": "\u131F",
+    "/ethi:gi": "\u130A",
+    "/ethi:go": "\u130E",
+    "/ethi:goa": "\u130F",
+    "/ethi:gu": "\u1309",
+    "/ethi:gwa": "\u1310",
+    "/ethi:gwaa": "\u1313",
+    "/ethi:gwe": "\u1315",
+    "/ethi:gwee": "\u1314",
+    "/ethi:gwi": "\u1312",
+    "/ethi:ha": "\u1200",
+    "/ethi:haa": "\u1203",
+    "/ethi:he": "\u1205",
+    "/ethi:hee": "\u1204",
+    "/ethi:hha": "\u1210",
+    "/ethi:hhaa": "\u1213",
+    "/ethi:hhe": "\u1215",
+    "/ethi:hhee": "\u1214",
+    "/ethi:hhi": "\u1212",
+    "/ethi:hho": "\u1216",
+    "/ethi:hhu": "\u1211",
+    "/ethi:hhwa": "\u1217",
+    "/ethi:hi": "\u1202",
+    "/ethi:ho": "\u1206",
+    "/ethi:hoa": "\u1207",
+    "/ethi:hu": "\u1201",
+    "/ethi:hundred": "\u137B",
+    "/ethi:iglottal": "\u12A2",
+    "/ethi:ja": "\u1300",
+    "/ethi:jaa": "\u1303",
+    "/ethi:je": "\u1305",
+    "/ethi:jee": "\u1304",
+    "/ethi:ji": "\u1302",
+    "/ethi:jo": "\u1306",
+    "/ethi:ju": "\u1301",
+    "/ethi:jwa": "\u1307",
+    "/ethi:ka": "\u12A8",
+    "/ethi:kaa": "\u12AB",
+    "/ethi:ke": "\u12AD",
+    "/ethi:kee": "\u12AC",
+    "/ethi:ki": "\u12AA",
+    "/ethi:ko": "\u12AE",
+    "/ethi:koa": "\u12AF",
+    "/ethi:ku": "\u12A9",
+    "/ethi:kwa": "\u12B0",
+    "/ethi:kwaa": "\u12B3",
+    "/ethi:kwe": "\u12B5",
+    "/ethi:kwee": "\u12B4",
+    "/ethi:kwi": "\u12B2",
+    "/ethi:kxa": "\u12B8",
+    "/ethi:kxaa": "\u12BB",
+    "/ethi:kxe": "\u12BD",
+    "/ethi:kxee": "\u12BC",
+    "/ethi:kxi": "\u12BA",
+    "/ethi:kxo": "\u12BE",
+    "/ethi:kxu": "\u12B9",
+    "/ethi:kxwa": "\u12C0",
+    "/ethi:kxwaa": "\u12C3",
+    "/ethi:kxwe": "\u12C5",
+    "/ethi:kxwee": "\u12C4",
+    "/ethi:kxwi": "\u12C2",
+    "/ethi:la": "\u1208",
+    "/ethi:laa": "\u120B",
+    "/ethi:le": "\u120D",
+    "/ethi:lee": "\u120C",
+    "/ethi:li": "\u120A",
+    "/ethi:lo": "\u120E",
+    "/ethi:lu": "\u1209",
+    "/ethi:lwa": "\u120F",
+    "/ethi:ma": "\u1218",
+    "/ethi:maa": "\u121B",
+    "/ethi:me": "\u121D",
+    "/ethi:mee": "\u121C",
+    "/ethi:mi": "\u121A",
+    "/ethi:mo": "\u121E",
+    "/ethi:mu": "\u1219",
+    "/ethi:mwa": "\u121F",
+    "/ethi:mya": "\u1359",
+    "/ethi:na": "\u1290",
+    "/ethi:naa": "\u1293",
+    "/ethi:ne": "\u1295",
+    "/ethi:nee": "\u1294",
+    "/ethi:ni": "\u1292",
+    "/ethi:nine": "\u1371",
+    "/ethi:ninety": "\u137A",
+    "/ethi:no": "\u1296",
+    "/ethi:nu": "\u1291",
+    "/ethi:nwa": "\u1297",
+    "/ethi:nya": "\u1298",
+    "/ethi:nyaa": "\u129B",
+    "/ethi:nye": "\u129D",
+    "/ethi:nyee": "\u129C",
+    "/ethi:nyi": "\u129A",
+    "/ethi:nyo": "\u129E",
+    "/ethi:nyu": "\u1299",
+    "/ethi:nywa": "\u129F",
+    "/ethi:oglottal": "\u12A6",
+    "/ethi:one": "\u1369",
+    "/ethi:pa": "\u1350",
+    "/ethi:paa": "\u1353",
+    "/ethi:paragraphseparator": "\u1368",
+    "/ethi:pe": "\u1355",
+    "/ethi:pee": "\u1354",
+    "/ethi:pha": "\u1330",
+    "/ethi:phaa": "\u1333",
+    "/ethi:pharyngeala": "\u12D0",
+    "/ethi:pharyngealaa": "\u12D3",
+    "/ethi:pharyngeale": "\u12D5",
+    "/ethi:pharyngealee": "\u12D4",
+    "/ethi:pharyngeali": "\u12D2",
+    "/ethi:pharyngealo": "\u12D6",
+    "/ethi:pharyngealu": "\u12D1",
+    "/ethi:phe": "\u1335",
+    "/ethi:phee": "\u1334",
+    "/ethi:phi": "\u1332",
+    "/ethi:pho": "\u1336",
+    "/ethi:phu": "\u1331",
+    "/ethi:phwa": "\u1337",
+    "/ethi:pi": "\u1352",
+    "/ethi:po": "\u1356",
+    "/ethi:prefacecolon": "\u1366",
+    "/ethi:pu": "\u1351",
+    "/ethi:pwa": "\u1357",
+    "/ethi:qa": "\u1240",
+    "/ethi:qaa": "\u1243",
+    "/ethi:qe": "\u1245",
+    "/ethi:qee": "\u1244",
+    "/ethi:qha": "\u1250",
+    "/ethi:qhaa": "\u1253",
+    "/ethi:qhe": "\u1255",
+    "/ethi:qhee": "\u1254",
+    "/ethi:qhi": "\u1252",
+    "/ethi:qho": "\u1256",
+    "/ethi:qhu": "\u1251",
+    "/ethi:qhwa": "\u1258",
+    "/ethi:qhwaa": "\u125B",
+    "/ethi:qhwe": "\u125D",
+    "/ethi:qhwee": "\u125C",
+    "/ethi:qhwi": "\u125A",
+    "/ethi:qi": "\u1242",
+    "/ethi:qo": "\u1246",
+    "/ethi:qoa": "\u1247",
+    "/ethi:qu": "\u1241",
+    "/ethi:questionmark": "\u1367",
+    "/ethi:qwa": "\u1248",
+    "/ethi:qwaa": "\u124B",
+    "/ethi:qwe": "\u124D",
+    "/ethi:qwee": "\u124C",
+    "/ethi:qwi": "\u124A",
+    "/ethi:ra": "\u1228",
+    "/ethi:raa": "\u122B",
+    "/ethi:re": "\u122D",
+    "/ethi:ree": "\u122C",
+    "/ethi:ri": "\u122A",
+    "/ethi:ro": "\u122E",
+    "/ethi:ru": "\u1229",
+    "/ethi:rwa": "\u122F",
+    "/ethi:rya": "\u1358",
+    "/ethi:sa": "\u1230",
+    "/ethi:saa": "\u1233",
+    "/ethi:se": "\u1235",
+    "/ethi:sectionmark": "\u1360",
+    "/ethi:see": "\u1234",
+    "/ethi:semicolon": "\u1364",
+    "/ethi:seven": "\u136F",
+    "/ethi:seventy": "\u1378",
+    "/ethi:sha": "\u1238",
+    "/ethi:shaa": "\u123B",
+    "/ethi:she": "\u123D",
+    "/ethi:shee": "\u123C",
+    "/ethi:shi": "\u123A",
+    "/ethi:sho": "\u123E",
+    "/ethi:shu": "\u1239",
+    "/ethi:shwa": "\u123F",
+    "/ethi:si": "\u1232",
+    "/ethi:six": "\u136E",
+    "/ethi:sixty": "\u1377",
+    "/ethi:so": "\u1236",
+    "/ethi:su": "\u1231",
+    "/ethi:swa": "\u1237",
+    "/ethi:sza": "\u1220",
+    "/ethi:szaa": "\u1223",
+    "/ethi:sze": "\u1225",
+    "/ethi:szee": "\u1224",
+    "/ethi:szi": "\u1222",
+    "/ethi:szo": "\u1226",
+    "/ethi:szu": "\u1221",
+    "/ethi:szwa": "\u1227",
+    "/ethi:ta": "\u1270",
+    "/ethi:taa": "\u1273",
+    "/ethi:te": "\u1275",
+    "/ethi:tee": "\u1274",
+    "/ethi:ten": "\u1372",
+    "/ethi:tenthousand": "\u137C",
+    "/ethi:tha": "\u1320",
+    "/ethi:thaa": "\u1323",
+    "/ethi:the": "\u1325",
+    "/ethi:thee": "\u1324",
+    "/ethi:thi": "\u1322",
+    "/ethi:thirty": "\u1374",
+    "/ethi:tho": "\u1326",
+    "/ethi:three": "\u136B",
+    "/ethi:thu": "\u1321",
+    "/ethi:thwa": "\u1327",
+    "/ethi:ti": "\u1272",
+    "/ethi:to": "\u1276",
+    "/ethi:tsa": "\u1338",
+    "/ethi:tsaa": "\u133B",
+    "/ethi:tse": "\u133D",
+    "/ethi:tsee": "\u133C",
+    "/ethi:tsi": "\u133A",
+    "/ethi:tso": "\u133E",
+    "/ethi:tsu": "\u1339",
+    "/ethi:tswa": "\u133F",
+    "/ethi:tu": "\u1271",
+    "/ethi:twa": "\u1277",
+    "/ethi:twenty": "\u1373",
+    "/ethi:two": "\u136A",
+    "/ethi:tza": "\u1340",
+    "/ethi:tzaa": "\u1343",
+    "/ethi:tze": "\u1345",
+    "/ethi:tzee": "\u1344",
+    "/ethi:tzi": "\u1342",
+    "/ethi:tzo": "\u1346",
+    "/ethi:tzoa": "\u1347",
+    "/ethi:tzu": "\u1341",
+    "/ethi:uglottal": "\u12A1",
+    "/ethi:va": "\u1268",
+    "/ethi:vaa": "\u126B",
+    "/ethi:ve": "\u126D",
+    "/ethi:vee": "\u126C",
+    "/ethi:vi": "\u126A",
+    "/ethi:vo": "\u126E",
+    "/ethi:vowellengthmarkcmb": "\u135E",
+    "/ethi:vu": "\u1269",
+    "/ethi:vwa": "\u126F",
+    "/ethi:wa": "\u12C8",
+    "/ethi:waa": "\u12CB",
+    "/ethi:waglottal": "\u12A7",
+    "/ethi:we": "\u12CD",
+    "/ethi:wee": "\u12CC",
+    "/ethi:wi": "\u12CA",
+    "/ethi:wo": "\u12CE",
+    "/ethi:woa": "\u12CF",
+    "/ethi:wordspace": "\u1361",
+    "/ethi:wu": "\u12C9",
+    "/ethi:xa": "\u1280",
+    "/ethi:xaa": "\u1283",
+    "/ethi:xe": "\u1285",
+    "/ethi:xee": "\u1284",
+    "/ethi:xi": "\u1282",
+    "/ethi:xo": "\u1286",
+    "/ethi:xoa": "\u1287",
+    "/ethi:xu": "\u1281",
+    "/ethi:xwa": "\u1288",
+    "/ethi:xwaa": "\u128B",
+    "/ethi:xwe": "\u128D",
+    "/ethi:xwee": "\u128C",
+    "/ethi:xwi": "\u128A",
+    "/ethi:ya": "\u12E8",
+    "/ethi:yaa": "\u12EB",
+    "/ethi:ye": "\u12ED",
+    "/ethi:yee": "\u12EC",
+    "/ethi:yi": "\u12EA",
+    "/ethi:yo": "\u12EE",
+    "/ethi:yoa": "\u12EF",
+    "/ethi:yu": "\u12E9",
+    "/ethi:za": "\u12D8",
+    "/ethi:zaa": "\u12DB",
+    "/ethi:ze": "\u12DD",
+    "/ethi:zee": "\u12DC",
+    "/ethi:zha": "\u12E0",
+    "/ethi:zhaa": "\u12E3",
+    "/ethi:zhe": "\u12E5",
+    "/ethi:zhee": "\u12E4",
+    "/ethi:zhi": "\u12E2",
+    "/ethi:zho": "\u12E6",
+    "/ethi:zhu": "\u12E1",
+    "/ethi:zhwa": "\u12E7",
+    "/ethi:zi": "\u12DA",
+    "/ethi:zo": "\u12DE",
+    "/ethi:zu": "\u12D9",
+    "/ethi:zwa": "\u12DF",
+    "/etilde": "\u1EBD",
+    "/etildebelow": "\u1E1B",
+    "/etnahta:hb": "\u0591",
+    "/etnahtafoukhhebrew": "\u0591",
+    "/etnahtafoukhlefthebrew": "\u0591",
+    "/etnahtahebrew": "\u0591",
+    "/etnahtalefthebrew": "\u0591",
+    "/eturned": "\u01DD",
+    "/eukorean": "\u3161",
+    "/eukrcyr": "\u0454",
+    "/euler": "\u2107",
+    "/euro": "\u20AC",
+    "/euroarchaic": "\u20A0",
+    "/europeanCastle": "\u1F3F0",
+    "/europeanPostOffice": "\u1F3E4",
+    "/evergreenTree": "\u1F332",
+    "/evowelsignbengali": "\u09C7",
+    "/evowelsigndeva": "\u0947",
+    "/evowelsigngujarati": "\u0AC7",
+    "/excellentideographiccircled": "\u329D",
+    "/excess": "\u2239",
+    "/exclam": "\u0021",
+    "/exclamarmenian": "\u055C",
+    "/exclamationquestion": "\u2049",
+    "/exclamdbl": "\u203C",
+    "/exclamdown": "\u00A1",
+    "/exclamdownsmall": "\uF7A1",
+    "/exclammonospace": "\uFF01",
+    "/exclamsmall": "\uF721",
+    "/existential": "\u2203",
+    "/expressionlessFace": "\u1F611",
+    "/extraterrestrialAlien": "\u1F47D",
+    "/eye": "\u1F441",
+    "/eyeglasses": "\u1F453",
+    "/eyes": "\u1F440",
+    "/ezh": "\u0292",
+    "/ezhcaron": "\u01EF",
+    "/ezhcurl": "\u0293",
+    "/ezhreversed": "\u01B9",
+    "/ezhtail": "\u01BA",
+    "/f": "\u0066",
+    "/f_f": "\uFB00",
+    "/f_f_i": "\uFB03",
+    "/f_f_l": "\uFB04",
+    "/faceMassage": "\u1F486",
+    "/faceSavouringDeliciousFood": "\u1F60B",
+    "/faceScreamingInFear": "\u1F631",
+    "/faceThrowingAKiss": "\u1F618",
+    "/faceWithColdSweat": "\u1F613",
+    "/faceWithLookOfTriumph": "\u1F624",
+    "/faceWithMedicalMask": "\u1F637",
+    "/faceWithNoGoodGesture": "\u1F645",
+    "/faceWithOkGesture": "\u1F646",
+    "/faceWithOpenMouth": "\u1F62E",
+    "/faceWithOpenMouthAndColdSweat": "\u1F630",
+    "/faceWithRollingEyes": "\u1F644",
+    "/faceWithStuckOutTongue": "\u1F61B",
+    "/faceWithStuckOutTongueAndTightlyClosedEyes": "\u1F61D",
+    "/faceWithStuckOutTongueAndWinkingEye": "\u1F61C",
+    "/faceWithTearsOfJoy": "\u1F602",
+    "/faceWithoutMouth": "\u1F636",
+    "/facsimile": "\u213B",
+    "/factory": "\u1F3ED",
+    "/fadeva": "\u095E",
+    "/fagurmukhi": "\u0A5E",
+    "/fahrenheit": "\u2109",
+    "/fallenLeaf": "\u1F342",
+    "/fallingdiagonal": "\u27CD",
+    "/fallingdiagonalincircleinsquareblackwhite": "\u26DE",
+    "/family": "\u1F46A",
+    "/farsi": "\u262B",
+    "/farsiYehDigitFourBelow": "\u0777",
+    "/farsiYehDigitThreeAbove": "\u0776",
+    "/farsiYehDigitTwoAbove": "\u0775",
+    "/fatha": "\u064E",
+    "/fathaIsol": "\uFE76",
+    "/fathaMedi": "\uFE77",
+    "/fathaarabic": "\u064E",
+    "/fathalowarabic": "\u064E",
+    "/fathasmall": "\u0618",
+    "/fathatan": "\u064B",
+    "/fathatanIsol": "\uFE70",
+    "/fathatanarabic": "\u064B",
+    "/fathatwodotsdots": "\u065E",
+    "/fatherChristmas": "\u1F385",
+    "/faxIcon": "\u1F5B7",
+    "/faxMachine": "\u1F4E0",
+    "/fbopomofo": "\u3108",
+    "/fcircle": "\u24D5",
+    "/fdot": "\u1E1F",
+    "/fdotaccent": "\u1E1F",
+    "/fearfulFace": "\u1F628",
+    "/februarytelegraph": "\u32C1",
+    "/feh.fina": "\uFED2",
+    "/feh.init": "\uFED3",
+    "/feh.init_alefmaksura.fina": "\uFC31",
+    "/feh.init_hah.fina": "\uFC2E",
+    "/feh.init_hah.medi": "\uFCBF",
+    "/feh.init_jeem.fina": "\uFC2D",
+    "/feh.init_jeem.medi": "\uFCBE",
+    "/feh.init_khah.fina": "\uFC2F",
+    "/feh.init_khah.medi": "\uFCC0",
+    "/feh.init_khah.medi_meem.medi": "\uFD7D",
+    "/feh.init_meem.fina": "\uFC30",
+    "/feh.init_meem.medi": "\uFCC1",
+    "/feh.init_yeh.fina": "\uFC32",
+    "/feh.isol": "\uFED1",
+    "/feh.medi": "\uFED4",
+    "/feh.medi_alefmaksura.fina": "\uFC7C",
+    "/feh.medi_khah.medi_meem.fina": "\uFD7C",
+    "/feh.medi_meem.medi_yeh.fina": "\uFDC1",
+    "/feh.medi_yeh.fina": "\uFC7D",
+    "/fehThreeDotsUpBelow": "\u0761",
+    "/fehTwoDotsBelow": "\u0760",
+    "/feharabic": "\u0641",
+    "/feharmenian": "\u0586",
+    "/fehdotbelow": "\u06A3",
+    "/fehdotbelowright": "\u06A2",
+    "/fehfinalarabic": "\uFED2",
+    "/fehinitialarabic": "\uFED3",
+    "/fehmedialarabic": "\uFED4",
+    "/fehthreedotsbelow": "\u06A5",
+    "/feicoptic": "\u03E5",
+    "/female": "\u2640",
+    "/femaleideographiccircled": "\u329B",
+    "/feng": "\u02A9",
+    "/ferrisWheel": "\u1F3A1",
+    "/ferry": "\u26F4",
+    "/festivalideographicparen": "\u3240",
+    "/ff": "\uFB00",
+    "/ffi": "\uFB03",
+    "/ffl": "\uFB04",
+    "/fhook": "\u0192",
+    "/fi": "\uFB01",  # ligature "fi"
+    "/fieldHockeyStickAndBall": "\u1F3D1",
+    "/fifteencircle": "\u246E",
+    "/fifteencircleblack": "\u24EF",
+    "/fifteenparen": "\u2482",
+    "/fifteenparenthesized": "\u2482",
+    "/fifteenperiod": "\u2496",
+    "/fifty.roman": "\u216C",
+    "/fifty.romansmall": "\u217C",
+    "/fiftycircle": "\u32BF",
+    "/fiftycirclesquare": "\u324C",
+    "/fiftyearlyform.roman": "\u2186",
+    "/fiftythousand.roman": "\u2187",
+    "/figuredash": "\u2012",
+    "/figurespace": "\u2007",
+    "/fileCabinet": "\u1F5C4",
+    "/fileFolder": "\u1F4C1",
+    "/filledbox": "\u25A0",
+    "/filledrect": "\u25AC",
+    "/filledstopabove": "\u06EC",
+    "/filmFrames": "\u1F39E",
+    "/filmProjector": "\u1F4FD",
+    "/finalkaf": "\u05DA",
+    "/finalkaf:hb": "\u05DA",
+    "/finalkafdagesh": "\uFB3A",
+    "/finalkafdageshhebrew": "\uFB3A",
+    "/finalkafhebrew": "\u05DA",
+    "/finalkafqamats": "\u05DA",
+    "/finalkafqamatshebrew": "\u05DA",
+    "/finalkafsheva": "\u05DA",
+    "/finalkafshevahebrew": "\u05DA",
+    "/finalkafwithdagesh:hb": "\uFB3A",
+    "/finalmem": "\u05DD",
+    "/finalmem:hb": "\u05DD",
+    "/finalmemhebrew": "\u05DD",
+    "/finalmemwide:hb": "\uFB26",
+    "/finalnun": "\u05DF",
+    "/finalnun:hb": "\u05DF",
+    "/finalnunhebrew": "\u05DF",
+    "/finalpe": "\u05E3",
+    "/finalpe:hb": "\u05E3",
+    "/finalpehebrew": "\u05E3",
+    "/finalpewithdagesh:hb": "\uFB43",
+    "/finalsigma": "\u03C2",
+    "/finaltsadi": "\u05E5",
+    "/finaltsadi:hb": "\u05E5",
+    "/finaltsadihebrew": "\u05E5",
+    "/financialideographiccircled": "\u3296",
+    "/financialideographicparen": "\u3236",
+    "/finsular": "\uA77C",
+    "/fire": "\u1F525",
+    "/fireEngine": "\u1F692",
+    "/fireideographiccircled": "\u328B",
+    "/fireideographicparen": "\u322B",
+    "/fireworkSparkler": "\u1F387",
+    "/fireworks": "\u1F386",
+    "/firstQuarterMoon": "\u1F313",
+    "/firstQuarterMoonFace": "\u1F31B",
+    "/firstquartermoon": "\u263D",
+    "/firststrongisolate": "\u2068",
+    "/firsttonechinese": "\u02C9",
+    "/fish": "\u1F41F",
+    "/fishCakeSwirlDesign": "\u1F365",
+    "/fisheye": "\u25C9",
+    "/fishingPoleAndFish": "\u1F3A3",
+    "/fistedHandSign": "\u1F44A",
+    "/fitacyr": "\u0473",
+    "/fitacyrillic": "\u0473",
+    "/five": "\u0035",
+    "/five.inferior": "\u2085",
+    "/five.roman": "\u2164",
+    "/five.romansmall": "\u2174",
+    "/five.superior": "\u2075",
+    "/fivearabic": "\u0665",
+    "/fivebengali": "\u09EB",
+    "/fivecircle": "\u2464",
+    "/fivecircledbl": "\u24F9",
+    "/fivecircleinversesansserif": "\u278E",
+    "/fivecomma": "\u1F106",
+    "/fivedeva": "\u096B",
+    "/fivedot": "\u2E2D",
+    "/fivedotpunctuation": "\u2059",
+    "/fiveeighths": "\u215D",
+    "/fivefar": "\u06F5",
+    "/fivegujarati": "\u0AEB",
+    "/fivegurmukhi": "\u0A6B",
+    "/fivehackarabic": "\u0665",
+    "/fivehangzhou": "\u3025",
+    "/fivehundred.roman": "\u216E",
+    "/fivehundred.romansmall": "\u217E",
+    "/fiveideographiccircled": "\u3284",
+    "/fiveideographicparen": "\u3224",
+    "/fiveinferior": "\u2085",
+    "/fivemonospace": "\uFF15",
+    "/fiveoldstyle": "\uF735",
+    "/fiveparen": "\u2478",
+    "/fiveparenthesized": "\u2478",
+    "/fiveperiod": "\u248C",
+    "/fivepersian": "\u06F5",
+    "/fivepointedstar": "\u066D",
+    "/fivepointonesquare": "\u1F1A0",
+    "/fiveroman": "\u2174",
+    "/fivesixths": "\u215A",
+    "/fivesuperior": "\u2075",
+    "/fivethai": "\u0E55",
+    "/fivethousand.roman": "\u2181",
+    "/fl": "\uFB02",
+    "/flagblack": "\u2691",
+    "/flaghorizontalmiddlestripeblackwhite": "\u26FF",
+    "/flaginhole": "\u26F3",
+    "/flagwhite": "\u2690",
+    "/flatness": "\u23E5",
+    "/fleurdelis": "\u269C",
+    "/flexedBiceps": "\u1F4AA",
+    "/floorleft": "\u230A",
+    "/floorright": "\u230B",
+    "/floppyDisk": "\u1F4BE",
+    "/floralheartbulletreversedrotated": "\u2619",
+    "/florin": "\u0192",
+    "/flower": "\u2698",
+    "/flowerPlayingCards": "\u1F3B4",
+    "/flowerpunctuationmark": "\u2055",
+    "/flushedFace": "\u1F633",
+    "/flyingEnvelope": "\u1F585",
+    "/flyingSaucer": "\u1F6F8",
+    "/fmfullwidth": "\u3399",
+    "/fmonospace": "\uFF46",
+    "/fmsquare": "\u3399",
+    "/fofanthai": "\u0E1F",
+    "/fofathai": "\u0E1D",
+    "/fog": "\u1F32B",
+    "/foggy": "\u1F301",
+    "/folder": "\u1F5C0",
+    "/fongmanthai": "\u0E4F",
+    "/footnote": "\u0602",
+    "/footprints": "\u1F463",
+    "/footsquare": "\u23CD",
+    "/forall": "\u2200",
+    "/forces": "\u22A9",
+    "/fork": "\u2442",
+    "/forkKnife": "\u1F374",
+    "/forkKnifePlate": "\u1F37D",
+    "/forsamaritan": "\u214F",
+    "/fortycircle": "\u32B5",
+    "/fortycirclesquare": "\u324B",
+    "/fortyeightcircle": "\u32BD",
+    "/fortyfivecircle": "\u32BA",
+    "/fortyfourcircle": "\u32B9",
+    "/fortyninecircle": "\u32BE",
+    "/fortyonecircle": "\u32B6",
+    "/fortysevencircle": "\u32BC",
+    "/fortysixcircle": "\u32BB",
+    "/fortythreecircle": "\u32B8",
+    "/fortytwocircle": "\u32B7",
+    "/fountain": "\u26F2",
+    "/four": "\u0034",
+    "/four.inferior": "\u2084",
+    "/four.roman": "\u2163",
+    "/four.romansmall": "\u2173",
+    "/four.superior": "\u2074",
+    "/fourLeafClover": "\u1F340",
+    "/fourarabic": "\u0664",
+    "/fourbengali": "\u09EA",
+    "/fourcircle": "\u2463",
+    "/fourcircledbl": "\u24F8",
+    "/fourcircleinversesansserif": "\u278D",
+    "/fourcomma": "\u1F105",
+    "/fourdeva": "\u096A",
+    "/fourdotmark": "\u205B",
+    "/fourdotpunctuation": "\u2058",
+    "/fourfar": "\u06F4",
+    "/fourfifths": "\u2158",
+    "/fourgujarati": "\u0AEA",
+    "/fourgurmukhi": "\u0A6A",
+    "/fourhackarabic": "\u0664",
+    "/fourhangzhou": "\u3024",
+    "/fourideographiccircled": "\u3283",
+    "/fourideographicparen": "\u3223",
+    "/fourinferior": "\u2084",
+    "/fourksquare": "\u1F19E",
+    "/fourmonospace": "\uFF14",
+    "/fournumeratorbengali": "\u09F7",
+    "/fouroldstyle": "\uF734",
+    "/fourparen": "\u2477",
+    "/fourparenthesized": "\u2477",
+    "/fourperemspace": "\u2005",
+    "/fourperiod": "\u248B",
+    "/fourpersian": "\u06F4",
+    "/fourroman": "\u2173",
+    "/foursuperior": "\u2074",
+    "/fourteencircle": "\u246D",
+    "/fourteencircleblack": "\u24EE",
+    "/fourteenparen": "\u2481",
+    "/fourteenparenthesized": "\u2481",
+    "/fourteenperiod": "\u2495",
+    "/fourthai": "\u0E54",
+    "/fourthtonechinese": "\u02CB",
+    "/fparen": "\u24A1",
+    "/fparenthesized": "\u24A1",
+    "/fraction": "\u2044",
+    "/frameAnX": "\u1F5BE",
+    "/framePicture": "\u1F5BC",
+    "/frameTiles": "\u1F5BD",
+    "/franc": "\u20A3",
+    "/freesquare": "\u1F193",
+    "/frenchFries": "\u1F35F",
+    "/freversedepigraphic": "\uA7FB",
+    "/friedShrimp": "\u1F364",
+    "/frogFace": "\u1F438",
+    "/front-facingBabyChick": "\u1F425",
+    "/frown": "\u2322",
+    "/frowningFaceWithOpenMouth": "\u1F626",
+    "/frowningfacewhite": "\u2639",
+    "/fstroke": "\uA799",
+    "/fturned": "\u214E",
+    "/fuelpump": "\u26FD",
+    "/fullBlock": "\u2588",
+    "/fullMoon": "\u1F315",
+    "/fullMoonFace": "\u1F31D",
+    "/functionapplication": "\u2061",
+    "/funeralurn": "\u26B1",
+    "/fuse": "\u23DB",
+    "/fwd:A": "\uFF21",
+    "/fwd:B": "\uFF22",
+    "/fwd:C": "\uFF23",
+    "/fwd:D": "\uFF24",
+    "/fwd:E": "\uFF25",
+    "/fwd:F": "\uFF26",
+    "/fwd:G": "\uFF27",
+    "/fwd:H": "\uFF28",
+    "/fwd:I": "\uFF29",
+    "/fwd:J": "\uFF2A",
+    "/fwd:K": "\uFF2B",
+    "/fwd:L": "\uFF2C",
+    "/fwd:M": "\uFF2D",
+    "/fwd:N": "\uFF2E",
+    "/fwd:O": "\uFF2F",
+    "/fwd:P": "\uFF30",
+    "/fwd:Q": "\uFF31",
+    "/fwd:R": "\uFF32",
+    "/fwd:S": "\uFF33",
+    "/fwd:T": "\uFF34",
+    "/fwd:U": "\uFF35",
+    "/fwd:V": "\uFF36",
+    "/fwd:W": "\uFF37",
+    "/fwd:X": "\uFF38",
+    "/fwd:Y": "\uFF39",
+    "/fwd:Z": "\uFF3A",
+    "/fwd:a": "\uFF41",
+    "/fwd:ampersand": "\uFF06",
+    "/fwd:asciicircum": "\uFF3E",
+    "/fwd:asciitilde": "\uFF5E",
+    "/fwd:asterisk": "\uFF0A",
+    "/fwd:at": "\uFF20",
+    "/fwd:b": "\uFF42",
+    "/fwd:backslash": "\uFF3C",
+    "/fwd:bar": "\uFF5C",
+    "/fwd:braceleft": "\uFF5B",
+    "/fwd:braceright": "\uFF5D",
+    "/fwd:bracketleft": "\uFF3B",
+    "/fwd:bracketright": "\uFF3D",
+    "/fwd:brokenbar": "\uFFE4",
+    "/fwd:c": "\uFF43",
+    "/fwd:centsign": "\uFFE0",
+    "/fwd:colon": "\uFF1A",
+    "/fwd:comma": "\uFF0C",
+    "/fwd:d": "\uFF44",
+    "/fwd:dollar": "\uFF04",
+    "/fwd:e": "\uFF45",
+    "/fwd:eight": "\uFF18",
+    "/fwd:equal": "\uFF1D",
+    "/fwd:exclam": "\uFF01",
+    "/fwd:f": "\uFF46",
+    "/fwd:five": "\uFF15",
+    "/fwd:four": "\uFF14",
+    "/fwd:g": "\uFF47",
+    "/fwd:grave": "\uFF40",
+    "/fwd:greater": "\uFF1E",
+    "/fwd:h": "\uFF48",
+    "/fwd:hyphen": "\uFF0D",
+    "/fwd:i": "\uFF49",
+    "/fwd:j": "\uFF4A",
+    "/fwd:k": "\uFF4B",
+    "/fwd:l": "\uFF4C",
+    "/fwd:leftwhiteparenthesis": "\uFF5F",
+    "/fwd:less": "\uFF1C",
+    "/fwd:m": "\uFF4D",
+    "/fwd:macron": "\uFFE3",
+    "/fwd:n": "\uFF4E",
+    "/fwd:nine": "\uFF19",
+    "/fwd:notsign": "\uFFE2",
+    "/fwd:numbersign": "\uFF03",
+    "/fwd:o": "\uFF4F",
+    "/fwd:one": "\uFF11",
+    "/fwd:p": "\uFF50",
+    "/fwd:parenthesisleft": "\uFF08",
+    "/fwd:parenthesisright": "\uFF09",
+    "/fwd:percent": "\uFF05",
+    "/fwd:period": "\uFF0E",
+    "/fwd:plus": "\uFF0B",
+    "/fwd:poundsign": "\uFFE1",
+    "/fwd:q": "\uFF51",
+    "/fwd:question": "\uFF1F",
+    "/fwd:quotedbl": "\uFF02",
+    "/fwd:quotesingle": "\uFF07",
+    "/fwd:r": "\uFF52",
+    "/fwd:rightwhiteparenthesis": "\uFF60",
+    "/fwd:s": "\uFF53",
+    "/fwd:semicolon": "\uFF1B",
+    "/fwd:seven": "\uFF17",
+    "/fwd:six": "\uFF16",
+    "/fwd:slash": "\uFF0F",
+    "/fwd:t": "\uFF54",
+    "/fwd:three": "\uFF13",
+    "/fwd:two": "\uFF12",
+    "/fwd:u": "\uFF55",
+    "/fwd:underscore": "\uFF3F",
+    "/fwd:v": "\uFF56",
+    "/fwd:w": "\uFF57",
+    "/fwd:wonsign": "\uFFE6",
+    "/fwd:x": "\uFF58",
+    "/fwd:y": "\uFF59",
+    "/fwd:yensign": "\uFFE5",
+    "/fwd:z": "\uFF5A",
+    "/fwd:zero": "\uFF10",
+    "/g": "\u0067",
+    "/gabengali": "\u0997",
+    "/gacute": "\u01F5",
+    "/gadeva": "\u0917",
+    "/gaf": "\u06AF",
+    "/gaf.fina": "\uFB93",
+    "/gaf.init": "\uFB94",
+    "/gaf.isol": "\uFB92",
+    "/gaf.medi": "\uFB95",
+    "/gafarabic": "\u06AF",
+    "/gaffinalarabic": "\uFB93",
+    "/gafinitialarabic": "\uFB94",
+    "/gafmedialarabic": "\uFB95",
+    "/gafring": "\u06B0",
+    "/gafthreedotsabove": "\u06B4",
+    "/gaftwodotsbelow": "\u06B2",
+    "/gagujarati": "\u0A97",
+    "/gagurmukhi": "\u0A17",
+    "/gahiragana": "\u304C",
+    "/gakatakana": "\u30AC",
+    "/galsquare": "\u33FF",
+    "/gameDie": "\u1F3B2",
+    "/gamma": "\u03B3",
+    "/gammadblstruck": "\u213D",
+    "/gammalatinsmall": "\u0263",
+    "/gammasuperior": "\u02E0",
+    "/gammasupmod": "\u02E0",
+    "/gamurda": "\uA993",
+    "/gangiacoptic": "\u03EB",
+    "/ganmasquare": "\u330F",
+    "/garonsquare": "\u330E",
+    "/gbfullwidth": "\u3387",
+    "/gbopomofo": "\u310D",
+    "/gbreve": "\u011F",
+    "/gcaron": "\u01E7",
+    "/gcedilla": "\u0123",
+    "/gcircle": "\u24D6",
+    "/gcircumflex": "\u011D",
+    "/gcommaaccent": "\u0123",
+    "/gdot": "\u0121",
+    "/gdotaccent": "\u0121",
+    "/gear": "\u2699",
+    "/gearhles": "\u26EE",
+    "/gearouthub": "\u26ED",
+    "/gecyr": "\u0433",
+    "/gecyrillic": "\u0433",
+    "/gehiragana": "\u3052",
+    "/gehookcyr": "\u0495",
+    "/gehookstrokecyr": "\u04FB",
+    "/gekatakana": "\u30B2",
+    "/gemStone": "\u1F48E",
+    "/gemini": "\u264A",
+    "/geometricallyequal": "\u2251",
+    "/geometricallyequivalent": "\u224E",
+    "/geometricproportion": "\u223A",
+    "/geresh:hb": "\u05F3",
+    "/gereshMuqdam:hb": "\u059D",
+    "/gereshaccenthebrew": "\u059C",
+    "/gereshhebrew": "\u05F3",
+    "/gereshmuqdamhebrew": "\u059D",
+    "/germandbls": "\u00DF",
+    "/germanpenny": "\u20B0",
+    "/gershayim:hb": "\u05F4",
+    "/gershayimaccenthebrew": "\u059E",
+    "/gershayimhebrew": "\u05F4",
+    "/gestrokecyr": "\u0493",
+    "/getailcyr": "\u04F7",
+    "/getamark": "\u3013",
+    "/geupcyr": "\u0491",
+    "/ghabengali": "\u0998",
+    "/ghadarmenian": "\u0572",
+    "/ghadeva": "\u0918",
+    "/ghagujarati": "\u0A98",
+    "/ghagurmukhi": "\u0A18",
+    "/ghain": "\u063A",
+    "/ghain.fina": "\uFECE",
+    "/ghain.init": "\uFECF",
+    "/ghain.init_alefmaksura.fina": "\uFCF9",
+    "/ghain.init_jeem.fina": "\uFC2B",
+    "/ghain.init_jeem.medi": "\uFCBC",
+    "/ghain.init_meem.fina": "\uFC2C",
+    "/ghain.init_meem.medi": "\uFCBD",
+    "/ghain.init_yeh.fina": "\uFCFA",
+    "/ghain.isol": "\uFECD",
+    "/ghain.medi": "\uFED0",
+    "/ghain.medi_alefmaksura.fina": "\uFD15",
+    "/ghain.medi_meem.medi_alefmaksura.fina": "\uFD7B",
+    "/ghain.medi_meem.medi_meem.fina": "\uFD79",
+    "/ghain.medi_meem.medi_yeh.fina": "\uFD7A",
+    "/ghain.medi_yeh.fina": "\uFD16",
+    "/ghainarabic": "\u063A",
+    "/ghaindotbelow": "\u06FC",
+    "/ghainfinalarabic": "\uFECE",
+    "/ghaininitialarabic": "\uFECF",
+    "/ghainmedialarabic": "\uFED0",
+    "/ghemiddlehookcyrillic": "\u0495",
+    "/ghestrokecyrillic": "\u0493",
+    "/gheupturncyrillic": "\u0491",
+    "/ghhadeva": "\u095A",
+    "/ghhagurmukhi": "\u0A5A",
+    "/ghook": "\u0260",
+    "/ghost": "\u1F47B",
+    "/ghzfullwidth": "\u3393",
+    "/ghzsquare": "\u3393",
+    "/gigasquare": "\u3310",
+    "/gihiragana": "\u304E",
+    "/gikatakana": "\u30AE",
+    "/gimarmenian": "\u0563",
+    "/gimel": "\u05D2",
+    "/gimel:hb": "\u05D2",
+    "/gimeldagesh": "\uFB32",
+    "/gimeldageshhebrew": "\uFB32",
+    "/gimelhebrew": "\u05D2",
+    "/gimelwithdagesh:hb": "\uFB32",
+    "/giniisquare": "\u3311",
+    "/ginsularturned": "\uA77F",
+    "/girl": "\u1F467",
+    "/girls": "\u1F6CA",
+    "/girudaasquare": "\u3313",
+    "/gjecyr": "\u0453",
+    "/gjecyrillic": "\u0453",
+    "/globeMeridians": "\u1F310",
+    "/glottalinvertedstroke": "\u01BE",
+    "/glottalstop": "\u0294",
+    "/glottalstopinverted": "\u0296",
+    "/glottalstopmod": "\u02C0",
+    "/glottalstopreversed": "\u0295",
+    "/glottalstopreversedmod": "\u02C1",
+    "/glottalstopreversedsuperior": "\u02E4",
+    "/glottalstopstroke": "\u02A1",
+    "/glottalstopstrokereversed": "\u02A2",
+    "/glottalstopsupreversedmod": "\u02E4",
+    "/glowingStar": "\u1F31F",
+    "/gmacron": "\u1E21",
+    "/gmonospace": "\uFF47",
+    "/gmtr:diamondblack": "\u25C6",
+    "/gmtr:diamondwhite": "\u25C7",
+    "/gnrl:hyphen": "\u2010",
+    "/goat": "\u1F410",
+    "/gobliquestroke": "\uA7A1",
+    "/gohiragana": "\u3054",
+    "/gokatakana": "\u30B4",
+    "/golfer": "\u1F3CC",
+    "/gpafullwidth": "\u33AC",
+    "/gparen": "\u24A2",
+    "/gparenthesized": "\u24A2",
+    "/gpasquare": "\u33AC",
+    "/gr:acute": "\u1FFD",
+    "/gr:grave": "\u1FEF",
+    "/gr:question": "\u037E",
+    "/gr:tilde": "\u1FC0",
+    "/gradient": "\u2207",
+    "/graduationCap": "\u1F393",
+    "/grapes": "\u1F347",
+    "/grave": "\u0060",
+    "/gravebelowcmb": "\u0316",
+    "/gravecmb": "\u0300",
+    "/gravecomb": "\u0300",
+    "/gravedblmiddlemod": "\u02F5",
+    "/gravedeva": "\u0953",
+    "/gravelowmod": "\u02CE",
+    "/gravemiddlemod": "\u02F4",
+    "/gravemod": "\u02CB",
+    "/gravemonospace": "\uFF40",
+    "/gravetonecmb": "\u0340",
+    "/greater": "\u003E",
+    "/greaterbutnotequal": "\u2269",
+    "/greaterbutnotequivalent": "\u22E7",
+    "/greaterdot": "\u22D7",
+    "/greaterequal": "\u2265",
+    "/greaterequalorless": "\u22DB",
+    "/greatermonospace": "\uFF1E",
+    "/greaterorequivalent": "\u2273",
+    "/greaterorless": "\u2277",
+    "/greateroverequal": "\u2267",
+    "/greatersmall": "\uFE65",
+    "/greenApple": "\u1F34F",
+    "/greenBook": "\u1F4D7",
+    "/greenHeart": "\u1F49A",
+    "/grimacingFace": "\u1F62C",
+    "/grinningCatFaceWithSmilingEyes": "\u1F638",
+    "/grinningFace": "\u1F600",
+    "/grinningFaceWithSmilingEyes": "\u1F601",
+    "/growingHeart": "\u1F497",
+    "/gscript": "\u0261",
+    "/gstroke": "\u01E5",
+    "/guarani": "\u20B2",
+    "/guardsman": "\u1F482",
+    "/gueh": "\u06B3",
+    "/gueh.fina": "\uFB97",
+    "/gueh.init": "\uFB98",
+    "/gueh.isol": "\uFB96",
+    "/gueh.medi": "\uFB99",
+    "/guhiragana": "\u3050",
+    "/guillemetleft": "\u00AB",
+    "/guillemetright": "\u00BB",
+    "/guillemotleft": "\u00AB",
+    "/guillemotright": "\u00BB",
+    "/guilsinglleft": "\u2039",
+    "/guilsinglright": "\u203A",
+    "/guitar": "\u1F3B8",
+    "/gujr:a": "\u0A85",
+    "/gujr:aa": "\u0A86",
+    "/gujr:aasign": "\u0ABE",
+    "/gujr:abbreviation": "\u0AF0",
+    "/gujr:ai": "\u0A90",
+    "/gujr:aisign": "\u0AC8",
+    "/gujr:anusvara": "\u0A82",
+    "/gujr:au": "\u0A94",
+    "/gujr:ausign": "\u0ACC",
+    "/gujr:avagraha": "\u0ABD",
+    "/gujr:ba": "\u0AAC",
+    "/gujr:bha": "\u0AAD",
+    "/gujr:binducandra": "\u0A81",
+    "/gujr:ca": "\u0A9A",
+    "/gujr:cha": "\u0A9B",
+    "/gujr:circlenuktaabove": "\u0AFE",
+    "/gujr:da": "\u0AA6",
+    "/gujr:dda": "\u0AA1",
+    "/gujr:ddha": "\u0AA2",
+    "/gujr:dha": "\u0AA7",
+    "/gujr:e": "\u0A8F",
+    "/gujr:ecandra": "\u0A8D",
+    "/gujr:eight": "\u0AEE",
+    "/gujr:esign": "\u0AC7",
+    "/gujr:esigncandra": "\u0AC5",
+    "/gujr:five": "\u0AEB",
+    "/gujr:four": "\u0AEA",
+    "/gujr:ga": "\u0A97",
+    "/gujr:gha": "\u0A98",
+    "/gujr:ha": "\u0AB9",
+    "/gujr:i": "\u0A87",
+    "/gujr:ii": "\u0A88",
+    "/gujr:iisign": "\u0AC0",
+    "/gujr:isign": "\u0ABF",
+    "/gujr:ja": "\u0A9C",
+    "/gujr:jha": "\u0A9D",
+    "/gujr:ka": "\u0A95",
+    "/gujr:kha": "\u0A96",
+    "/gujr:la": "\u0AB2",
+    "/gujr:lla": "\u0AB3",
+    "/gujr:llvocal": "\u0AE1",
+    "/gujr:llvocalsign": "\u0AE3",
+    "/gujr:lvocal": "\u0A8C",
+    "/gujr:lvocalsign": "\u0AE2",
+    "/gujr:ma": "\u0AAE",
+    "/gujr:maddah": "\u0AFC",
+    "/gujr:na": "\u0AA8",
+    "/gujr:nga": "\u0A99",
+    "/gujr:nine": "\u0AEF",
+    "/gujr:nna": "\u0AA3",
+    "/gujr:nukta": "\u0ABC",
+    "/gujr:nya": "\u0A9E",
+    "/gujr:o": "\u0A93",
+    "/gujr:ocandra": "\u0A91",
+    "/gujr:om": "\u0AD0",
+    "/gujr:one": "\u0AE7",
+    "/gujr:osign": "\u0ACB",
+    "/gujr:osigncandra": "\u0AC9",
+    "/gujr:pa": "\u0AAA",
+    "/gujr:pha": "\u0AAB",
+    "/gujr:ra": "\u0AB0",
+    "/gujr:rrvocal": "\u0AE0",
+    "/gujr:rrvocalsign": "\u0AC4",
+    "/gujr:rupee": "\u0AF1",
+    "/gujr:rvocal": "\u0A8B",
+    "/gujr:rvocalsign": "\u0AC3",
+    "/gujr:sa": "\u0AB8",
+    "/gujr:seven": "\u0AED",
+    "/gujr:sha": "\u0AB6",
+    "/gujr:shadda": "\u0AFB",
+    "/gujr:six": "\u0AEC",
+    "/gujr:ssa": "\u0AB7",
+    "/gujr:sukun": "\u0AFA",
+    "/gujr:ta": "\u0AA4",
+    "/gujr:tha": "\u0AA5",
+    "/gujr:three": "\u0AE9",
+    "/gujr:three-dotnuktaabove": "\u0AFD",
+    "/gujr:tta": "\u0A9F",
+    "/gujr:ttha": "\u0AA0",
+    "/gujr:two": "\u0AE8",
+    "/gujr:two-circlenuktaabove": "\u0AFF",
+    "/gujr:u": "\u0A89",
+    "/gujr:usign": "\u0AC1",
+    "/gujr:uu": "\u0A8A",
+    "/gujr:uusign": "\u0AC2",
+    "/gujr:va": "\u0AB5",
+    "/gujr:virama": "\u0ACD",
+    "/gujr:visarga": "\u0A83",
+    "/gujr:ya": "\u0AAF",
+    "/gujr:zero": "\u0AE6",
+    "/gujr:zha": "\u0AF9",
+    "/gukatakana": "\u30B0",
+    "/guramusquare": "\u3318",
+    "/guramutonsquare": "\u3319",
+    "/guru:a": "\u0A05",
+    "/guru:aa": "\u0A06",
+    "/guru:aasign": "\u0A3E",
+    "/guru:adakbindisign": "\u0A01",
+    "/guru:addak": "\u0A71",
+    "/guru:ai": "\u0A10",
+    "/guru:aisign": "\u0A48",
+    "/guru:au": "\u0A14",
+    "/guru:ausign": "\u0A4C",
+    "/guru:ba": "\u0A2C",
+    "/guru:bha": "\u0A2D",
+    "/guru:bindisign": "\u0A02",
+    "/guru:ca": "\u0A1A",
+    "/guru:cha": "\u0A1B",
+    "/guru:da": "\u0A26",
+    "/guru:dda": "\u0A21",
+    "/guru:ddha": "\u0A22",
+    "/guru:dha": "\u0A27",
+    "/guru:ee": "\u0A0F",
+    "/guru:eesign": "\u0A47",
+    "/guru:eight": "\u0A6E",
+    "/guru:ekonkar": "\u0A74",
+    "/guru:fa": "\u0A5E",
+    "/guru:five": "\u0A6B",
+    "/guru:four": "\u0A6A",
+    "/guru:ga": "\u0A17",
+    "/guru:gha": "\u0A18",
+    "/guru:ghha": "\u0A5A",
+    "/guru:ha": "\u0A39",
+    "/guru:i": "\u0A07",
+    "/guru:ii": "\u0A08",
+    "/guru:iisign": "\u0A40",
+    "/guru:iri": "\u0A72",
+    "/guru:isign": "\u0A3F",
+    "/guru:ja": "\u0A1C",
+    "/guru:jha": "\u0A1D",
+    "/guru:ka": "\u0A15",
+    "/guru:kha": "\u0A16",
+    "/guru:khha": "\u0A59",
+    "/guru:la": "\u0A32",
+    "/guru:lla": "\u0A33",
+    "/guru:ma": "\u0A2E",
+    "/guru:na": "\u0A28",
+    "/guru:nga": "\u0A19",
+    "/guru:nine": "\u0A6F",
+    "/guru:nna": "\u0A23",
+    "/guru:nukta": "\u0A3C",
+    "/guru:nya": "\u0A1E",
+    "/guru:one": "\u0A67",
+    "/guru:oo": "\u0A13",
+    "/guru:oosign": "\u0A4B",
+    "/guru:pa": "\u0A2A",
+    "/guru:pha": "\u0A2B",
+    "/guru:ra": "\u0A30",
+    "/guru:rra": "\u0A5C",
+    "/guru:sa": "\u0A38",
+    "/guru:seven": "\u0A6D",
+    "/guru:sha": "\u0A36",
+    "/guru:six": "\u0A6C",
+    "/guru:ta": "\u0A24",
+    "/guru:tha": "\u0A25",
+    "/guru:three": "\u0A69",
+    "/guru:tippi": "\u0A70",
+    "/guru:tta": "\u0A1F",
+    "/guru:ttha": "\u0A20",
+    "/guru:two": "\u0A68",
+    "/guru:u": "\u0A09",
+    "/guru:udaatsign": "\u0A51",
+    "/guru:ura": "\u0A73",
+    "/guru:usign": "\u0A41",
+    "/guru:uu": "\u0A0A",
+    "/guru:uusign": "\u0A42",
+    "/guru:va": "\u0A35",
+    "/guru:virama": "\u0A4D",
+    "/guru:visarga": "\u0A03",
+    "/guru:ya": "\u0A2F",
+    "/guru:yakashsign": "\u0A75",
+    "/guru:za": "\u0A5B",
+    "/guru:zero": "\u0A66",
+    "/gyfullwidth": "\u33C9",
+    "/gysquare": "\u33C9",
+    "/h": "\u0068",
+    "/h.inferior": "\u2095",
+    "/haabkhasiancyrillic": "\u04A9",
+    "/haabkhcyr": "\u04A9",
+    "/haaltonearabic": "\u06C1",
+    "/habengali": "\u09B9",
+    "/hacirclekatakana": "\u32E9",
+    "/hacyr": "\u0445",
+    "/hadescendercyrillic": "\u04B3",
+    "/hadeva": "\u0939",
+    "/hafullwidth": "\u33CA",
+    "/hagujarati": "\u0AB9",
+    "/hagurmukhi": "\u0A39",
+    "/hah": "\u062D",
+    "/hah.fina": "\uFEA2",
+    "/hah.init": "\uFEA3",
+    "/hah.init_alefmaksura.fina": "\uFCFF",
+    "/hah.init_jeem.fina": "\uFC17",
+    "/hah.init_jeem.medi": "\uFCA9",
+    "/hah.init_meem.fina": "\uFC18",
+    "/hah.init_meem.medi": "\uFCAA",
+    "/hah.init_yeh.fina": "\uFD00",
+    "/hah.isol": "\uFEA1",
+    "/hah.medi": "\uFEA4",
+    "/hah.medi_alefmaksura.fina": "\uFD1B",
+    "/hah.medi_jeem.medi_yeh.fina": "\uFDBF",
+    "/hah.medi_meem.medi_alefmaksura.fina": "\uFD5B",
+    "/hah.medi_meem.medi_yeh.fina": "\uFD5A",
+    "/hah.medi_yeh.fina": "\uFD1C",
+    "/hahDigitFourBelow": "\u077C",
+    "/hahSmallTahAbove": "\u0772",
+    "/hahSmallTahBelow": "\u076E",
+    "/hahSmallTahTwoDots": "\u076F",
+    "/hahThreeDotsUpBelow": "\u0758",
+    "/hahTwoDotsAbove": "\u0757",
+    "/haharabic": "\u062D",
+    "/hahfinalarabic": "\uFEA2",
+    "/hahhamza": "\u0681",
+    "/hahinitialarabic": "\uFEA3",
+    "/hahiragana": "\u306F",
+    "/hahmedialarabic": "\uFEA4",
+    "/hahookcyr": "\u04FD",
+    "/hahthreedotsabove": "\u0685",
+    "/hahtwodotsvertical": "\u0682",
+    "/haircut": "\u1F487",
+    "/hairspace": "\u200A",
+    "/haitusquare": "\u332A",
+    "/hakatakana": "\u30CF",
+    "/hakatakanahalfwidth": "\uFF8A",
+    "/halantgurmukhi": "\u0A4D",
+    "/halfcircleleftblack": "\u25D6",
+    "/halfcirclerightblack": "\u25D7",
+    "/hamburger": "\u1F354",
+    "/hammer": "\u1F528",
+    "/hammerAndWrench": "\u1F6E0",
+    "/hammerpick": "\u2692",
+    "/hammersickle": "\u262D",
+    "/hamsterFace": "\u1F439",
+    "/hamza": "\u0621",
+    "/hamzaIsol": "\uFE80",
+    "/hamzaabove": "\u0654",
+    "/hamzaarabic": "\u0621",
+    "/hamzabelow": "\u0655",
+    "/hamzadammaarabic": "\u0621",
+    "/hamzadammatanarabic": "\u0621",
+    "/hamzafathaarabic": "\u0621",
+    "/hamzafathatanarabic": "\u0621",
+    "/hamzalowarabic": "\u0621",
+    "/hamzalowkasraarabic": "\u0621",
+    "/hamzalowkasratanarabic": "\u0621",
+    "/hamzasukunarabic": "\u0621",
+    "/handbag": "\u1F45C",
+    "/handtailfishhookturned": "\u02AF",
+    "/hangulchieuchaparen": "\u3217",
+    "/hangulchieuchparen": "\u3209",
+    "/hangulcieucaparen": "\u3216",
+    "/hangulcieucparen": "\u3208",
+    "/hangulcieucuparen": "\u321C",
+    "/hanguldottonemarkdbl": "\u302F",
+    "/hangulfiller": "\u3164",
+    "/hangulhieuhaparen": "\u321B",
+    "/hangulhieuhparen": "\u320D",
+    "/hangulieungaparen": "\u3215",
+    "/hangulieungparen": "\u3207",
+    "/hangulkhieukhaparen": "\u3218",
+    "/hangulkhieukhparen": "\u320A",
+    "/hangulkiyeokaparen": "\u320E",
+    "/hangulkiyeokparen": "\u3200",
+    "/hangulmieumaparen": "\u3212",
+    "/hangulmieumparen": "\u3204",
+    "/hangulnieunaparen": "\u320F",
+    "/hangulnieunparen": "\u3201",
+    "/hangulphieuphaparen": "\u321A",
+    "/hangulphieuphparen": "\u320C",
+    "/hangulpieupaparen": "\u3213",
+    "/hangulpieupparen": "\u3205",
+    "/hangulrieulaparen": "\u3211",
+    "/hangulrieulparen": "\u3203",
+    "/hangulsingledottonemark": "\u302E",
+    "/hangulsiosaparen": "\u3214",
+    "/hangulsiosparen": "\u3206",
+    "/hangulthieuthaparen": "\u3219",
+    "/hangulthieuthparen": "\u320B",
+    "/hangultikeutaparen": "\u3210",
+    "/hangultikeutparen": "\u3202",
+    "/happyPersonRaisingOneHand": "\u1F64B",
+    "/hardDisk": "\u1F5B4",
+    "/hardcyr": "\u044A",
+    "/hardsigncyrillic": "\u044A",
+    "/harpoondownbarbleft": "\u21C3",
+    "/harpoondownbarbright": "\u21C2",
+    "/harpoonleftbarbdown": "\u21BD",
+    "/harpoonleftbarbup": "\u21BC",
+    "/harpoonrightbarbdown": "\u21C1",
+    "/harpoonrightbarbup": "\u21C0",
+    "/harpoonupbarbleft": "\u21BF",
+    "/harpoonupbarbright": "\u21BE",
+    "/hasquare": "\u33CA",
+    "/hastrokecyr": "\u04FF",
+    "/hatafPatah:hb": "\u05B2",
+    "/hatafQamats:hb": "\u05B3",
+    "/hatafSegol:hb": "\u05B1",
+    "/hatafpatah": "\u05B2",
+    "/hatafpatah16": "\u05B2",
+    "/hatafpatah23": "\u05B2",
+    "/hatafpatah2f": "\u05B2",
+    "/hatafpatahhebrew": "\u05B2",
+    "/hatafpatahnarrowhebrew": "\u05B2",
+    "/hatafpatahquarterhebrew": "\u05B2",
+    "/hatafpatahwidehebrew": "\u05B2",
+    "/hatafqamats": "\u05B3",
+    "/hatafqamats1b": "\u05B3",
+    "/hatafqamats28": "\u05B3",
+    "/hatafqamats34": "\u05B3",
+    "/hatafqamatshebrew": "\u05B3",
+    "/hatafqamatsnarrowhebrew": "\u05B3",
+    "/hatafqamatsquarterhebrew": "\u05B3",
+    "/hatafqamatswidehebrew": "\u05B3",
+    "/hatafsegol": "\u05B1",
+    "/hatafsegol17": "\u05B1",
+    "/hatafsegol24": "\u05B1",
+    "/hatafsegol30": "\u05B1",
+    "/hatafsegolhebrew": "\u05B1",
+    "/hatafsegolnarrowhebrew": "\u05B1",
+    "/hatafsegolquarterhebrew": "\u05B1",
+    "/hatafsegolwidehebrew": "\u05B1",
+    "/hatchingChick": "\u1F423",
+    "/haveideographiccircled": "\u3292",
+    "/haveideographicparen": "\u3232",
+    "/hbar": "\u0127",
+    "/hbopomofo": "\u310F",
+    "/hbrevebelow": "\u1E2B",
+    "/hcaron": "\u021F",
+    "/hcedilla": "\u1E29",
+    "/hcircle": "\u24D7",
+    "/hcircumflex": "\u0125",
+    "/hcsquare": "\u1F1A6",
+    "/hdescender": "\u2C68",
+    "/hdieresis": "\u1E27",
+    "/hdot": "\u1E23",
+    "/hdotaccent": "\u1E23",
+    "/hdotbelow": "\u1E25",
+    "/hdrsquare": "\u1F1A7",
+    "/he": "\u05D4",
+    "/he:hb": "\u05D4",
+    "/headphone": "\u1F3A7",
+    "/headstonegraveyard": "\u26FC",
+    "/hearNoEvilMonkey": "\u1F649",
+    "/heart": "\u2665",
+    "/heartArrow": "\u1F498",
+    "/heartDecoration": "\u1F49F",
+    "/heartRibbon": "\u1F49D",
+    "/heartTipOnTheLeft": "\u1F394",
+    "/heartblack": "\u2665",
+    "/heartsuitblack": "\u2665",
+    "/heartsuitwhite": "\u2661",
+    "/heartwhite": "\u2661",
+    "/heavyDollarSign": "\u1F4B2",
+    "/heavyLatinCross": "\u1F547",
+    "/heavydbldashhorz": "\u254D",
+    "/heavydbldashvert": "\u254F",
+    "/heavydn": "\u257B",
+    "/heavydnhorz": "\u2533",
+    "/heavydnleft": "\u2513",
+    "/heavydnright": "\u250F",
+    "/heavyhorz": "\u2501",
+    "/heavyleft": "\u2578",
+    "/heavyleftlightright": "\u257E",
+    "/heavyquaddashhorz": "\u2509",
+    "/heavyquaddashvert": "\u250B",
+    "/heavyright": "\u257A",
+    "/heavytrpldashhorz": "\u2505",
+    "/heavytrpldashvert": "\u2507",
+    "/heavyup": "\u2579",
+    "/heavyuphorz": "\u253B",
+    "/heavyupleft": "\u251B",
+    "/heavyuplightdn": "\u257F",
+    "/heavyupright": "\u2517",
+    "/heavyvert": "\u2503",
+    "/heavyverthorz": "\u254B",
+    "/heavyvertleft": "\u252B",
+    "/heavyvertright": "\u2523",
+    "/hecirclekatakana": "\u32EC",
+    "/hedagesh": "\uFB34",
+    "/hedageshhebrew": "\uFB34",
+    "/hedinterlacedpentagramleft": "\u26E6",
+    "/hedinterlacedpentagramright": "\u26E5",
+    "/heh": "\u0647",
+    "/heh.fina": "\uFEEA",
+    "/heh.init": "\uFEEB",
+    "/heh.init_alefmaksura.fina": "\uFC53",
+    "/heh.init_jeem.fina": "\uFC51",
+    "/heh.init_jeem.medi": "\uFCD7",
+    "/heh.init_meem.fina": "\uFC52",
+    "/heh.init_meem.medi": "\uFCD8",
+    "/heh.init_meem.medi_jeem.medi": "\uFD93",
+    "/heh.init_meem.medi_meem.medi": "\uFD94",
+    "/heh.init_superscriptalef.medi": "\uFCD9",
+    "/heh.init_yeh.fina": "\uFC54",
+    "/heh.isol": "\uFEE9",
+    "/heh.medi": "\uFEEC",
+    "/hehaltonearabic": "\u06C1",
+    "/heharabic": "\u0647",
+    "/hehdoachashmee": "\u06BE",
+    "/hehdoachashmee.fina": "\uFBAB",
+    "/hehdoachashmee.init": "\uFBAC",
+    "/hehdoachashmee.isol": "\uFBAA",
+    "/hehdoachashmee.medi": "\uFBAD",
+    "/hehebrew": "\u05D4",
+    "/hehfinalaltonearabic": "\uFBA7",
+    "/hehfinalalttwoarabic": "\uFEEA",
+    "/hehfinalarabic": "\uFEEA",
+    "/hehgoal": "\u06C1",
+    "/hehgoal.fina": "\uFBA7",
+    "/hehgoal.init": "\uFBA8",
+    "/hehgoal.isol": "\uFBA6",
+    "/hehgoal.medi": "\uFBA9",
+    "/hehgoalhamza": "\u06C2",
+    "/hehhamzaabovefinalarabic": "\uFBA5",
+    "/hehhamzaaboveisolatedarabic": "\uFBA4",
+    "/hehinitialaltonearabic": "\uFBA8",
+    "/hehinitialarabic": "\uFEEB",
+    "/hehinvertedV": "\u06FF",
+    "/hehiragana": "\u3078",
+    "/hehmedialaltonearabic": "\uFBA9",
+    "/hehmedialarabic": "\uFEEC",
+    "/hehyeh": "\u06C0",
+    "/hehyeh.fina": "\uFBA5",
+    "/hehyeh.isol": "\uFBA4",
+    "/heiseierasquare": "\u337B",
+    "/hekatakana": "\u30D8",
+    "/hekatakanahalfwidth": "\uFF8D",
+    "/hekutaarusquare": "\u3336",
+    "/helicopter": "\u1F681",
+    "/helm": "\u2388",
+    "/helmetcrosswhite": "\u26D1",
+    "/heng": "\uA727",
+    "/henghook": "\u0267",
+    "/herb": "\u1F33F",
+    "/hermitianconjugatematrix": "\u22B9",
+    "/herutusquare": "\u3339",
+    "/het": "\u05D7",
+    "/het:hb": "\u05D7",
+    "/heta": "\u0371",
+    "/hethebrew": "\u05D7",
+    "/hewide:hb": "\uFB23",
+    "/hewithmapiq:hb": "\uFB34",
+    "/hfishhookturned": "\u02AE",
+    "/hhalf": "\u2C76",
+    "/hhook": "\u0266",
+    "/hhooksuperior": "\u02B1",
+    "/hhooksupmod": "\u02B1",
+    "/hi-ressquare": "\u1F1A8",
+    "/hibiscus": "\u1F33A",
+    "/hicirclekatakana": "\u32EA",
+    "/hieuhacirclekorean": "\u327B",
+    "/hieuhaparenkorean": "\u321B",
+    "/hieuhcirclekorean": "\u326D",
+    "/hieuhkorean": "\u314E",
+    "/hieuhparenkorean": "\u320D",
+    "/high-heeledShoe": "\u1F460",
+    "/highBrightness": "\u1F506",
+    "/highSpeedTrain": "\u1F684",
+    "/highSpeedTrainWithBulletNose": "\u1F685",
+    "/highhamza": "\u0674",
+    "/highideographiccircled": "\u32A4",
+    "/highvoltage": "\u26A1",
+    "/hihiragana": "\u3072",
+    "/hikatakana": "\u30D2",
+    "/hikatakanahalfwidth": "\uFF8B",
+    "/hira:a": "\u3042",
+    "/hira:asmall": "\u3041",
+    "/hira:ba": "\u3070",
+    "/hira:be": "\u3079",
+    "/hira:bi": "\u3073",
+    "/hira:bo": "\u307C",
+    "/hira:bu": "\u3076",
+    "/hira:da": "\u3060",
+    "/hira:de": "\u3067",
+    "/hira:di": "\u3062",
+    "/hira:digraphyori": "\u309F",
+    "/hira:do": "\u3069",
+    "/hira:du": "\u3065",
+    "/hira:e": "\u3048",
+    "/hira:esmall": "\u3047",
+    "/hira:ga": "\u304C",
+    "/hira:ge": "\u3052",
+    "/hira:gi": "\u304E",
+    "/hira:go": "\u3054",
+    "/hira:gu": "\u3050",
+    "/hira:ha": "\u306F",
+    "/hira:he": "\u3078",
+    "/hira:hi": "\u3072",
+    "/hira:ho": "\u307B",
+    "/hira:hu": "\u3075",
+    "/hira:i": "\u3044",
+    "/hira:ismall": "\u3043",
+    "/hira:iterationhiragana": "\u309D",
+    "/hira:ka": "\u304B",
+    "/hira:kasmall": "\u3095",
+    "/hira:ke": "\u3051",
+    "/hira:kesmall": "\u3096",
+    "/hira:ki": "\u304D",
+    "/hira:ko": "\u3053",
+    "/hira:ku": "\u304F",
+    "/hira:ma": "\u307E",
+    "/hira:me": "\u3081",
+    "/hira:mi": "\u307F",
+    "/hira:mo": "\u3082",
+    "/hira:mu": "\u3080",
+    "/hira:n": "\u3093",
+    "/hira:na": "\u306A",
+    "/hira:ne": "\u306D",
+    "/hira:ni": "\u306B",
+    "/hira:no": "\u306E",
+    "/hira:nu": "\u306C",
+    "/hira:o": "\u304A",
+    "/hira:osmall": "\u3049",
+    "/hira:pa": "\u3071",
+    "/hira:pe": "\u307A",
+    "/hira:pi": "\u3074",
+    "/hira:po": "\u307D",
+    "/hira:pu": "\u3077",
+    "/hira:ra": "\u3089",
+    "/hira:re": "\u308C",
+    "/hira:ri": "\u308A",
+    "/hira:ro": "\u308D",
+    "/hira:ru": "\u308B",
+    "/hira:sa": "\u3055",
+    "/hira:se": "\u305B",
+    "/hira:semivoicedmarkkana": "\u309C",
+    "/hira:semivoicedmarkkanacmb": "\u309A",
+    "/hira:si": "\u3057",
+    "/hira:so": "\u305D",
+    "/hira:su": "\u3059",
+    "/hira:ta": "\u305F",
+    "/hira:te": "\u3066",
+    "/hira:ti": "\u3061",
+    "/hira:to": "\u3068",
+    "/hira:tu": "\u3064",
+    "/hira:tusmall": "\u3063",
+    "/hira:u": "\u3046",
+    "/hira:usmall": "\u3045",
+    "/hira:voicediterationhiragana": "\u309E",
+    "/hira:voicedmarkkana": "\u309B",
+    "/hira:voicedmarkkanacmb": "\u3099",
+    "/hira:vu": "\u3094",
+    "/hira:wa": "\u308F",
+    "/hira:wasmall": "\u308E",
+    "/hira:we": "\u3091",
+    "/hira:wi": "\u3090",
+    "/hira:wo": "\u3092",
+    "/hira:ya": "\u3084",
+    "/hira:yasmall": "\u3083",
+    "/hira:yo": "\u3088",
+    "/hira:yosmall": "\u3087",
+    "/hira:yu": "\u3086",
+    "/hira:yusmall": "\u3085",
+    "/hira:za": "\u3056",
+    "/hira:ze": "\u305C",
+    "/hira:zi": "\u3058",
+    "/hira:zo": "\u305E",
+    "/hira:zu": "\u305A",
+    "/hiriq": "\u05B4",
+    "/hiriq14": "\u05B4",
+    "/hiriq21": "\u05B4",
+    "/hiriq2d": "\u05B4",
+    "/hiriq:hb": "\u05B4",
+    "/hiriqhebrew": "\u05B4",
+    "/hiriqnarrowhebrew": "\u05B4",
+    "/hiriqquarterhebrew": "\u05B4",
+    "/hiriqwidehebrew": "\u05B4",
+    "/historicsite": "\u26EC",
+    "/hlinebelow": "\u1E96",
+    "/hmonospace": "\uFF48",
+    "/hoarmenian": "\u0570",
+    "/hocho": "\u1F52A",
+    "/hocirclekatakana": "\u32ED",
+    "/hohipthai": "\u0E2B",
+    "/hohiragana": "\u307B",
+    "/hokatakana": "\u30DB",
+    "/hokatakanahalfwidth": "\uFF8E",
+    "/holam": "\u05B9",
+    "/holam19": "\u05B9",
+    "/holam26": "\u05B9",
+    "/holam32": "\u05B9",
+    "/holam:hb": "\u05B9",
+    "/holamHaser:hb": "\u05BA",
+    "/holamhebrew": "\u05B9",
+    "/holamnarrowhebrew": "\u05B9",
+    "/holamquarterhebrew": "\u05B9",
+    "/holamwidehebrew": "\u05B9",
+    "/hole": "\u1F573",
+    "/homotic": "\u223B",
+    "/honeyPot": "\u1F36F",
+    "/honeybee": "\u1F41D",
+    "/honokhukthai": "\u0E2E",
+    "/honsquare": "\u333F",
+    "/hook": "\u2440",
+    "/hookabovecomb": "\u0309",
+    "/hookcmb": "\u0309",
+    "/hookpalatalizedbelowcmb": "\u0321",
+    "/hookretroflexbelowcmb": "\u0322",
+    "/hoonsquare": "\u3342",
+    "/hoorusquare": "\u3341",
+    "/horicoptic": "\u03E9",
+    "/horizontalTrafficLight": "\u1F6A5",
+    "/horizontalbar": "\u2015",
+    "/horizontalbarwhitearrowonpedestalup": "\u21EC",
+    "/horizontalmalestroke": "\u26A9",
+    "/horncmb": "\u031B",
+    "/horse": "\u1F40E",
+    "/horseFace": "\u1F434",
+    "/horseRacing": "\u1F3C7",
+    "/hospital": "\u1F3E5",
+    "/hotDog": "\u1F32D",
+    "/hotPepper": "\u1F336",
+    "/hotbeverage": "\u2615",
+    "/hotel": "\u1F3E8",
+    "/hotsprings": "\u2668",
+    "/hourglass": "\u231B",
+    "/hourglassflowings": "\u23F3",
+    "/house": "\u2302",
+    "/houseBuilding": "\u1F3E0",
+    "/houseBuildings": "\u1F3D8",
+    "/houseGarden": "\u1F3E1",
+    "/hpafullwidth": "\u3371",
+    "/hpalatalhook": "\uA795",
+    "/hparen": "\u24A3",
+    "/hparenthesized": "\u24A3",
+    "/hpfullwidth": "\u33CB",
+    "/hryvnia": "\u20B4",
+    "/hsuperior": "\u02B0",
+    "/hsupmod": "\u02B0",
+    "/hturned": "\u0265",
+    "/htypeopencircuit": "\u238F",
+    "/huaraddosquare": "\u3332",
+    "/hucirclekatakana": "\u32EB",
+    "/huhiragana": "\u3075",
+    "/huiitosquare": "\u3333",
+    "/hukatakana": "\u30D5",
+    "/hukatakanahalfwidth": "\uFF8C",
+    "/hundredPoints": "\u1F4AF",
+    "/hundredthousandscmbcyr": "\u0488",
+    "/hungarumlaut": "\u02DD",
+    "/hungarumlautcmb": "\u030B",
+    "/huransquare": "\u3335",
+    "/hushedFace": "\u1F62F",
+    "/hv": "\u0195",
+    "/hwd:a": "\uFFC2",
+    "/hwd:ae": "\uFFC3",
+    "/hwd:blacksquare": "\uFFED",
+    "/hwd:chieuch": "\uFFBA",
+    "/hwd:cieuc": "\uFFB8",
+    "/hwd:downwardsarrow": "\uFFEC",
+    "/hwd:e": "\uFFC7",
+    "/hwd:eo": "\uFFC6",
+    "/hwd:eu": "\uFFDA",
+    "/hwd:formslightvertical": "\uFFE8",
+    "/hwd:hangulfiller": "\uFFA0",
+    "/hwd:hieuh": "\uFFBE",
+    "/hwd:i": "\uFFDC",
+    "/hwd:ideographiccomma": "\uFF64",
+    "/hwd:ideographicfullstop": "\uFF61",
+    "/hwd:ieung": "\uFFB7",
+    "/hwd:kata:a": "\uFF71",
+    "/hwd:kata:asmall": "\uFF67",
+    "/hwd:kata:e": "\uFF74",
+    "/hwd:kata:esmall": "\uFF6A",
+    "/hwd:kata:ha": "\uFF8A",
+    "/hwd:kata:he": "\uFF8D",
+    "/hwd:kata:hi": "\uFF8B",
+    "/hwd:kata:ho": "\uFF8E",
+    "/hwd:kata:hu": "\uFF8C",
+    "/hwd:kata:i": "\uFF72",
+    "/hwd:kata:ismall": "\uFF68",
+    "/hwd:kata:ka": "\uFF76",
+    "/hwd:kata:ke": "\uFF79",
+    "/hwd:kata:ki": "\uFF77",
+    "/hwd:kata:ko": "\uFF7A",
+    "/hwd:kata:ku": "\uFF78",
+    "/hwd:kata:ma": "\uFF8F",
+    "/hwd:kata:me": "\uFF92",
+    "/hwd:kata:mi": "\uFF90",
+    "/hwd:kata:middledot": "\uFF65",
+    "/hwd:kata:mo": "\uFF93",
+    "/hwd:kata:mu": "\uFF91",
+    "/hwd:kata:n": "\uFF9D",
+    "/hwd:kata:na": "\uFF85",
+    "/hwd:kata:ne": "\uFF88",
+    "/hwd:kata:ni": "\uFF86",
+    "/hwd:kata:no": "\uFF89",
+    "/hwd:kata:nu": "\uFF87",
+    "/hwd:kata:o": "\uFF75",
+    "/hwd:kata:osmall": "\uFF6B",
+    "/hwd:kata:prolongedkana": "\uFF70",
+    "/hwd:kata:ra": "\uFF97",
+    "/hwd:kata:re": "\uFF9A",
+    "/hwd:kata:ri": "\uFF98",
+    "/hwd:kata:ro": "\uFF9B",
+    "/hwd:kata:ru": "\uFF99",
+    "/hwd:kata:sa": "\uFF7B",
+    "/hwd:kata:se": "\uFF7E",
+    "/hwd:kata:semi-voiced": "\uFF9F",
+    "/hwd:kata:si": "\uFF7C",
+    "/hwd:kata:so": "\uFF7F",
+    "/hwd:kata:su": "\uFF7D",
+    "/hwd:kata:ta": "\uFF80",
+    "/hwd:kata:te": "\uFF83",
+    "/hwd:kata:ti": "\uFF81",
+    "/hwd:kata:to": "\uFF84",
+    "/hwd:kata:tu": "\uFF82",
+    "/hwd:kata:tusmall": "\uFF6F",
+    "/hwd:kata:u": "\uFF73",
+    "/hwd:kata:usmall": "\uFF69",
+    "/hwd:kata:voiced": "\uFF9E",
+    "/hwd:kata:wa": "\uFF9C",
+    "/hwd:kata:wo": "\uFF66",
+    "/hwd:kata:ya": "\uFF94",
+    "/hwd:kata:yasmall": "\uFF6C",
+    "/hwd:kata:yo": "\uFF96",
+    "/hwd:kata:yosmall": "\uFF6E",
+    "/hwd:kata:yu": "\uFF95",
+    "/hwd:kata:yusmall": "\uFF6D",
+    "/hwd:khieukh": "\uFFBB",
+    "/hwd:kiyeok": "\uFFA1",
+    "/hwd:kiyeoksios": "\uFFA3",
+    "/hwd:leftcornerbracket": "\uFF62",
+    "/hwd:leftwardsarrow": "\uFFE9",
+    "/hwd:mieum": "\uFFB1",
+    "/hwd:nieun": "\uFFA4",
+    "/hwd:nieuncieuc": "\uFFA5",
+    "/hwd:nieunhieuh": "\uFFA6",
+    "/hwd:o": "\uFFCC",
+    "/hwd:oe": "\uFFCF",
+    "/hwd:phieuph": "\uFFBD",
+    "/hwd:pieup": "\uFFB2",
+    "/hwd:pieupsios": "\uFFB4",
+    "/hwd:rieul": "\uFFA9",
+    "/hwd:rieulhieuh": "\uFFB0",
+    "/hwd:rieulkiyeok": "\uFFAA",
+    "/hwd:rieulmieum": "\uFFAB",
+    "/hwd:rieulphieuph": "\uFFAF",
+    "/hwd:rieulpieup": "\uFFAC",
+    "/hwd:rieulsios": "\uFFAD",
+    "/hwd:rieulthieuth": "\uFFAE",
+    "/hwd:rightcornerbracket": "\uFF63",
+    "/hwd:rightwardsarrow": "\uFFEB",
+    "/hwd:sios": "\uFFB5",
+    "/hwd:ssangcieuc": "\uFFB9",
+    "/hwd:ssangkiyeok": "\uFFA2",
+    "/hwd:ssangpieup": "\uFFB3",
+    "/hwd:ssangsios": "\uFFB6",
+    "/hwd:ssangtikeut": "\uFFA8",
+    "/hwd:thieuth": "\uFFBC",
+    "/hwd:tikeut": "\uFFA7",
+    "/hwd:u": "\uFFD3",
+    "/hwd:upwardsarrow": "\uFFEA",
+    "/hwd:wa": "\uFFCD",
+    "/hwd:wae": "\uFFCE",
+    "/hwd:we": "\uFFD5",
+    "/hwd:weo": "\uFFD4",
+    "/hwd:whitecircle": "\uFFEE",
+    "/hwd:wi": "\uFFD6",
+    "/hwd:ya": "\uFFC4",
+    "/hwd:yae": "\uFFC5",
+    "/hwd:ye": "\uFFCB",
+    "/hwd:yeo": "\uFFCA",
+    "/hwd:yi": "\uFFDB",
+    "/hwd:yo": "\uFFD2",
+    "/hwd:yu": "\uFFD7",
+    "/hyphen": "\u002D",
+    "/hyphenationpoint": "\u2027",
+    "/hyphenbullet": "\u2043",
+    "/hyphendbl": "\u2E40",
+    "/hyphendbloblique": "\u2E17",
+    "/hyphendieresis": "\u2E1A",
+    "/hypheninferior": "\uF6E5",
+    "/hyphenminus": "\u002D",
+    "/hyphenmonospace": "\uFF0D",
+    "/hyphensmall": "\uFE63",
+    "/hyphensoft": "\u00AD",
+    "/hyphensuperior": "\uF6E6",
+    "/hyphentwo": "\u2010",
+    "/hypodiastole": "\u2E12",
+    "/hysteresis": "\u238E",
+    "/hzfullwidth": "\u3390",
+    "/i": "\u0069",
+    "/i.superior": "\u2071",
+    "/iacute": "\u00ED",
+    "/iacyrillic": "\u044F",
+    "/iaepigraphic": "\uA7FE",
+    "/ibengali": "\u0987",
+    "/ibopomofo": "\u3127",
+    "/ibreve": "\u012D",
+    "/icaron": "\u01D0",
+    "/iceCream": "\u1F368",
+    "/iceHockeyStickAndPuck": "\u1F3D2",
+    "/iceskate": "\u26F8",
+    "/icircle": "\u24D8",
+    "/icirclekatakana": "\u32D1",
+    "/icircumflex": "\u00EE",
+    "/icyr": "\u0438",
+    "/icyrillic": "\u0456",
+    "/idblgrave": "\u0209",
+    "/idblstruckitalic": "\u2148",
+    "/ideographearthcircle": "\u328F",
+    "/ideographfirecircle": "\u328B",
+    "/ideographicallianceparen": "\u323F",
+    "/ideographiccallparen": "\u323A",
+    "/ideographiccentrecircle": "\u32A5",
+    "/ideographicclose": "\u3006",
+    "/ideographiccomma": "\u3001",
+    "/ideographiccommaleft": "\uFF64",
+    "/ideographiccongratulationparen": "\u3237",
+    "/ideographiccorrectcircle": "\u32A3",
+    "/ideographicdepartingtonemark": "\u302C",
+    "/ideographicearthparen": "\u322F",
+    "/ideographicenteringtonemark": "\u302D",
+    "/ideographicenterpriseparen": "\u323D",
+    "/ideographicexcellentcircle": "\u329D",
+    "/ideographicfestivalparen": "\u3240",
+    "/ideographicfinancialcircle": "\u3296",
+    "/ideographicfinancialparen": "\u3236",
+    "/ideographicfireparen": "\u322B",
+    "/ideographichalffillspace": "\u303F",
+    "/ideographichaveparen": "\u3232",
+    "/ideographichighcircle": "\u32A4",
+    "/ideographiciterationmark": "\u3005",
+    "/ideographiclaborcircle": "\u3298",
+    "/ideographiclaborparen": "\u3238",
+    "/ideographicleftcircle": "\u32A7",
+    "/ideographicleveltonemark": "\u302A",
+    "/ideographiclowcircle": "\u32A6",
+    "/ideographicmedicinecircle": "\u32A9",
+    "/ideographicmetalparen": "\u322E",
+    "/ideographicmoonparen": "\u322A",
+    "/ideographicnameparen": "\u3234",
+    "/ideographicperiod": "\u3002",
+    "/ideographicprintcircle": "\u329E",
+    "/ideographicreachparen": "\u3243",
+    "/ideographicrepresentparen": "\u3239",
+    "/ideographicresourceparen": "\u323E",
+    "/ideographicrightcircle": "\u32A8",
+    "/ideographicrisingtonemark": "\u302B",
+    "/ideographicsecretcircle": "\u3299",
+    "/ideographicselfparen": "\u3242",
+    "/ideographicsocietyparen": "\u3233",
+    "/ideographicspace": "\u3000",
+    "/ideographicspecialparen": "\u3235",
+    "/ideographicstockparen": "\u3231",
+    "/ideographicstudyparen": "\u323B",
+    "/ideographicsunparen": "\u3230",
+    "/ideographicsuperviseparen": "\u323C",
+    "/ideographictelegraphlinefeedseparatorsymbol": "\u3037",
+    "/ideographictelegraphsymbolforhoureight": "\u3360",
+    "/ideographictelegraphsymbolforhoureighteen": "\u336A",
+    "/ideographictelegraphsymbolforhoureleven": "\u3363",
+    "/ideographictelegraphsymbolforhourfifteen": "\u3367",
+    "/ideographictelegraphsymbolforhourfive": "\u335D",
+    "/ideographictelegraphsymbolforhourfour": "\u335C",
+    "/ideographictelegraphsymbolforhourfourteen": "\u3366",
+    "/ideographictelegraphsymbolforhournine": "\u3361",
+    "/ideographictelegraphsymbolforhournineteen": "\u336B",
+    "/ideographictelegraphsymbolforhourone": "\u3359",
+    "/ideographictelegraphsymbolforhourseven": "\u335F",
+    "/ideographictelegraphsymbolforhourseventeen": "\u3369",
+    "/ideographictelegraphsymbolforhoursix": "\u335E",
+    "/ideographictelegraphsymbolforhoursixteen": "\u3368",
+    "/ideographictelegraphsymbolforhourten": "\u3362",
+    "/ideographictelegraphsymbolforhourthirteen": "\u3365",
+    "/ideographictelegraphsymbolforhourthree": "\u335B",
+    "/ideographictelegraphsymbolforhourtwelve": "\u3364",
+    "/ideographictelegraphsymbolforhourtwenty": "\u336C",
+    "/ideographictelegraphsymbolforhourtwentyfour": "\u3370",
+    "/ideographictelegraphsymbolforhourtwentyone": "\u336D",
+    "/ideographictelegraphsymbolforhourtwentythree": "\u336F",
+    "/ideographictelegraphsymbolforhourtwentytwo": "\u336E",
+    "/ideographictelegraphsymbolforhourtwo": "\u335A",
+    "/ideographictelegraphsymbolforhourzero": "\u3358",
+    "/ideographicvariationindicator": "\u303E",
+    "/ideographicwaterparen": "\u322C",
+    "/ideographicwoodparen": "\u322D",
+    "/ideographiczero": "\u3007",
+    "/ideographmetalcircle": "\u328E",
+    "/ideographmooncircle": "\u328A",
+    "/ideographnamecircle": "\u3294",
+    "/ideographsuncircle": "\u3290",
+    "/ideographwatercircle": "\u328C",
+    "/ideographwoodcircle": "\u328D",
+    "/ideva": "\u0907",
+    "/idieresis": "\u00EF",
+    "/idieresisacute": "\u1E2F",
+    "/idieresiscyr": "\u04E5",
+    "/idieresiscyrillic": "\u04E5",
+    "/idotbelow": "\u1ECB",
+    "/idsquare": "\u1F194",
+    "/iebrevecyr": "\u04D7",
+    "/iebrevecyrillic": "\u04D7",
+    "/iecyr": "\u0435",
+    "/iecyrillic": "\u0435",
+    "/iegravecyr": "\u0450",
+    "/iepigraphicsideways": "\uA7F7",
+    "/ieungacirclekorean": "\u3275",
+    "/ieungaparenkorean": "\u3215",
+    "/ieungcirclekorean": "\u3267",
+    "/ieungkorean": "\u3147",
+    "/ieungparenkorean": "\u3207",
+    "/ieungucirclekorean": "\u327E",
+    "/igrave": "\u00EC",
+    "/igravecyr": "\u045D",
+    "/igravedbl": "\u0209",
+    "/igujarati": "\u0A87",
+    "/igurmukhi": "\u0A07",
+    "/ihiragana": "\u3044",
+    "/ihoi": "\u1EC9",
+    "/ihookabove": "\u1EC9",
+    "/iibengali": "\u0988",
+    "/iicyrillic": "\u0438",
+    "/iideva": "\u0908",
+    "/iigujarati": "\u0A88",
+    "/iigurmukhi": "\u0A08",
+    "/iimatragurmukhi": "\u0A40",
+    "/iinvertedbreve": "\u020B",
+    "/iishortcyrillic": "\u0439",
+    "/iivowelsignbengali": "\u09C0",
+    "/iivowelsigndeva": "\u0940",
+    "/iivowelsigngujarati": "\u0AC0",
+    "/ij": "\u0133",
+    "/ikatakana": "\u30A4",
+    "/ikatakanahalfwidth": "\uFF72",
+    "/ikawi": "\uA985",
+    "/ikorean": "\u3163",
+    "/ilde": "\u02DC",
+    "/iluy:hb": "\u05AC",
+    "/iluyhebrew": "\u05AC",
+    "/imacron": "\u012B",
+    "/imacroncyr": "\u04E3",
+    "/imacroncyrillic": "\u04E3",
+    "/image": "\u22B7",
+    "/imageorapproximatelyequal": "\u2253",
+    "/imatragurmukhi": "\u0A3F",
+    "/imonospace": "\uFF49",
+    "/imp": "\u1F47F",
+    "/inboxTray": "\u1F4E5",
+    "/incomingEnvelope": "\u1F4E8",
+    "/increaseFontSize": "\u1F5DA",
+    "/increment": "\u2206",
+    "/indianrupee": "\u20B9",
+    "/infinity": "\u221E",
+    "/information": "\u2139",
+    "/infullwidth": "\u33CC",
+    "/inhibitarabicformshaping": "\u206C",
+    "/inhibitsymmetricswapping": "\u206A",
+    "/iniarmenian": "\u056B",
+    "/iningusquare": "\u3304",
+    "/inmationDeskPerson": "\u1F481",
+    "/inputLatinCapitalLetters": "\u1F520",
+    "/inputLatinLetters": "\u1F524",
+    "/inputLatinSmallLetters": "\u1F521",
+    "/inputNumbers": "\u1F522",
+    "/inputS": "\u1F523",
+    "/insertion": "\u2380",
+    "/integral": "\u222B",
+    "/integralbottom": "\u2321",
+    "/integralbt": "\u2321",
+    "/integralclockwise": "\u2231",
+    "/integralcontour": "\u222E",
+    "/integralcontouranticlockwise": "\u2233",
+    "/integralcontourclockwise": "\u2232",
+    "/integraldbl": "\u222C",
+    "/integralex": "\uF8F5",
+    "/integralextension": "\u23AE",
+    "/integralsurface": "\u222F",
+    "/integraltop": "\u2320",
+    "/integraltp": "\u2320",
+    "/integraltpl": "\u222D",
+    "/integralvolume": "\u2230",
+    "/intercalate": "\u22BA",
+    "/interlinearanchor": "\uFFF9",
+    "/interlinearseparator": "\uFFFA",
+    "/interlinearterminator": "\uFFFB",
+    "/interlockedfemalemale": "\u26A4",
+    "/interrobang": "\u203D",
+    "/interrobanginverted": "\u2E18",
+    "/intersection": "\u2229",
+    "/intersectionarray": "\u22C2",
+    "/intersectiondbl": "\u22D2",
+    "/intisquare": "\u3305",
+    "/invbullet": "\u25D8",
+    "/invcircle": "\u25D9",
+    "/inverteddamma": "\u0657",
+    "/invertedfork": "\u2443",
+    "/invertedpentagram": "\u26E7",
+    "/invertedundertie": "\u2054",
+    "/invisibleplus": "\u2064",
+    "/invisibleseparator": "\u2063",
+    "/invisibletimes": "\u2062",
+    "/invsmileface": "\u263B",
+    "/iocyr": "\u0451",
+    "/iocyrillic": "\u0451",
+    "/iogonek": "\u012F",
+    "/iota": "\u03B9",
+    "/iotaacute": "\u1F77",
+    "/iotaadscript": "\u1FBE",
+    "/iotaasper": "\u1F31",
+    "/iotaasperacute": "\u1F35",
+    "/iotaaspergrave": "\u1F33",
+    "/iotaaspertilde": "\u1F37",
+    "/iotabreve": "\u1FD0",
+    "/iotadieresis": "\u03CA",
+    "/iotadieresisacute": "\u1FD3",
+    "/iotadieresisgrave": "\u1FD2",
+    "/iotadieresistilde": "\u1FD7",
+    "/iotadieresistonos": "\u0390",
+    "/iotafunc": "\u2373",
+    "/iotagrave": "\u1F76",
+    "/iotalatin": "\u0269",
+    "/iotalenis": "\u1F30",
+    "/iotalenisacute": "\u1F34",
+    "/iotalenisgrave": "\u1F32",
+    "/iotalenistilde": "\u1F36",
+    "/iotasub": "\u037A",
+    "/iotatilde": "\u1FD6",
+    "/iotatonos": "\u03AF",
+    "/iotaturned": "\u2129",
+    "/iotaunderlinefunc": "\u2378",
+    "/iotawithmacron": "\u1FD1",
+    "/ipa:Ismall": "\u026A",
+    "/ipa:alpha": "\u0251",
+    "/ipa:ereversed": "\u0258",
+    "/ipa:esh": "\u0283",
+    "/ipa:gamma": "\u0263",
+    "/ipa:glottalstop": "\u0294",
+    "/ipa:gscript": "\u0261",
+    "/ipa:iota": "\u0269",
+    "/ipa:phi": "\u0278",
+    "/ipa:rtail": "\u027D",
+    "/ipa:schwa": "\u0259",
+    "/ipa:upsilon": "\u028A",
+    "/iparen": "\u24A4",
+    "/iparenthesized": "\u24A4",
+    "/irigurmukhi": "\u0A72",
+    "/is": "\uA76D",
+    "/isen-isenpada": "\uA9DF",
+    "/ishortcyr": "\u0439",
+    "/ishortsharptailcyr": "\u048B",
+    "/ismallhiragana": "\u3043",
+    "/ismallkatakana": "\u30A3",
+    "/ismallkatakanahalfwidth": "\uFF68",
+    "/issharbengali": "\u09FA",
+    "/istroke": "\u0268",
+    "/isuperior": "\uF6ED",
+    "/itemideographiccircled": "\u32A0",
+    "/iterationhiragana": "\u309D",
+    "/iterationkatakana": "\u30FD",
+    "/itilde": "\u0129",
+    "/itildebelow": "\u1E2D",
+    "/iubopomofo": "\u3129",
+    "/iucyrillic": "\u044E",
+    "/iufullwidth": "\u337A",
+    "/iukrcyr": "\u0456",
+    "/ivowelsignbengali": "\u09BF",
+    "/ivowelsigndeva": "\u093F",
+    "/ivowelsigngujarati": "\u0ABF",
+    "/izakayaLantern": "\u1F3EE",
+    "/izhitsacyr": "\u0475",
+    "/izhitsacyrillic": "\u0475",
+    "/izhitsadblgravecyrillic": "\u0477",
+    "/izhitsagravedblcyr": "\u0477",
+    "/j": "\u006A",
+    "/j.inferior": "\u2C7C",
+    "/jaarmenian": "\u0571",
+    "/jabengali": "\u099C",
+    "/jackOLantern": "\u1F383",
+    "/jadeva": "\u091C",
+    "/jagujarati": "\u0A9C",
+    "/jagurmukhi": "\u0A1C",
+    "/jamahaprana": "\uA999",
+    "/januarytelegraph": "\u32C0",
+    "/japaneseBeginner": "\u1F530",
+    "/japaneseCastle": "\u1F3EF",
+    "/japaneseDolls": "\u1F38E",
+    "/japaneseGoblin": "\u1F47A",
+    "/japaneseOgre": "\u1F479",
+    "/japanesePostOffice": "\u1F3E3",
+    "/japanesebank": "\u26FB",
+    "/java:a": "\uA984",
+    "/java:ai": "\uA98D",
+    "/java:ba": "\uA9A7",
+    "/java:ca": "\uA995",
+    "/java:da": "\uA9A2",
+    "/java:dda": "\uA99D",
+    "/java:e": "\uA98C",
+    "/java:eight": "\uA9D8",
+    "/java:five": "\uA9D5",
+    "/java:four": "\uA9D4",
+    "/java:ga": "\uA992",
+    "/java:ha": "\uA9B2",
+    "/java:i": "\uA986",
+    "/java:ii": "\uA987",
+    "/java:ja": "\uA997",
+    "/java:ka": "\uA98F",
+    "/java:la": "\uA9AD",
+    "/java:ma": "\uA9A9",
+    "/java:na": "\uA9A4",
+    "/java:nga": "\uA994",
+    "/java:nine": "\uA9D9",
+    "/java:nya": "\uA99A",
+    "/java:o": "\uA98E",
+    "/java:one": "\uA9D1",
+    "/java:pa": "\uA9A5",
+    "/java:ra": "\uA9AB",
+    "/java:sa": "\uA9B1",
+    "/java:seven": "\uA9D7",
+    "/java:six": "\uA9D6",
+    "/java:ta": "\uA9A0",
+    "/java:three": "\uA9D3",
+    "/java:tta": "\uA99B",
+    "/java:two": "\uA9D2",
+    "/java:u": "\uA988",
+    "/java:wa": "\uA9AE",
+    "/java:ya": "\uA9AA",
+    "/java:zero": "\uA9D0",
+    "/jbopomofo": "\u3110",
+    "/jcaron": "\u01F0",
+    "/jcircle": "\u24D9",
+    "/jcircumflex": "\u0135",
+    "/jcrossedtail": "\u029D",
+    "/jdblstruckitalic": "\u2149",
+    "/jdotlessstroke": "\u025F",
+    "/jeans": "\u1F456",
+    "/jecyr": "\u0458",
+    "/jecyrillic": "\u0458",
+    "/jeem": "\u062C",
+    "/jeem.fina": "\uFE9E",
+    "/jeem.init": "\uFE9F",
+    "/jeem.init_alefmaksura.fina": "\uFD01",
+    "/jeem.init_hah.fina": "\uFC15",
+    "/jeem.init_hah.medi": "\uFCA7",
+    "/jeem.init_meem.fina": "\uFC16",
+    "/jeem.init_meem.medi": "\uFCA8",
+    "/jeem.init_meem.medi_hah.medi": "\uFD59",
+    "/jeem.init_yeh.fina": "\uFD02",
+    "/jeem.isol": "\uFE9D",
+    "/jeem.medi": "\uFEA0",
+    "/jeem.medi_alefmaksura.fina": "\uFD1D",
+    "/jeem.medi_hah.medi_alefmaksura.fina": "\uFDA6",
+    "/jeem.medi_hah.medi_yeh.fina": "\uFDBE",
+    "/jeem.medi_meem.medi_alefmaksura.fina": "\uFDA7",
+    "/jeem.medi_meem.medi_hah.fina": "\uFD58",
+    "/jeem.medi_meem.medi_yeh.fina": "\uFDA5",
+    "/jeem.medi_yeh.fina": "\uFD1E",
+    "/jeemabove": "\u06DA",
+    "/jeemarabic": "\u062C",
+    "/jeemfinalarabic": "\uFE9E",
+    "/jeeminitialarabic": "\uFE9F",
+    "/jeemmedialarabic": "\uFEA0",
+    "/jeh": "\u0698",
+    "/jeh.fina": "\uFB8B",
+    "/jeh.isol": "\uFB8A",
+    "/jeharabic": "\u0698",
+    "/jehfinalarabic": "\uFB8B",
+    "/jhabengali": "\u099D",
+    "/jhadeva": "\u091D",
+    "/jhagujarati": "\u0A9D",
+    "/jhagurmukhi": "\u0A1D",
+    "/jheharmenian": "\u057B",
+    "/jis": "\u3004",
+    "/jiterup": "\u2643",
+    "/jmonospace": "\uFF4A",
+    "/jotdiaeresisfunc": "\u2364",
+    "/jotunderlinefunc": "\u235B",
+    "/joystick": "\u1F579",
+    "/jparen": "\u24A5",
+    "/jparenthesized": "\u24A5",
+    "/jstroke": "\u0249",
+    "/jsuperior": "\u02B2",
+    "/jsupmod": "\u02B2",
+    "/jueuicircle": "\u327D",
+    "/julytelegraph": "\u32C6",
+    "/junetelegraph": "\u32C5",
+    "/juno": "\u26B5",
+    "/k": "\u006B",
+    "/k.inferior": "\u2096",
+    "/kaaba": "\u1F54B",
+    "/kaaleutcyr": "\u051F",
+    "/kabashkcyr": "\u04A1",
+    "/kabashkircyrillic": "\u04A1",
+    "/kabengali": "\u0995",
+    "/kacirclekatakana": "\u32D5",
+    "/kacute": "\u1E31",
+    "/kacyr": "\u043A",
+    "/kacyrillic": "\u043A",
+    "/kadescendercyrillic": "\u049B",
+    "/kadeva": "\u0915",
+    "/kaf": "\u05DB",
+    "/kaf.fina": "\uFEDA",
+    "/kaf.init": "\uFEDB",
+    "/kaf.init_alef.fina": "\uFC37",
+    "/kaf.init_alefmaksura.fina": "\uFC3D",
+    "/kaf.init_hah.fina": "\uFC39",
+    "/kaf.init_hah.medi": "\uFCC5",
+    "/kaf.init_jeem.fina": "\uFC38",
+    "/kaf.init_jeem.medi": "\uFCC4",
+    "/kaf.init_khah.fina": "\uFC3A",
+    "/kaf.init_khah.medi": "\uFCC6",
+    "/kaf.init_lam.fina": "\uFC3B",
+    "/kaf.init_lam.medi": "\uFCC7",
+    "/kaf.init_meem.fina": "\uFC3C",
+    "/kaf.init_meem.medi": "\uFCC8",
+    "/kaf.init_meem.medi_meem.medi": "\uFDC3",
+    "/kaf.init_yeh.fina": "\uFC3E",
+    "/kaf.isol": "\uFED9",
+    "/kaf.medi": "\uFEDC",
+    "/kaf.medi_alef.fina": "\uFC80",
+    "/kaf.medi_alefmaksura.fina": "\uFC83",
+    "/kaf.medi_lam.fina": "\uFC81",
+    "/kaf.medi_lam.medi": "\uFCEB",
+    "/kaf.medi_meem.fina": "\uFC82",
+    "/kaf.medi_meem.medi": "\uFCEC",
+    "/kaf.medi_meem.medi_meem.fina": "\uFDBB",
+    "/kaf.medi_meem.medi_yeh.fina": "\uFDB7",
+    "/kaf.medi_yeh.fina": "\uFC84",
+    "/kaf:hb": "\u05DB",
+    "/kafTwoDotsAbove": "\u077F",
+    "/kafarabic": "\u0643",
+    "/kafdagesh": "\uFB3B",
+    "/kafdageshhebrew": "\uFB3B",
+    "/kafdotabove": "\u06AC",
+    "/kaffinalarabic": "\uFEDA",
+    "/kafhebrew": "\u05DB",
+    "/kafinitialarabic": "\uFEDB",
+    "/kafmedialarabic": "\uFEDC",
+    "/kafrafehebrew": "\uFB4D",
+    "/kafring": "\u06AB",
+    "/kafswash": "\u06AA",
+    "/kafthreedotsbelow": "\u06AE",
+    "/kafullwidth": "\u3384",
+    "/kafwide:hb": "\uFB24",
+    "/kafwithdagesh:hb": "\uFB3B",
+    "/kafwithrafe:hb": "\uFB4D",
+    "/kagujarati": "\u0A95",
+    "/kagurmukhi": "\u0A15",
+    "/kahiragana": "\u304B",
+    "/kahookcyr": "\u04C4",
+    "/kahookcyrillic": "\u04C4",
+    "/kairisquare": "\u330B",
+    "/kaisymbol": "\u03D7",
+    "/kakatakana": "\u30AB",
+    "/kakatakanahalfwidth": "\uFF76",
+    "/kamurda": "\uA991",
+    "/kappa": "\u03BA",
+    "/kappa.math": "\u03F0",
+    "/kappasymbolgreek": "\u03F0",
+    "/kapyeounmieumkorean": "\u3171",
+    "/kapyeounphieuphkorean": "\u3184",
+    "/kapyeounpieupkorean": "\u3178",
+    "/kapyeounssangpieupkorean": "\u3179",
+    "/karattosquare": "\u330C",
+    "/karoriisquare": "\u330D",
+    "/kasasak": "\uA990",
+    "/kashida": "\u0640",
+    "/kashidaFina": "\uFE73",
+    "/kashidaautoarabic": "\u0640",
+    "/kashidaautonosidebearingarabic": "\u0640",
+    "/kashmiriyeh": "\u0620",
+    "/kasmallkatakana": "\u30F5",
+    "/kasquare": "\u3384",
+    "/kasra": "\u0650",
+    "/kasraIsol": "\uFE7A",
+    "/kasraMedi": "\uFE7B",
+    "/kasraarabic": "\u0650",
+    "/kasrasmall": "\u061A",
+    "/kasratan": "\u064D",
+    "/kasratanIsol": "\uFE74",
+    "/kasratanarabic": "\u064D",
+    "/kastrokecyr": "\u049F",
+    "/kastrokecyrillic": "\u049F",
+    "/kata:a": "\u30A2",
+    "/kata:asmall": "\u30A1",
+    "/kata:ba": "\u30D0",
+    "/kata:be": "\u30D9",
+    "/kata:bi": "\u30D3",
+    "/kata:bo": "\u30DC",
+    "/kata:bu": "\u30D6",
+    "/kata:da": "\u30C0",
+    "/kata:de": "\u30C7",
+    "/kata:di": "\u30C2",
+    "/kata:digraphkoto": "\u30FF",
+    "/kata:do": "\u30C9",
+    "/kata:doublehyphenkana": "\u30A0",
+    "/kata:du": "\u30C5",
+    "/kata:e": "\u30A8",
+    "/kata:esmall": "\u30A7",
+    "/kata:ga": "\u30AC",
+    "/kata:ge": "\u30B2",
+    "/kata:gi": "\u30AE",
+    "/kata:go": "\u30B4",
+    "/kata:gu": "\u30B0",
+    "/kata:ha": "\u30CF",
+    "/kata:he": "\u30D8",
+    "/kata:hi": "\u30D2",
+    "/kata:ho": "\u30DB",
+    "/kata:hu": "\u30D5",
+    "/kata:i": "\u30A4",
+    "/kata:ismall": "\u30A3",
+    "/kata:iteration": "\u30FD",
+    "/kata:ka": "\u30AB",
+    "/kata:kasmall": "\u30F5",
+    "/kata:ke": "\u30B1",
+    "/kata:kesmall": "\u30F6",
+    "/kata:ki": "\u30AD",
+    "/kata:ko": "\u30B3",
+    "/kata:ku": "\u30AF",
+    "/kata:ma": "\u30DE",
+    "/kata:me": "\u30E1",
+    "/kata:mi": "\u30DF",
+    "/kata:middledot": "\u30FB",
+    "/kata:mo": "\u30E2",
+    "/kata:mu": "\u30E0",
+    "/kata:n": "\u30F3",
+    "/kata:na": "\u30CA",
+    "/kata:ne": "\u30CD",
+    "/kata:ni": "\u30CB",
+    "/kata:no": "\u30CE",
+    "/kata:nu": "\u30CC",
+    "/kata:o": "\u30AA",
+    "/kata:osmall": "\u30A9",
+    "/kata:pa": "\u30D1",
+    "/kata:pe": "\u30DA",
+    "/kata:pi": "\u30D4",
+    "/kata:po": "\u30DD",
+    "/kata:prolongedkana": "\u30FC",
+    "/kata:pu": "\u30D7",
+    "/kata:ra": "\u30E9",
+    "/kata:re": "\u30EC",
+    "/kata:ri": "\u30EA",
+    "/kata:ro": "\u30ED",
+    "/kata:ru": "\u30EB",
+    "/kata:sa": "\u30B5",
+    "/kata:se": "\u30BB",
+    "/kata:si": "\u30B7",
+    "/kata:so": "\u30BD",
+    "/kata:su": "\u30B9",
+    "/kata:ta": "\u30BF",
+    "/kata:te": "\u30C6",
+    "/kata:ti": "\u30C1",
+    "/kata:to": "\u30C8",
+    "/kata:tu": "\u30C4",
+    "/kata:tusmall": "\u30C3",
+    "/kata:u": "\u30A6",
+    "/kata:usmall": "\u30A5",
+    "/kata:va": "\u30F7",
+    "/kata:ve": "\u30F9",
+    "/kata:vi": "\u30F8",
+    "/kata:vo": "\u30FA",
+    "/kata:voicediteration": "\u30FE",
+    "/kata:vu": "\u30F4",
+    "/kata:wa": "\u30EF",
+    "/kata:wasmall": "\u30EE",
+    "/kata:we": "\u30F1",
+    "/kata:wi": "\u30F0",
+    "/kata:wo": "\u30F2",
+    "/kata:ya": "\u30E4",
+    "/kata:yasmall": "\u30E3",
+    "/kata:yo": "\u30E8",
+    "/kata:yosmall": "\u30E7",
+    "/kata:yu": "\u30E6",
+    "/kata:yusmall": "\u30E5",
+    "/kata:za": "\u30B6",
+    "/kata:ze": "\u30BC",
+    "/kata:zi": "\u30B8",
+    "/kata:zo": "\u30BE",
+    "/kata:zu": "\u30BA",
+    "/katahiraprolongmarkhalfwidth": "\uFF70",
+    "/katailcyr": "\u049B",
+    "/kaverticalstrokecyr": "\u049D",
+    "/kaverticalstrokecyrillic": "\u049D",
+    "/kavykainvertedlow": "\u2E45",
+    "/kavykalow": "\u2E47",
+    "/kavykawithdotlow": "\u2E48",
+    "/kavykawithkavykaaboveinvertedlow": "\u2E46",
+    "/kbfullwidth": "\u3385",
+    "/kbopomofo": "\u310E",
+    "/kcalfullwidth": "\u3389",
+    "/kcalsquare": "\u3389",
+    "/kcaron": "\u01E9",
+    "/kcedilla": "\u0137",
+    "/kcircle": "\u24DA",
+    "/kcommaaccent": "\u0137",
+    "/kdescender": "\u2C6A",
+    "/kdiagonalstroke": "\uA743",
+    "/kdotbelow": "\u1E33",
+    "/kecirclekatakana": "\u32D8",
+    "/keesusquare": "\u331C",
+    "/keharmenian": "\u0584",
+    "/keheh": "\u06A9",
+    "/keheh.fina": "\uFB8F",
+    "/keheh.init": "\uFB90",
+    "/keheh.isol": "\uFB8E",
+    "/keheh.medi": "\uFB91",
+    "/kehehDotAbove": "\u0762",
+    "/kehehThreeDotsAbove": "\u0763",
+    "/kehehThreeDotsUpBelow": "\u0764",
+    "/kehehthreedotsbelow": "\u063C",
+    "/kehehtwodotsabove": "\u063B",
+    "/kehiragana": "\u3051",
+    "/kekatakana": "\u30B1",
+    "/kekatakanahalfwidth": "\uFF79",
+    "/kelvin": "\u212A",
+    "/kenarmenian": "\u056F",
+    "/keretconsonant": "\uA9BD",
+    "/kesmallkatakana": "\u30F6",
+    "/key": "\u1F511",
+    "/keyboardAndMouse": "\u1F5A6",
+    "/keycapTen": "\u1F51F",
+    "/kgfullwidth": "\u338F",
+    "/kgreenlandic": "\u0138",
+    "/khabengali": "\u0996",
+    "/khacyrillic": "\u0445",
+    "/khadeva": "\u0916",
+    "/khagujarati": "\u0A96",
+    "/khagurmukhi": "\u0A16",
+    "/khah": "\u062E",
+    "/khah.fina": "\uFEA6",
+    "/khah.init": "\uFEA7",
+    "/khah.init_alefmaksura.fina": "\uFD03",
+    "/khah.init_hah.fina": "\uFC1A",
+    "/khah.init_jeem.fina": "\uFC19",
+    "/khah.init_jeem.medi": "\uFCAB",
+    "/khah.init_meem.fina": "\uFC1B",
+    "/khah.init_meem.medi": "\uFCAC",
+    "/khah.init_yeh.fina": "\uFD04",
+    "/khah.isol": "\uFEA5",
+    "/khah.medi": "\uFEA8",
+    "/khah.medi_alefmaksura.fina": "\uFD1F",
+    "/khah.medi_yeh.fina": "\uFD20",
+    "/khaharabic": "\u062E",
+    "/khahfinalarabic": "\uFEA6",
+    "/khahinitialarabic": "\uFEA7",
+    "/khahmedialarabic": "\uFEA8",
+    "/kheicoptic": "\u03E7",
+    "/khhadeva": "\u0959",
+    "/khhagurmukhi": "\u0A59",
+    "/khieukhacirclekorean": "\u3278",
+    "/khieukhaparenkorean": "\u3218",
+    "/khieukhcirclekorean": "\u326A",
+    "/khieukhkorean": "\u314B",
+    "/khieukhparenkorean": "\u320A",
+    "/khokhaithai": "\u0E02",
+    "/khokhonthai": "\u0E05",
+    "/khokhuatthai": "\u0E03",
+    "/khokhwaithai": "\u0E04",
+    "/khomutthai": "\u0E5B",
+    "/khook": "\u0199",
+    "/khorakhangthai": "\u0E06",
+    "/khzfullwidth": "\u3391",
+    "/khzsquare": "\u3391",
+    "/kicirclekatakana": "\u32D6",
+    "/kihiragana": "\u304D",
+    "/kikatakana": "\u30AD",
+    "/kikatakanahalfwidth": "\uFF77",
+    "/kimono": "\u1F458",
+    "/kindergartenideographiccircled": "\u3245",
+    "/kingblack": "\u265A",
+    "/kingwhite": "\u2654",
+    "/kip": "\u20AD",
+    "/kiroguramusquare": "\u3315",
+    "/kiromeetorusquare": "\u3316",
+    "/kirosquare": "\u3314",
+    "/kirowattosquare": "\u3317",
+    "/kiss": "\u1F48F",
+    "/kissMark": "\u1F48B",
+    "/kissingCatFaceWithClosedEyes": "\u1F63D",
+    "/kissingFace": "\u1F617",
+    "/kissingFaceWithClosedEyes": "\u1F61A",
+    "/kissingFaceWithSmilingEyes": "\u1F619",
+    "/kiyeokacirclekorean": "\u326E",
+    "/kiyeokaparenkorean": "\u320E",
+    "/kiyeokcirclekorean": "\u3260",
+    "/kiyeokkorean": "\u3131",
+    "/kiyeokparenkorean": "\u3200",
+    "/kiyeoksioskorean": "\u3133",
+    "/kjecyr": "\u045C",
+    "/kjecyrillic": "\u045C",
+    "/kkfullwidth": "\u33CD",
+    "/klfullwidth": "\u3398",
+    "/klinebelow": "\u1E35",
+    "/klsquare": "\u3398",
+    "/km2fullwidth": "\u33A2",
+    "/km3fullwidth": "\u33A6",
+    "/kmcapitalfullwidth": "\u33CE",
+    "/kmcubedsquare": "\u33A6",
+    "/kmfullwidth": "\u339E",
+    "/kmonospace": "\uFF4B",
+    "/kmsquaredsquare": "\u33A2",
+    "/knda:a": "\u0C85",
+    "/knda:aa": "\u0C86",
+    "/knda:aasign": "\u0CBE",
+    "/knda:ai": "\u0C90",
+    "/knda:ailength": "\u0CD6",
+    "/knda:aisign": "\u0CC8",
+    "/knda:anusvara": "\u0C82",
+    "/knda:au": "\u0C94",
+    "/knda:ausign": "\u0CCC",
+    "/knda:avagraha": "\u0CBD",
+    "/knda:ba": "\u0CAC",
+    "/knda:bha": "\u0CAD",
+    "/knda:ca": "\u0C9A",
+    "/knda:cha": "\u0C9B",
+    "/knda:da": "\u0CA6",
+    "/knda:dda": "\u0CA1",
+    "/knda:ddha": "\u0CA2",
+    "/knda:dha": "\u0CA7",
+    "/knda:e": "\u0C8E",
+    "/knda:ee": "\u0C8F",
+    "/knda:eesign": "\u0CC7",
+    "/knda:eight": "\u0CEE",
+    "/knda:esign": "\u0CC6",
+    "/knda:fa": "\u0CDE",
+    "/knda:five": "\u0CEB",
+    "/knda:four": "\u0CEA",
+    "/knda:ga": "\u0C97",
+    "/knda:gha": "\u0C98",
+    "/knda:ha": "\u0CB9",
+    "/knda:i": "\u0C87",
+    "/knda:ii": "\u0C88",
+    "/knda:iisign": "\u0CC0",
+    "/knda:isign": "\u0CBF",
+    "/knda:ja": "\u0C9C",
+    "/knda:jha": "\u0C9D",
+    "/knda:jihvamuliya": "\u0CF1",
+    "/knda:ka": "\u0C95",
+    "/knda:kha": "\u0C96",
+    "/knda:la": "\u0CB2",
+    "/knda:length": "\u0CD5",
+    "/knda:lla": "\u0CB3",
+    "/knda:llvocal": "\u0CE1",
+    "/knda:llvocalsign": "\u0CE3",
+    "/knda:lvocal": "\u0C8C",
+    "/knda:lvocalsign": "\u0CE2",
+    "/knda:ma": "\u0CAE",
+    "/knda:na": "\u0CA8",
+    "/knda:nga": "\u0C99",
+    "/knda:nine": "\u0CEF",
+    "/knda:nna": "\u0CA3",
+    "/knda:nukta": "\u0CBC",
+    "/knda:nya": "\u0C9E",
+    "/knda:o": "\u0C92",
+    "/knda:one": "\u0CE7",
+    "/knda:oo": "\u0C93",
+    "/knda:oosign": "\u0CCB",
+    "/knda:osign": "\u0CCA",
+    "/knda:pa": "\u0CAA",
+    "/knda:pha": "\u0CAB",
+    "/knda:ra": "\u0CB0",
+    "/knda:rra": "\u0CB1",
+    "/knda:rrvocal": "\u0CE0",
+    "/knda:rrvocalsign": "\u0CC4",
+    "/knda:rvocal": "\u0C8B",
+    "/knda:rvocalsign": "\u0CC3",
+    "/knda:sa": "\u0CB8",
+    "/knda:seven": "\u0CED",
+    "/knda:sha": "\u0CB6",
+    "/knda:signcandrabindu": "\u0C81",
+    "/knda:signspacingcandrabindu": "\u0C80",
+    "/knda:six": "\u0CEC",
+    "/knda:ssa": "\u0CB7",
+    "/knda:ta": "\u0CA4",
+    "/knda:tha": "\u0CA5",
+    "/knda:three": "\u0CE9",
+    "/knda:tta": "\u0C9F",
+    "/knda:ttha": "\u0CA0",
+    "/knda:two": "\u0CE8",
+    "/knda:u": "\u0C89",
+    "/knda:upadhmaniya": "\u0CF2",
+    "/knda:usign": "\u0CC1",
+    "/knda:uu": "\u0C8A",
+    "/knda:uusign": "\u0CC2",
+    "/knda:va": "\u0CB5",
+    "/knda:virama": "\u0CCD",
+    "/knda:visarga": "\u0C83",
+    "/knda:ya": "\u0CAF",
+    "/knda:zero": "\u0CE6",
+    "/knightblack": "\u265E",
+    "/knightwhite": "\u2658",
+    "/ko:a": "\u314F",
+    "/ko:ae": "\u3150",
+    "/ko:aejungseong": "\u1162",
+    "/ko:aeujungseong": "\u11A3",
+    "/ko:ajungseong": "\u1161",
+    "/ko:aojungseong": "\u1176",
+    "/ko:araea": "\u318D",
+    "/ko:araeae": "\u318E",
+    "/ko:araeaeojungseong": "\u119F",
+    "/ko:araeaijungseong": "\u11A1",
+    "/ko:araeajungseong": "\u119E",
+    "/ko:araeaujungseong": "\u11A0",
+    "/ko:aujungseong": "\u1177",
+    "/ko:ceongchieumchieuchchoseong": "\u1155",
+    "/ko:ceongchieumcieucchoseong": "\u1150",
+    "/ko:ceongchieumsioschoseong": "\u113E",
+    "/ko:ceongchieumssangcieucchoseong": "\u1151",
+    "/ko:ceongchieumssangsioschoseong": "\u113F",
+    "/ko:chieuch": "\u314A",
+    "/ko:chieuchchoseong": "\u110E",
+    "/ko:chieuchhieuhchoseong": "\u1153",
+    "/ko:chieuchjongseong": "\u11BE",
+    "/ko:chieuchkhieukhchoseong": "\u1152",
+    "/ko:chitueumchieuchchoseong": "\u1154",
+    "/ko:chitueumcieucchoseong": "\u114E",
+    "/ko:chitueumsioschoseong": "\u113C",
+    "/ko:chitueumssangcieucchoseong": "\u114F",
+    "/ko:chitueumssangsioschoseong": "\u113D",
+    "/ko:cieuc": "\u3148",
+    "/ko:cieucchoseong": "\u110C",
+    "/ko:cieucieungchoseong": "\u114D",
+    "/ko:cieucjongseong": "\u11BD",
+    "/ko:e": "\u3154",
+    "/ko:ejungseong": "\u1166",
+    "/ko:eo": "\u3153",
+    "/ko:eo_eujungseong": "\u117C",
+    "/ko:eojungseong": "\u1165",
+    "/ko:eoojungseong": "\u117A",
+    "/ko:eoujungseong": "\u117B",
+    "/ko:eu": "\u3161",
+    "/ko:eueujungseong": "\u1196",
+    "/ko:eujungseong": "\u1173",
+    "/ko:euujungseong": "\u1195",
+    "/ko:filler": "\u3164",
+    "/ko:fillerchoseong": "\u115F",
+    "/ko:fillerjungseong": "\u1160",
+    "/ko:hieuh": "\u314E",
+    "/ko:hieuhchoseong": "\u1112",
+    "/ko:hieuhjongseong": "\u11C2",
+    "/ko:hieuhmieumjongseong": "\u11F7",
+    "/ko:hieuhnieunjongseong": "\u11F5",
+    "/ko:hieuhpieupjongseong": "\u11F8",
+    "/ko:hieuhrieuljongseong": "\u11F6",
+    "/ko:i": "\u3163",
+    "/ko:iajungseong": "\u1198",
+    "/ko:iaraeajungseong": "\u119D",
+    "/ko:ieujungseong": "\u119C",
+    "/ko:ieung": "\u3147",
+    "/ko:ieungchieuchchoseong": "\u1149",
+    "/ko:ieungchoseong": "\u110B",
+    "/ko:ieungcieucchoseong": "\u1148",
+    "/ko:ieungjongseong": "\u11BC",
+    "/ko:ieungkhieukhjongseong": "\u11EF",
+    "/ko:ieungkiyeokchoseong": "\u1141",
+    "/ko:ieungkiyeokjongseong": "\u11EC",
+    "/ko:ieungmieumchoseong": "\u1143",
+    "/ko:ieungpansioschoseong": "\u1146",
+    "/ko:ieungphieuphchoseong": "\u114B",
+    "/ko:ieungpieupchoseong": "\u1144",
+    "/ko:ieungsioschoseong": "\u1145",
+    "/ko:ieungssangkiyeokjongseong": "\u11ED",
+    "/ko:ieungthieuthchoseong": "\u114A",
+    "/ko:ieungtikeutchoseong": "\u1142",
+    "/ko:ijungseong": "\u1175",
+    "/ko:iojungseong": "\u119A",
+    "/ko:iujungseong": "\u119B",
+    "/ko:iyajungseong": "\u1199",
+    "/ko:kapyeounmieum": "\u3171",
+    "/ko:kapyeounmieumchoseong": "\u111D",
+    "/ko:kapyeounmieumjongseong": "\u11E2",
+    "/ko:kapyeounphieuph": "\u3184",
+    "/ko:kapyeounphieuphchoseong": "\u1157",
+    "/ko:kapyeounphieuphjongseong": "\u11F4",
+    "/ko:kapyeounpieup": "\u3178",
+    "/ko:kapyeounpieupchoseong": "\u112B",
+    "/ko:kapyeounpieupjongseong": "\u11E6",
+    "/ko:kapyeounrieulchoseong": "\u111B",
+    "/ko:kapyeounssangpieup": "\u3179",
+    "/ko:kapyeounssangpieupchoseong": "\u112C",
+    "/ko:khieukh": "\u314B",
+    "/ko:khieukhchoseong": "\u110F",
+    "/ko:khieukhjongseong": "\u11BF",
+    "/ko:kiyeok": "\u3131",
+    "/ko:kiyeokchieuchjongseong": "\u11FC",
+    "/ko:kiyeokchoseong": "\u1100",
+    "/ko:kiyeokhieuhjongseong": "\u11FE",
+    "/ko:kiyeokjongseong": "\u11A8",
+    "/ko:kiyeokkhieukhjongseong": "\u11FD",
+    "/ko:kiyeoknieunjongseong": "\u11FA",
+    "/ko:kiyeokpieupjongseong": "\u11FB",
+    "/ko:kiyeokrieuljongseong": "\u11C3",
+    "/ko:kiyeoksios": "\u3133",
+    "/ko:kiyeoksiosjongseong": "\u11AA",
+    "/ko:kiyeoksioskiyeokjongseong": "\u11C4",
+    "/ko:kiyeoktikeutchoseong": "\u115A",
+    "/ko:mieum": "\u3141",
+    "/ko:mieumchieuchjongseong": "\u11E0",
+    "/ko:mieumchoseong": "\u1106",
+    "/ko:mieumhieuhjongseong": "\u11E1",
+    "/ko:mieumjongseong": "\u11B7",
+    "/ko:mieumkiyeokjongseong": "\u11DA",
+    "/ko:mieumpansios": "\u3170",
+    "/ko:mieumpansiosjongseong": "\u11DF",
+    "/ko:mieumpieup": "\u316E",
+    "/ko:mieumpieupchoseong": "\u111C",
+    "/ko:mieumpieupjongseong": "\u11DC",
+    "/ko:mieumrieuljongseong": "\u11DB",
+    "/ko:mieumsios": "\u316F",
+    "/ko:mieumsiosjongseong": "\u11DD",
+    "/ko:mieumssangsiosjongseong": "\u11DE",
+    "/ko:nieun": "\u3134",
+    "/ko:nieunchoseong": "\u1102",
+    "/ko:nieuncieuc": "\u3135",
+    "/ko:nieuncieucchoseong": "\u115C",
+    "/ko:nieuncieucjongseong": "\u11AC",
+    "/ko:nieunhieuh": "\u3136",
+    "/ko:nieunhieuhchoseong": "\u115D",
+    "/ko:nieunhieuhjongseong": "\u11AD",
+    "/ko:nieunjongseong": "\u11AB",
+    "/ko:nieunkiyeokchoseong": "\u1113",
+    "/ko:nieunkiyeokjongseong": "\u11C5",
+    "/ko:nieunpansios": "\u3168",
+    "/ko:nieunpansiosjongseong": "\u11C8",
+    "/ko:nieunpieupchoseong": "\u1116",
+    "/ko:nieunsios": "\u3167",
+    "/ko:nieunsioschoseong": "\u115B",
+    "/ko:nieunsiosjongseong": "\u11C7",
+    "/ko:nieunthieuthjongseong": "\u11C9",
+    "/ko:nieuntikeut": "\u3166",
+    "/ko:nieuntikeutchoseong": "\u1115",
+    "/ko:nieuntikeutjongseong": "\u11C6",
+    "/ko:o": "\u3157",
+    "/ko:o_ejungseong": "\u1180",
+    "/ko:o_eojungseong": "\u117F",
+    "/ko:oe": "\u315A",
+    "/ko:oejungseong": "\u116C",
+    "/ko:ojungseong": "\u1169",
+    "/ko:oojungseong": "\u1182",
+    "/ko:oujungseong": "\u1183",
+    "/ko:oyaejungseong": "\u11A7",
+    "/ko:oyajungseong": "\u11A6",
+    "/ko:oyejungseong": "\u1181",
+    "/ko:pansios": "\u317F",
+    "/ko:pansioschoseong": "\u1140",
+    "/ko:pansiosjongseong": "\u11EB",
+    "/ko:phieuph": "\u314D",
+    "/ko:phieuphchoseong": "\u1111",
+    "/ko:phieuphjongseong": "\u11C1",
+    "/ko:phieuphpieupchoseong": "\u1156",
+    "/ko:phieuphpieupjongseong": "\u11F3",
+    "/ko:pieup": "\u3142",
+    "/ko:pieupchieuchchoseong": "\u1128",
+    "/ko:pieupchoseong": "\u1107",
+    "/ko:pieupcieuc": "\u3176",
+    "/ko:pieupcieucchoseong": "\u1127",
+    "/ko:pieuphieuhjongseong": "\u11E5",
+    "/ko:pieupjongseong": "\u11B8",
+    "/ko:pieupkiyeok": "\u3172",
+    "/ko:pieupkiyeokchoseong": "\u111E",
+    "/ko:pieupnieunchoseong": "\u111F",
+    "/ko:pieupphieuphchoseong": "\u112A",
+    "/ko:pieupphieuphjongseong": "\u11E4",
+    "/ko:pieuprieuljongseong": "\u11E3",
+    "/ko:pieupsios": "\u3144",
+    "/ko:pieupsioschoseong": "\u1121",
+    "/ko:pieupsioscieucchoseong": "\u1126",
+    "/ko:pieupsiosjongseong": "\u11B9",
+    "/ko:pieupsioskiyeok": "\u3174",
+    "/ko:pieupsioskiyeokchoseong": "\u1122",
+    "/ko:pieupsiospieupchoseong": "\u1124",
+    "/ko:pieupsiostikeut": "\u3175",
+    "/ko:pieupsiostikeutchoseong": "\u1123",
+    "/ko:pieupssangsioschoseong": "\u1125",
+    "/ko:pieupthieuth": "\u3177",
+    "/ko:pieupthieuthchoseong": "\u1129",
+    "/ko:pieuptikeut": "\u3173",
+    "/ko:pieuptikeutchoseong": "\u1120",
+    "/ko:rieul": "\u3139",
+    "/ko:rieulchoseong": "\u1105",
+    "/ko:rieulhieuh": "\u3140",
+    "/ko:rieulhieuhchoseong": "\u111A",
+    "/ko:rieulhieuhjongseong": "\u11B6",
+    "/ko:rieuljongseong": "\u11AF",
+    "/ko:rieulkapyeounpieupjongseong": "\u11D5",
+    "/ko:rieulkhieukhjongseong": "\u11D8",
+    "/ko:rieulkiyeok": "\u313A",
+    "/ko:rieulkiyeokjongseong": "\u11B0",
+    "/ko:rieulkiyeoksios": "\u3169",
+    "/ko:rieulkiyeoksiosjongseong": "\u11CC",
+    "/ko:rieulmieum": "\u313B",
+    "/ko:rieulmieumjongseong": "\u11B1",
+    "/ko:rieulmieumkiyeokjongseong": "\u11D1",
+    "/ko:rieulmieumsiosjongseong": "\u11D2",
+    "/ko:rieulnieunchoseong": "\u1118",
+    "/ko:rieulnieunjongseong": "\u11CD",
+    "/ko:rieulpansios": "\u316C",
+    "/ko:rieulpansiosjongseong": "\u11D7",
+    "/ko:rieulphieuph": "\u313F",
+    "/ko:rieulphieuphjongseong": "\u11B5",
+    "/ko:rieulpieup": "\u313C",
+    "/ko:rieulpieuphieuhjongseong": "\u11D4",
+    "/ko:rieulpieupjongseong": "\u11B2",
+    "/ko:rieulpieupsios": "\u316B",
+    "/ko:rieulpieupsiosjongseong": "\u11D3",
+    "/ko:rieulsios": "\u313D",
+    "/ko:rieulsiosjongseong": "\u11B3",
+    "/ko:rieulssangsiosjongseong": "\u11D6",
+    "/ko:rieulthieuth": "\u313E",
+    "/ko:rieulthieuthjongseong": "\u11B4",
+    "/ko:rieultikeut": "\u316A",
+    "/ko:rieultikeuthieuhjongseong": "\u11CF",
+    "/ko:rieultikeutjongseong": "\u11CE",
+    "/ko:rieulyeorinhieuh": "\u316D",
+    "/ko:rieulyeorinhieuhjongseong": "\u11D9",
+    "/ko:sios": "\u3145",
+    "/ko:sioschieuchchoseong": "\u1137",
+    "/ko:sioschoseong": "\u1109",
+    "/ko:sioscieuc": "\u317E",
+    "/ko:sioscieucchoseong": "\u1136",
+    "/ko:sioshieuhchoseong": "\u113B",
+    "/ko:siosieungchoseong": "\u1135",
+    "/ko:siosjongseong": "\u11BA",
+    "/ko:sioskhieukhchoseong": "\u1138",
+    "/ko:sioskiyeok": "\u317A",
+    "/ko:sioskiyeokchoseong": "\u112D",
+    "/ko:sioskiyeokjongseong": "\u11E7",
+    "/ko:siosmieumchoseong": "\u1131",
+    "/ko:siosnieun": "\u317B",
+    "/ko:siosnieunchoseong": "\u112E",
+    "/ko:siosphieuphchoseong": "\u113A",
+    "/ko:siospieup": "\u317D",
+    "/ko:siospieupchoseong": "\u1132",
+    "/ko:siospieupjongseong": "\u11EA",
+    "/ko:siospieupkiyeokchoseong": "\u1133",
+    "/ko:siosrieulchoseong": "\u1130",
+    "/ko:siosrieuljongseong": "\u11E9",
+    "/ko:siosssangsioschoseong": "\u1134",
+    "/ko:siosthieuthchoseong": "\u1139",
+    "/ko:siostikeut": "\u317C",
+    "/ko:siostikeutchoseong": "\u112F",
+    "/ko:siostikeutjongseong": "\u11E8",
+    "/ko:ssangaraeajungseong": "\u11A2",
+    "/ko:ssangcieuc": "\u3149",
+    "/ko:ssangcieucchoseong": "\u110D",
+    "/ko:ssanghieuh": "\u3185",
+    "/ko:ssanghieuhchoseong": "\u1158",
+    "/ko:ssangieung": "\u3180",
+    "/ko:ssangieungchoseong": "\u1147",
+    "/ko:ssangieungjongseong": "\u11EE",
+    "/ko:ssangkiyeok": "\u3132",
+    "/ko:ssangkiyeokchoseong": "\u1101",
+    "/ko:ssangkiyeokjongseong": "\u11A9",
+    "/ko:ssangnieun": "\u3165",
+    "/ko:ssangnieunchoseong": "\u1114",
+    "/ko:ssangnieunjongseong": "\u11FF",
+    "/ko:ssangpieup": "\u3143",
+    "/ko:ssangpieupchoseong": "\u1108",
+    "/ko:ssangrieulchoseong": "\u1119",
+    "/ko:ssangrieuljongseong": "\u11D0",
+    "/ko:ssangsios": "\u3146",
+    "/ko:ssangsioschoseong": "\u110A",
+    "/ko:ssangsiosjongseong": "\u11BB",
+    "/ko:ssangtikeut": "\u3138",
+    "/ko:ssangtikeutchoseong": "\u1104",
+    "/ko:thieuth": "\u314C",
+    "/ko:thieuthchoseong": "\u1110",
+    "/ko:thieuthjongseong": "\u11C0",
+    "/ko:tikeut": "\u3137",
+    "/ko:tikeutchoseong": "\u1103",
+    "/ko:tikeutjongseong": "\u11AE",
+    "/ko:tikeutkiyeokchoseong": "\u1117",
+    "/ko:tikeutkiyeokjongseong": "\u11CA",
+    "/ko:tikeutrieulchoseong": "\u115E",
+    "/ko:tikeutrieuljongseong": "\u11CB",
+    "/ko:u": "\u315C",
+    "/ko:uaejungseong": "\u118A",
+    "/ko:uajungseong": "\u1189",
+    "/ko:ueo_eujungseong": "\u118B",
+    "/ko:ujungseong": "\u116E",
+    "/ko:uujungseong": "\u118D",
+    "/ko:uyejungseong": "\u118C",
+    "/ko:wa": "\u3158",
+    "/ko:wae": "\u3159",
+    "/ko:waejungseong": "\u116B",
+    "/ko:wajungseong": "\u116A",
+    "/ko:we": "\u315E",
+    "/ko:wejungseong": "\u1170",
+    "/ko:weo": "\u315D",
+    "/ko:weojungseong": "\u116F",
+    "/ko:wi": "\u315F",
+    "/ko:wijungseong": "\u1171",
+    "/ko:ya": "\u3151",
+    "/ko:yae": "\u3152",
+    "/ko:yaejungseong": "\u1164",
+    "/ko:yajungseong": "\u1163",
+    "/ko:yaojungseong": "\u1178",
+    "/ko:yaujungseong": "\u11A4",
+    "/ko:yayojungseong": "\u1179",
+    "/ko:ye": "\u3156",
+    "/ko:yejungseong": "\u1168",
+    "/ko:yeo": "\u3155",
+    "/ko:yeojungseong": "\u1167",
+    "/ko:yeoojungseong": "\u117D",
+    "/ko:yeorinhieuh": "\u3186",
+    "/ko:yeorinhieuhchoseong": "\u1159",
+    "/ko:yeorinhieuhjongseong": "\u11F9",
+    "/ko:yeoujungseong": "\u117E",
+    "/ko:yeoyajungseong": "\u11A5",
+    "/ko:yesieung": "\u3181",
+    "/ko:yesieungchoseong": "\u114C",
+    "/ko:yesieungjongseong": "\u11F0",
+    "/ko:yesieungpansios": "\u3183",
+    "/ko:yesieungpansiosjongseong": "\u11F2",
+    "/ko:yesieungsios": "\u3182",
+    "/ko:yesieungsiosjongseong": "\u11F1",
+    "/ko:yi": "\u3162",
+    "/ko:yijungseong": "\u1174",
+    "/ko:yiujungseong": "\u1197",
+    "/ko:yo": "\u315B",
+    "/ko:yoi": "\u3189",
+    "/ko:yoijungseong": "\u1188",
+    "/ko:yojungseong": "\u116D",
+    "/ko:yoojungseong": "\u1187",
+    "/ko:yoya": "\u3187",
+    "/ko:yoyae": "\u3188",
+    "/ko:yoyaejungseong": "\u1185",
+    "/ko:yoyajungseong": "\u1184",
+    "/ko:yoyeojungseong": "\u1186",
+    "/ko:yu": "\u3160",
+    "/ko:yuajungseong": "\u118E",
+    "/ko:yuejungseong": "\u1190",
+    "/ko:yueojungseong": "\u118F",
+    "/ko:yui": "\u318C",
+    "/ko:yuijungseong": "\u1194",
+    "/ko:yujungseong": "\u1172",
+    "/ko:yuujungseong": "\u1193",
+    "/ko:yuye": "\u318B",
+    "/ko:yuyejungseong": "\u1192",
+    "/ko:yuyeo": "\u318A",
+    "/ko:yuyeojungseong": "\u1191",
+    "/koala": "\u1F428",
+    "/kobliquestroke": "\uA7A3",
+    "/kocirclekatakana": "\u32D9",
+    "/kohiragana": "\u3053",
+    "/kohmfullwidth": "\u33C0",
+    "/kohmsquare": "\u33C0",
+    "/kokaithai": "\u0E01",
+    "/kokatakana": "\u30B3",
+    "/kokatakanahalfwidth": "\uFF7A",
+    "/kooposquare": "\u331E",
+    "/koppa": "\u03DF",
+    "/koppaarchaic": "\u03D9",
+    "/koppacyr": "\u0481",
+    "/koppacyrillic": "\u0481",
+    "/koreanstandardsymbol": "\u327F",
+    "/koroniscmb": "\u0343",
+    "/korunasquare": "\u331D",
+    "/kotoideographiccircled": "\u3247",
+    "/kpafullwidth": "\u33AA",
+    "/kparen": "\u24A6",
+    "/kparenthesized": "\u24A6",
+    "/kpasquare": "\u33AA",
+    "/kra": "\u0138",
+    "/ksicyr": "\u046F",
+    "/ksicyrillic": "\u046F",
+    "/kstroke": "\uA741",
+    "/kstrokediagonalstroke": "\uA745",
+    "/ktfullwidth": "\u33CF",
+    "/ktsquare": "\u33CF",
+    "/kturned": "\u029E",
+    "/kucirclekatakana": "\u32D7",
+    "/kuhiragana": "\u304F",
+    "/kukatakana": "\u30AF",
+    "/kukatakanahalfwidth": "\uFF78",
+    "/kuroonesquare": "\u331B",
+    "/kuruzeirosquare": "\u331A",
+    "/kvfullwidth": "\u33B8",
+    "/kvsquare": "\u33B8",
+    "/kwfullwidth": "\u33BE",
+    "/kwsquare": "\u33BE",
+    "/kyuriisquare": "\u3312",
+    "/l": "\u006C",
+    "/l.inferior": "\u2097",
+    "/label": "\u1F3F7",
+    "/labengali": "\u09B2",
+    "/laborideographiccircled": "\u3298",
+    "/laborideographicparen": "\u3238",
+    "/lacute": "\u013A",
+    "/ladeva": "\u0932",
+    "/ladyBeetle": "\u1F41E",
+    "/lagujarati": "\u0AB2",
+    "/lagurmukhi": "\u0A32",
+    "/lakkhangyaothai": "\u0E45",
+    "/lam": "\u0644",
+    "/lam.fina": "\uFEDE",
+    "/lam.init": "\uFEDF",
+    "/lam.init_alef.fina": "\uFEFB",
+    "/lam.init_alef.medi_hamzaabove.fina": "\uFEF7",
+    "/lam.init_alef.medi_hamzabelow.fina": "\uFEF9",
+    "/lam.init_alef.medi_maddaabove.fina": "\uFEF5",
+    "/lam.init_alefmaksura.fina": "\uFC43",
+    "/lam.init_hah.fina": "\uFC40",
+    "/lam.init_hah.medi": "\uFCCA",
+    "/lam.init_hah.medi_meem.medi": "\uFDB5",
+    "/lam.init_heh.medi": "\uFCCD",
+    "/lam.init_jeem.fina": "\uFC3F",
+    "/lam.init_jeem.medi": "\uFCC9",
+    "/lam.init_jeem.medi_jeem.medi": "\uFD83",
+    "/lam.init_jeem.medi_meem.medi": "\uFDBA",
+    "/lam.init_khah.fina": "\uFC41",
+    "/lam.init_khah.medi": "\uFCCB",
+    "/lam.init_khah.medi_meem.medi": "\uFD86",
+    "/lam.init_meem.fina": "\uFC42",
+    "/lam.init_meem.medi": "\uFCCC",
+    "/lam.init_meem.medi_hah.medi": "\uFD88",
+    "/lam.init_yeh.fina": "\uFC44",
+    "/lam.isol": "\uFEDD",
+    "/lam.medi": "\uFEE0",
+    "/lam.medi_alef.fina": "\uFEFC",
+    "/lam.medi_alef.medi_hamzaabove.fina": "\uFEF8",
+    "/lam.medi_alef.medi_hamzabelow.fina": "\uFEFA",
+    "/lam.medi_alef.medi_maddaabove.fina": "\uFEF6",
+    "/lam.medi_alefmaksura.fina": "\uFC86",
+    "/lam.medi_hah.medi_alefmaksura.fina": "\uFD82",
+    "/lam.medi_hah.medi_meem.fina": "\uFD80",
+    "/lam.medi_hah.medi_yeh.fina": "\uFD81",
+    "/lam.medi_jeem.medi_jeem.fina": "\uFD84",
+    "/lam.medi_jeem.medi_meem.fina": "\uFDBC",
+    "/lam.medi_jeem.medi_yeh.fina": "\uFDAC",
+    "/lam.medi_khah.medi_meem.fina": "\uFD85",
+    "/lam.medi_meem.fina": "\uFC85",
+    "/lam.medi_meem.medi": "\uFCED",
+    "/lam.medi_meem.medi_hah.fina": "\uFD87",
+    "/lam.medi_meem.medi_yeh.fina": "\uFDAD",
+    "/lam.medi_yeh.fina": "\uFC87",
+    "/lamBar": "\u076A",
+    "/lamVabove": "\u06B5",
+    "/lamalefabove": "\u06D9",
+    "/lamaleffinalarabic": "\uFEFC",
+    "/lamalefhamzaabovefinalarabic": "\uFEF8",
+    "/lamalefhamzaaboveisolatedarabic": "\uFEF7",
+    "/lamalefhamzabelowfinalarabic": "\uFEFA",
+    "/lamalefhamzabelowisolatedarabic": "\uFEF9",
+    "/lamalefisolatedarabic": "\uFEFB",
+    "/lamalefmaddaabovefinalarabic": "\uFEF6",
+    "/lamalefmaddaaboveisolatedarabic": "\uFEF5",
+    "/lamarabic": "\u0644",
+    "/lambda": "\u03BB",
+    "/lambdastroke": "\u019B",
+    "/lamdotabove": "\u06B6",
+    "/lamed": "\u05DC",
+    "/lamed:hb": "\u05DC",
+    "/lameddagesh": "\uFB3C",
+    "/lameddageshhebrew": "\uFB3C",
+    "/lamedhebrew": "\u05DC",
+    "/lamedholam": "\u05DC",
+    "/lamedholamdagesh": "\u05DC",
+    "/lamedholamdageshhebrew": "\u05DC",
+    "/lamedholamhebrew": "\u05DC",
+    "/lamedwide:hb": "\uFB25",
+    "/lamedwithdagesh:hb": "\uFB3C",
+    "/lamfinalarabic": "\uFEDE",
+    "/lamhahinitialarabic": "\uFCCA",
+    "/laminitialarabic": "\uFEDF",
+    "/lamjeeminitialarabic": "\uFCC9",
+    "/lamkhahinitialarabic": "\uFCCB",
+    "/lamlamhehisolatedarabic": "\uFDF2",
+    "/lammedialarabic": "\uFEE0",
+    "/lammeemhahinitialarabic": "\uFD88",
+    "/lammeeminitialarabic": "\uFCCC",
+    "/lammeemjeeminitialarabic": "\uFEDF",
+    "/lammeemkhahinitialarabic": "\uFEDF",
+    "/lamthreedotsabove": "\u06B7",
+    "/lamthreedotsbelow": "\u06B8",
+    "/lanemergeleftblack": "\u26D8",
+    "/lanemergeleftwhite": "\u26D9",
+    "/largeBlueCircle": "\u1F535",
+    "/largeBlueDiamond": "\u1F537",
+    "/largeOrangeDiamond": "\u1F536",
+    "/largeRedCircle": "\u1F534",
+    "/largecircle": "\u25EF",
+    "/largetackdown": "\u27D9",
+    "/largetackup": "\u27D8",
+    "/lari": "\u20BE",
+    "/lastQuarterMoon": "\u1F317",
+    "/lastQuarterMoonFace": "\u1F31C",
+    "/lastquartermoon": "\u263E",
+    "/layar": "\uA982",
+    "/lazysinverted": "\u223E",
+    "/lbar": "\u019A",
+    "/lbbar": "\u2114",
+    "/lbelt": "\u026C",
+    "/lbeltretroflex": "\uA78E",
+    "/lbopomofo": "\u310C",
+    "/lbroken": "\uA747",
+    "/lcaron": "\u013E",
+    "/lcedilla": "\u013C",
+    "/lcircle": "\u24DB",
+    "/lcircumflexbelow": "\u1E3D",
+    "/lcommaaccent": "\u013C",
+    "/lcurl": "\u0234",
+    "/ldblbar": "\u2C61",
+    "/ldot": "\u0140",
+    "/ldotaccent": "\u0140",
+    "/ldotbelow": "\u1E37",
+    "/ldotbelowmacron": "\u1E39",
+    "/leafFlutteringInWind": "\u1F343",
+    "/ledger": "\u1F4D2",
+    "/left-pointingMagnifyingGlass": "\u1F50D",
+    "/leftAngerBubble": "\u1F5EE",
+    "/leftFiveEighthsBlock": "\u258B",
+    "/leftHalfBlock": "\u258C",
+    "/leftHandTelephoneReceiver": "\u1F57B",
+    "/leftLuggage": "\u1F6C5",
+    "/leftOneEighthBlock": "\u258F",
+    "/leftOneQuarterBlock": "\u258E",
+    "/leftSevenEighthsBlock": "\u2589",
+    "/leftSpeechBubble": "\u1F5E8",
+    "/leftThoughtBubble": "\u1F5EC",
+    "/leftThreeEighthsBlock": "\u258D",
+    "/leftThreeQuartersBlock": "\u258A",
+    "/leftWritingHand": "\u1F58E",
+    "/leftangleabovecmb": "\u031A",
+    "/leftarrowoverrightarrow": "\u21C6",
+    "/leftdnheavyrightuplight": "\u2545",
+    "/leftharpoonoverrightharpoon": "\u21CB",
+    "/leftheavyrightdnlight": "\u252D",
+    "/leftheavyrightuplight": "\u2535",
+    "/leftheavyrightvertlight": "\u253D",
+    "/leftideographiccircled": "\u32A7",
+    "/leftlightrightdnheavy": "\u2532",
+    "/leftlightrightupheavy": "\u253A",
+    "/leftlightrightvertheavy": "\u254A",
+    "/lefttackbelowcmb": "\u0318",
+    "/lefttorightembed": "\u202A",
+    "/lefttorightisolate": "\u2066",
+    "/lefttorightmark": "\u200E",
+    "/lefttorightoverride": "\u202D",
+    "/leftupheavyrightdnlight": "\u2543",
+    "/lemon": "\u1F34B",
+    "/lenis": "\u1FBF",
+    "/lenisacute": "\u1FCE",
+    "/lenisgrave": "\u1FCD",
+    "/lenistilde": "\u1FCF",
+    "/leo": "\u264C",
+    "/leopard": "\u1F406",
+    "/less": "\u003C",
+    "/lessbutnotequal": "\u2268",
+    "/lessbutnotequivalent": "\u22E6",
+    "/lessdot": "\u22D6",
+    "/lessequal": "\u2264",
+    "/lessequalorgreater": "\u22DA",
+    "/lessmonospace": "\uFF1C",
+    "/lessorequivalent": "\u2272",
+    "/lessorgreater": "\u2276",
+    "/lessoverequal": "\u2266",
+    "/lesssmall": "\uFE64",
+    "/levelSlider": "\u1F39A",
+    "/lezh": "\u026E",
+    "/lfblock": "\u258C",
+    "/lhacyr": "\u0515",
+    "/lhookretroflex": "\u026D",
+    "/libra": "\u264E",
+    "/ligaturealeflamed:hb": "\uFB4F",
+    "/ligatureoemod": "\uA7F9",
+    "/lightCheckMark": "\u1F5F8",
+    "/lightRail": "\u1F688",
+    "/lightShade": "\u2591",
+    "/lightarcdnleft": "\u256E",
+    "/lightarcdnright": "\u256D",
+    "/lightarcupleft": "\u256F",
+    "/lightarcupright": "\u2570",
+    "/lightdbldashhorz": "\u254C",
+    "/lightdbldashvert": "\u254E",
+    "/lightdiagcross": "\u2573",
+    "/lightdiagupleftdnright": "\u2572",
+    "/lightdiaguprightdnleft": "\u2571",
+    "/lightdn": "\u2577",
+    "/lightdnhorz": "\u252C",
+    "/lightdnleft": "\u2510",
+    "/lightdnright": "\u250C",
+    "/lighthorz": "\u2500",
+    "/lightleft": "\u2574",
+    "/lightleftheavyright": "\u257C",
+    "/lightning": "\u2607",
+    "/lightningMood": "\u1F5F2",
+    "/lightningMoodBubble": "\u1F5F1",
+    "/lightquaddashhorz": "\u2508",
+    "/lightquaddashvert": "\u250A",
+    "/lightright": "\u2576",
+    "/lighttrpldashhorz": "\u2504",
+    "/lighttrpldashvert": "\u2506",
+    "/lightup": "\u2575",
+    "/lightupheavydn": "\u257D",
+    "/lightuphorz": "\u2534",
+    "/lightupleft": "\u2518",
+    "/lightupright": "\u2514",
+    "/lightvert": "\u2502",
+    "/lightverthorz": "\u253C",
+    "/lightvertleft": "\u2524",
+    "/lightvertright": "\u251C",
+    "/lineextensionhorizontal": "\u23AF",
+    "/lineextensionvertical": "\u23D0",
+    "/linemiddledotvertical": "\u237F",
+    "/lineseparator": "\u2028",
+    "/lingsapada": "\uA9C8",
+    "/link": "\u1F517",
+    "/linkedPaperclips": "\u1F587",
+    "/lips": "\u1F5E2",
+    "/lipstick": "\u1F484",
+    "/lira": "\u20A4",
+    "/litre": "\u2113",
+    "/livretournois": "\u20B6",
+    "/liwnarmenian": "\u056C",
+    "/lj": "\u01C9",
+    "/ljecyr": "\u0459",
+    "/ljecyrillic": "\u0459",
+    "/ljekomicyr": "\u0509",
+    "/ll": "\uF6C0",
+    "/lladeva": "\u0933",
+    "/llagujarati": "\u0AB3",
+    "/llinebelow": "\u1E3B",
+    "/llladeva": "\u0934",
+    "/llvocalicbengali": "\u09E1",
+    "/llvocalicdeva": "\u0961",
+    "/llvocalicvowelsignbengali": "\u09E3",
+    "/llvocalicvowelsigndeva": "\u0963",
+    "/llwelsh": "\u1EFB",
+    "/lmacrondot": "\u1E39",
+    "/lmfullwidth": "\u33D0",
+    "/lmiddletilde": "\u026B",
+    "/lmonospace": "\uFF4C",
+    "/lmsquare": "\u33D0",
+    "/lnfullwidth": "\u33D1",
+    "/lochulathai": "\u0E2C",
+    "/lock": "\u1F512",
+    "/lockInkPen": "\u1F50F",
+    "/logfullwidth": "\u33D2",
+    "/logicaland": "\u2227",
+    "/logicalandarray": "\u22C0",
+    "/logicalnot": "\u00AC",
+    "/logicalnotreversed": "\u2310",
+    "/logicalor": "\u2228",
+    "/logicalorarray": "\u22C1",
+    "/lolingthai": "\u0E25",
+    "/lollipop": "\u1F36D",
+    "/longdivision": "\u27CC",
+    "/longovershortmetrical": "\u23D2",
+    "/longovertwoshortsmetrical": "\u23D4",
+    "/longs": "\u017F",
+    "/longs_t": "\uFB05",
+    "/longsdot": "\u1E9B",
+    "/longswithdiagonalstroke": "\u1E9C",
+    "/longswithhighstroke": "\u1E9D",
+    "/longtackleft": "\u27DE",
+    "/longtackright": "\u27DD",
+    "/losslesssquare": "\u1F1A9",
+    "/loudlyCryingFace": "\u1F62D",
+    "/loveHotel": "\u1F3E9",
+    "/loveLetter": "\u1F48C",
+    "/lowBrightness": "\u1F505",
+    "/lowasterisk": "\u204E",
+    "/lowerFiveEighthsBlock": "\u2585",
+    "/lowerHalfBlock": "\u2584",
+    "/lowerLeftBallpointPen": "\u1F58A",
+    "/lowerLeftCrayon": "\u1F58D",
+    "/lowerLeftFountainPen": "\u1F58B",
+    "/lowerLeftPaintbrush": "\u1F58C",
+    "/lowerLeftPencil": "\u1F589",
+    "/lowerOneEighthBlock": "\u2581",
+    "/lowerOneQuarterBlock": "\u2582",
+    "/lowerRightShadowedWhiteCircle": "\u1F53E",
+    "/lowerSevenEighthsBlock": "\u2587",
+    "/lowerThreeEighthsBlock": "\u2583",
+    "/lowerThreeQuartersBlock": "\u2586",
+    "/lowercornerdotright": "\u27D3",
+    "/lowerhalfcircle": "\u25E1",
+    "/lowerhalfcircleinversewhite": "\u25DB",
+    "/lowerquadrantcirculararcleft": "\u25DF",
+    "/lowerquadrantcirculararcright": "\u25DE",
+    "/lowertriangleleft": "\u25FA",
+    "/lowertriangleleftblack": "\u25E3",
+    "/lowertriangleright": "\u25FF",
+    "/lowertrianglerightblack": "\u25E2",
+    "/lowideographiccircled": "\u32A6",
+    "/lowlinecenterline": "\uFE4E",
+    "/lowlinecmb": "\u0332",
+    "/lowlinedashed": "\uFE4D",
+    "/lownumeralsign": "\u0375",
+    "/lowquotedblprime": "\u301F",
+    "/lozenge": "\u25CA",
+    "/lozengedividedbyrulehorizontal": "\u27E0",
+    "/lozengesquare": "\u2311",
+    "/lparen": "\u24A7",
+    "/lparenthesized": "\u24A7",
+    "/lretroflex": "\u026D",
+    "/ls": "\u02AA",
+    "/lslash": "\u0142",
+    "/lsquare": "\u2113",
+    "/lstroke": "\uA749",
+    "/lsuperior": "\uF6EE",
+    "/lsupmod": "\u02E1",
+    "/lt:Alpha": "\u2C6D",
+    "/lt:Alphaturned": "\u2C70",
+    "/lt:Beta": "\uA7B4",
+    "/lt:Chi": "\uA7B3",
+    "/lt:Gamma": "\u0194",
+    "/lt:Iota": "\u0196",
+    "/lt:Omega": "\uA7B6",
+    "/lt:Upsilon": "\u01B1",
+    "/lt:beta": "\uA7B5",
+    "/lt:delta": "\u1E9F",
+    "/lt:omega": "\uA7B7",
+    "/ltshade": "\u2591",
+    "/lttr:bet": "\u2136",
+    "/lttr:dalet": "\u2138",
+    "/lttr:gimel": "\u2137",
+    "/lttr:gscript": "\u210A",
+    "/lturned": "\uA781",
+    "/ltypeopencircuit": "\u2390",
+    "/luhurpada": "\uA9C5",
+    "/lum": "\uA772",
+    "/lungsipada": "\uA9C9",
+    "/luthai": "\u0E26",
+    "/lvocalicbengali": "\u098C",
+    "/lvocalicdeva": "\u090C",
+    "/lvocalicvowelsignbengali": "\u09E2",
+    "/lvocalicvowelsigndeva": "\u0962",
+    "/lxfullwidth": "\u33D3",
+    "/lxsquare": "\u33D3",
+    "/lzed": "\u02AB",
+    "/m": "\u006D",
+    "/m.inferior": "\u2098",
+    "/m2fullwidth": "\u33A1",
+    "/m3fullwidth": "\u33A5",
+    "/mabengali": "\u09AE",
+    "/macirclekatakana": "\u32EE",
+    "/macron": "\u00AF",
+    "/macronbelowcmb": "\u0331",
+    "/macroncmb": "\u0304",
+    "/macronlowmod": "\u02CD",
+    "/macronmod": "\u02C9",
+    "/macronmonospace": "\uFFE3",
+    "/macute": "\u1E3F",
+    "/madda": "\u0653",
+    "/maddaabove": "\u06E4",
+    "/madeva": "\u092E",
+    "/madyapada": "\uA9C4",
+    "/mafullwidth": "\u3383",
+    "/magujarati": "\u0AAE",
+    "/magurmukhi": "\u0A2E",
+    "/mahapakhhebrew": "\u05A4",
+    "/mahapakhlefthebrew": "\u05A4",
+    "/mahhasquare": "\u3345",
+    "/mahiragana": "\u307E",
+    "/mahpach:hb": "\u05A4",
+    "/maichattawalowleftthai": "\uF895",
+    "/maichattawalowrightthai": "\uF894",
+    "/maichattawathai": "\u0E4B",
+    "/maichattawaupperleftthai": "\uF893",
+    "/maieklowleftthai": "\uF88C",
+    "/maieklowrightthai": "\uF88B",
+    "/maiekthai": "\u0E48",
+    "/maiekupperleftthai": "\uF88A",
+    "/maihanakatleftthai": "\uF884",
+    "/maihanakatthai": "\u0E31",
+    "/maikurosquare": "\u3343",
+    "/mairusquare": "\u3344",
+    "/maitaikhuleftthai": "\uF889",
+    "/maitaikhuthai": "\u0E47",
+    "/maitholowleftthai": "\uF88F",
+    "/maitholowrightthai": "\uF88E",
+    "/maithothai": "\u0E49",
+    "/maithoupperleftthai": "\uF88D",
+    "/maitrilowleftthai": "\uF892",
+    "/maitrilowrightthai": "\uF891",
+    "/maitrithai": "\u0E4A",
+    "/maitriupperleftthai": "\uF890",
+    "/maiyamokthai": "\u0E46",
+    "/makatakana": "\u30DE",
+    "/makatakanahalfwidth": "\uFF8F",
+    "/male": "\u2642",
+    "/malefemale": "\u26A5",
+    "/maleideographiccircled": "\u329A",
+    "/malestroke": "\u26A6",
+    "/malestrokemalefemale": "\u26A7",
+    "/man": "\u1F468",
+    "/manAndWomanHoldingHands": "\u1F46B",
+    "/manDancing": "\u1F57A",
+    "/manGuaPiMao": "\u1F472",
+    "/manInBusinessSuitLevitating": "\u1F574",
+    "/manTurban": "\u1F473",
+    "/manat": "\u20BC",
+    "/mansShoe": "\u1F45E",
+    "/mansyonsquare": "\u3347",
+    "/mantelpieceClock": "\u1F570",
+    "/mapleLeaf": "\u1F341",
+    "/maplighthouse": "\u26EF",
+    "/maqaf:hb": "\u05BE",
+    "/maqafhebrew": "\u05BE",
+    "/marchtelegraph": "\u32C2",
+    "/mark": "\u061C",
+    "/markerdottedraisedinterpolation": "\u2E07",
+    "/markerdottedtransposition": "\u2E08",
+    "/markerraisedinterpolation": "\u2E06",
+    "/marknoonghunna": "\u0658",
+    "/marksChapter": "\u1F545",
+    "/marriage": "\u26AD",
+    "/mars": "\u2642",
+    "/marukusquare": "\u3346",
+    "/masoraCircle:hb": "\u05AF",
+    "/masoracirclehebrew": "\u05AF",
+    "/masquare": "\u3383",
+    "/masumark": "\u303C",
+    "/math:bowtie": "\u22C8",
+    "/math:cuberoot": "\u221B",
+    "/math:fourthroot": "\u221C",
+    "/maximize": "\u1F5D6",
+    "/maytelegraph": "\u32C4",
+    "/mbfullwidth": "\u3386",
+    "/mbopomofo": "\u3107",
+    "/mbsmallfullwidth": "\u33D4",
+    "/mbsquare": "\u33D4",
+    "/mcircle": "\u24DC",
+    "/mcubedsquare": "\u33A5",
+    "/mdot": "\u1E41",
+    "/mdotaccent": "\u1E41",
+    "/mdotbelow": "\u1E43",
+    "/measuredangle": "\u2221",
+    "/measuredby": "\u225E",
+    "/meatOnBone": "\u1F356",
+    "/mecirclekatakana": "\u32F1",
+    "/medicineideographiccircled": "\u32A9",
+    "/mediumShade": "\u2592",
+    "/mediumcircleblack": "\u26AB",
+    "/mediumcirclewhite": "\u26AA",
+    "/mediummathematicalspace": "\u205F",
+    "/mediumsmallcirclewhite": "\u26AC",
+    "/meem": "\u0645",
+    "/meem.fina": "\uFEE2",
+    "/meem.init": "\uFEE3",
+    "/meem.init_alefmaksura.fina": "\uFC49",
+    "/meem.init_hah.fina": "\uFC46",
+    "/meem.init_hah.medi": "\uFCCF",
+    "/meem.init_hah.medi_jeem.medi": "\uFD89",
+    "/meem.init_hah.medi_meem.medi": "\uFD8A",
+    "/meem.init_jeem.fina": "\uFC45",
+    "/meem.init_jeem.medi": "\uFCCE",
+    "/meem.init_jeem.medi_hah.medi": "\uFD8C",
+    "/meem.init_jeem.medi_khah.medi": "\uFD92",
+    "/meem.init_jeem.medi_meem.medi": "\uFD8D",
+    "/meem.init_khah.fina": "\uFC47",
+    "/meem.init_khah.medi": "\uFCD0",
+    "/meem.init_khah.medi_jeem.medi": "\uFD8E",
+    "/meem.init_khah.medi_meem.medi": "\uFD8F",
+    "/meem.init_meem.fina": "\uFC48",
+    "/meem.init_meem.medi": "\uFCD1",
+    "/meem.init_yeh.fina": "\uFC4A",
+    "/meem.isol": "\uFEE1",
+    "/meem.medi": "\uFEE4",
+    "/meem.medi_alef.fina": "\uFC88",
+    "/meem.medi_hah.medi_yeh.fina": "\uFD8B",
+    "/meem.medi_jeem.medi_yeh.fina": "\uFDC0",
+    "/meem.medi_khah.medi_yeh.fina": "\uFDB9",
+    "/meem.medi_meem.fina": "\uFC89",
+    "/meem.medi_meem.medi_yeh.fina": "\uFDB1",
+    "/meemDotAbove": "\u0765",
+    "/meemDotBelow": "\u0766",
+    "/meemabove": "\u06E2",
+    "/meemabove.init": "\u06D8",
+    "/meemarabic": "\u0645",
+    "/meembelow": "\u06ED",
+    "/meemfinalarabic": "\uFEE2",
+    "/meeminitialarabic": "\uFEE3",
+    "/meemmedialarabic": "\uFEE4",
+    "/meemmeeminitialarabic": "\uFCD1",
+    "/meemmeemisolatedarabic": "\uFC48",
+    "/meetorusquare": "\u334D",
+    "/megasquare": "\u334B",
+    "/megatonsquare": "\u334C",
+    "/mehiragana": "\u3081",
+    "/meizierasquare": "\u337E",
+    "/mekatakana": "\u30E1",
+    "/mekatakanahalfwidth": "\uFF92",
+    "/melon": "\u1F348",
+    "/mem": "\u05DE",
+    "/mem:hb": "\u05DE",
+    "/memdagesh": "\uFB3E",
+    "/memdageshhebrew": "\uFB3E",
+    "/memhebrew": "\u05DE",
+    "/memo": "\u1F4DD",
+    "/memwithdagesh:hb": "\uFB3E",
+    "/menarmenian": "\u0574",
+    "/menorahNineBranches": "\u1F54E",
+    "/menpostSindhi": "\u06FE",
+    "/mens": "\u1F6B9",
+    "/mepigraphicinverted": "\uA7FD",
+    "/mercha:hb": "\u05A5",
+    "/merchaKefulah:hb": "\u05A6",
+    "/mercury": "\u263F",
+    "/merkhahebrew": "\u05A5",
+    "/merkhakefulahebrew": "\u05A6",
+    "/merkhakefulalefthebrew": "\u05A6",
+    "/merkhalefthebrew": "\u05A5",
+    "/metalideographiccircled": "\u328E",
+    "/metalideographicparen": "\u322E",
+    "/meteg:hb": "\u05BD",
+    "/metro": "\u1F687",
+    "/mgfullwidth": "\u338E",
+    "/mhook": "\u0271",
+    "/mhzfullwidth": "\u3392",
+    "/mhzsquare": "\u3392",
+    "/micirclekatakana": "\u32EF",
+    "/microphone": "\u1F3A4",
+    "/microscope": "\u1F52C",
+    "/middledotkatakanahalfwidth": "\uFF65",
+    "/middot": "\u00B7",
+    "/mieumacirclekorean": "\u3272",
+    "/mieumaparenkorean": "\u3212",
+    "/mieumcirclekorean": "\u3264",
+    "/mieumkorean": "\u3141",
+    "/mieumpansioskorean": "\u3170",
+    "/mieumparenkorean": "\u3204",
+    "/mieumpieupkorean": "\u316E",
+    "/mieumsioskorean": "\u316F",
+    "/mihiragana": "\u307F",
+    "/mikatakana": "\u30DF",
+    "/mikatakanahalfwidth": "\uFF90",
+    "/mikuronsquare": "\u3348",
+    "/milfullwidth": "\u33D5",
+    "/militaryMedal": "\u1F396",
+    "/milkyWay": "\u1F30C",
+    "/mill": "\u20A5",
+    "/millionscmbcyr": "\u0489",
+    "/millisecond": "\u2034",
+    "/millisecondreversed": "\u2037",
+    "/minibus": "\u1F690",
+    "/minidisc": "\u1F4BD",
+    "/minimize": "\u1F5D5",
+    "/minus": "\u2212",
+    "/minus.inferior": "\u208B",
+    "/minus.superior": "\u207B",
+    "/minusbelowcmb": "\u0320",
+    "/minuscircle": "\u2296",
+    "/minusmod": "\u02D7",
+    "/minusplus": "\u2213",
+    "/minussignmod": "\u02D7",
+    "/minustilde": "\u2242",
+    "/minute": "\u2032",
+    "/minutereversed": "\u2035",
+    "/miribaarusquare": "\u334A",
+    "/mirisquare": "\u3349",
+    "/misc:baby": "\u1F476",
+    "/misc:bell": "\u1F514",
+    "/misc:dash": "\u1F4A8",
+    "/misc:decimalseparator": "\u2396",
+    "/misc:diamondblack": "\u2666",
+    "/misc:diamondwhite": "\u2662",
+    "/misc:ear": "\u1F442",
+    "/misc:om": "\u1F549",
+    "/misc:ring": "\u1F48D",
+    "/misra": "\u060F",
+    "/mlfullwidth": "\u3396",
+    "/mlonglegturned": "\u0270",
+    "/mlsquare": "\u3396",
+    "/mlym:a": "\u0D05",
+    "/mlym:aa": "\u0D06",
+    "/mlym:aasign": "\u0D3E",
+    "/mlym:ai": "\u0D10",
+    "/mlym:aisign": "\u0D48",
+    "/mlym:anusvarasign": "\u0D02",
+    "/mlym:archaicii": "\u0D5F",
+    "/mlym:au": "\u0D14",
+    "/mlym:aulength": "\u0D57",
+    "/mlym:ausign": "\u0D4C",
+    "/mlym:avagrahasign": "\u0D3D",
+    "/mlym:ba": "\u0D2C",
+    "/mlym:bha": "\u0D2D",
+    "/mlym:ca": "\u0D1A",
+    "/mlym:candrabindusign": "\u0D01",
+    "/mlym:cha": "\u0D1B",
+    "/mlym:circularviramasign": "\u0D3C",
+    "/mlym:combininganusvaraabovesign": "\u0D00",
+    "/mlym:da": "\u0D26",
+    "/mlym:date": "\u0D79",
+    "/mlym:dda": "\u0D21",
+    "/mlym:ddha": "\u0D22",
+    "/mlym:dha": "\u0D27",
+    "/mlym:dotreph": "\u0D4E",
+    "/mlym:e": "\u0D0E",
+    "/mlym:ee": "\u0D0F",
+    "/mlym:eesign": "\u0D47",
+    "/mlym:eight": "\u0D6E",
+    "/mlym:esign": "\u0D46",
+    "/mlym:five": "\u0D6B",
+    "/mlym:four": "\u0D6A",
+    "/mlym:ga": "\u0D17",
+    "/mlym:gha": "\u0D18",
+    "/mlym:ha": "\u0D39",
+    "/mlym:i": "\u0D07",
+    "/mlym:ii": "\u0D08",
+    "/mlym:iisign": "\u0D40",
+    "/mlym:isign": "\u0D3F",
+    "/mlym:ja": "\u0D1C",
+    "/mlym:jha": "\u0D1D",
+    "/mlym:ka": "\u0D15",
+    "/mlym:kchillu": "\u0D7F",
+    "/mlym:kha": "\u0D16",
+    "/mlym:la": "\u0D32",
+    "/mlym:lchillu": "\u0D7D",
+    "/mlym:lla": "\u0D33",
+    "/mlym:llchillu": "\u0D7E",
+    "/mlym:llla": "\u0D34",
+    "/mlym:lllchillu": "\u0D56",
+    "/mlym:llvocal": "\u0D61",
+    "/mlym:llvocalsign": "\u0D63",
+    "/mlym:lvocal": "\u0D0C",
+    "/mlym:lvocalsign": "\u0D62",
+    "/mlym:ma": "\u0D2E",
+    "/mlym:mchillu": "\u0D54",
+    "/mlym:na": "\u0D28",
+    "/mlym:nchillu": "\u0D7B",
+    "/mlym:nga": "\u0D19",
+    "/mlym:nine": "\u0D6F",
+    "/mlym:nna": "\u0D23",
+    "/mlym:nnchillu": "\u0D7A",
+    "/mlym:nnna": "\u0D29",
+    "/mlym:nya": "\u0D1E",
+    "/mlym:o": "\u0D12",
+    "/mlym:one": "\u0D67",
+    "/mlym:oneeighth": "\u0D77",
+    "/mlym:onefifth": "\u0D5E",
+    "/mlym:onefortieth": "\u0D59",
+    "/mlym:onehalf": "\u0D74",
+    "/mlym:onehundred": "\u0D71",
+    "/mlym:oneone-hundred-and-sixtieth": "\u0D58",
+    "/mlym:onequarter": "\u0D73",
+    "/mlym:onesixteenth": "\u0D76",
+    "/mlym:onetenth": "\u0D5C",
+    "/mlym:onethousand": "\u0D72",
+    "/mlym:onetwentieth": "\u0D5B",
+    "/mlym:oo": "\u0D13",
+    "/mlym:oosign": "\u0D4B",
+    "/mlym:osign": "\u0D4A",
+    "/mlym:pa": "\u0D2A",
+    "/mlym:parasign": "\u0D4F",
+    "/mlym:pha": "\u0D2B",
+    "/mlym:ra": "\u0D30",
+    "/mlym:rra": "\u0D31",
+    "/mlym:rrchillu": "\u0D7C",
+    "/mlym:rrvocal": "\u0D60",
+    "/mlym:rrvocalsign": "\u0D44",
+    "/mlym:rvocal": "\u0D0B",
+    "/mlym:rvocalsign": "\u0D43",
+    "/mlym:sa": "\u0D38",
+    "/mlym:seven": "\u0D6D",
+    "/mlym:sha": "\u0D36",
+    "/mlym:six": "\u0D6C",
+    "/mlym:ssa": "\u0D37",
+    "/mlym:ta": "\u0D24",
+    "/mlym:ten": "\u0D70",
+    "/mlym:tha": "\u0D25",
+    "/mlym:three": "\u0D69",
+    "/mlym:threeeightieths": "\u0D5A",
+    "/mlym:threequarters": "\u0D75",
+    "/mlym:threesixteenths": "\u0D78",
+    "/mlym:threetwentieths": "\u0D5D",
+    "/mlym:tta": "\u0D1F",
+    "/mlym:ttha": "\u0D20",
+    "/mlym:ttta": "\u0D3A",
+    "/mlym:two": "\u0D68",
+    "/mlym:u": "\u0D09",
+    "/mlym:usign": "\u0D41",
+    "/mlym:uu": "\u0D0A",
+    "/mlym:uusign": "\u0D42",
+    "/mlym:va": "\u0D35",
+    "/mlym:verticalbarviramasign": "\u0D3B",
+    "/mlym:viramasign": "\u0D4D",
+    "/mlym:visargasign": "\u0D03",
+    "/mlym:ya": "\u0D2F",
+    "/mlym:ychillu": "\u0D55",
+    "/mlym:zero": "\u0D66",
+    "/mm2fullwidth": "\u339F",
+    "/mm3fullwidth": "\u33A3",
+    "/mmcubedsquare": "\u33A3",
+    "/mmfullwidth": "\u339C",
+    "/mmonospace": "\uFF4D",
+    "/mmsquaredsquare": "\u339F",
+    "/mobilePhone": "\u1F4F1",
+    "/mobilePhoneOff": "\u1F4F4",
+    "/mobilePhoneRightwardsArrowAtLeft": "\u1F4F2",
+    "/mocirclekatakana": "\u32F2",
+    "/models": "\u22A7",
+    "/mohiragana": "\u3082",
+    "/mohmfullwidth": "\u33C1",
+    "/mohmsquare": "\u33C1",
+    "/mokatakana": "\u30E2",
+    "/mokatakanahalfwidth": "\uFF93",
+    "/molfullwidth": "\u33D6",
+    "/molsquare": "\u33D6",
+    "/momathai": "\u0E21",
+    "/moneyBag": "\u1F4B0",
+    "/moneyWings": "\u1F4B8",
+    "/mong:a": "\u1820",
+    "/mong:aaligali": "\u1887",
+    "/mong:ahaligali": "\u1897",
+    "/mong:ang": "\u1829",
+    "/mong:angsibe": "\u1862",
+    "/mong:angtodo": "\u184A",
+    "/mong:anusvaraonealigali": "\u1880",
+    "/mong:ba": "\u182A",
+    "/mong:baludaaligali": "\u1885",
+    "/mong:baludaaligalithree": "\u1886",
+    "/mong:batodo": "\u184B",
+    "/mong:bhamanchualigali": "\u18A8",
+    "/mong:birga": "\u1800",
+    "/mong:caaligali": "\u188B",
+    "/mong:camanchualigali": "\u189C",
+    "/mong:cha": "\u1834",
+    "/mong:chasibe": "\u1871",
+    "/mong:chatodo": "\u1852",
+    "/mong:chi": "\u1842",
+    "/mong:colon": "\u1804",
+    "/mong:comma": "\u1802",
+    "/mong:commamanchu": "\u1808",
+    "/mong:cyamanchualigali": "\u18A3",
+    "/mong:da": "\u1833",
+    "/mong:daaligali": "\u1891",
+    "/mong:dagalgaaligali": "\u18A9",
+    "/mong:damarualigali": "\u1882",
+    "/mong:dasibe": "\u1869",
+    "/mong:datodo": "\u1851",
+    "/mong:ddaaligali": "\u188E",
+    "/mong:ddhamanchualigali": "\u189F",
+    "/mong:dhamanchualigali": "\u18A1",
+    "/mong:dzatodo": "\u185C",
+    "/mong:e": "\u1821",
+    "/mong:ee": "\u1827",
+    "/mong:eight": "\u1818",
+    "/mong:ellipsis": "\u1801",
+    "/mong:esibe": "\u185D",
+    "/mong:etodo": "\u1844",
+    "/mong:fa": "\u1839",
+    "/mong:famanchu": "\u1876",
+    "/mong:fasibe": "\u186B",
+    "/mong:five": "\u1815",
+    "/mong:four": "\u1814",
+    "/mong:fourdots": "\u1805",
+    "/mong:freevariationselectorone": "\u180B",
+    "/mong:freevariationselectorthree": "\u180D",
+    "/mong:freevariationselectortwo": "\u180C",
+    "/mong:ga": "\u182D",
+    "/mong:gaasibe": "\u186C",
+    "/mong:gaatodo": "\u1858",
+    "/mong:gasibe": "\u1864",
+    "/mong:gatodo": "\u184E",
+    "/mong:ghamanchualigali": "\u189A",
+    "/mong:haa": "\u183E",
+    "/mong:haasibe": "\u186D",
+    "/mong:haatodo": "\u1859",
+    "/mong:hasibe": "\u1865",
+    "/mong:i": "\u1822",
+    "/mong:ialigali": "\u1888",
+    "/mong:imanchu": "\u1873",
+    "/mong:isibe": "\u185E",
+    "/mong:itodo": "\u1845",
+    "/mong:iysibe": "\u185F",
+    "/mong:ja": "\u1835",
+    "/mong:jasibe": "\u186A",
+    "/mong:jatodo": "\u1853",
+    "/mong:jhamanchualigali": "\u189D",
+    "/mong:jiatodo": "\u185A",
+    "/mong:ka": "\u183A",
+    "/mong:kaaligali": "\u1889",
+    "/mong:kamanchu": "\u1874",
+    "/mong:kasibe": "\u1863",
+    "/mong:katodo": "\u1857",
+    "/mong:kha": "\u183B",
+    "/mong:la": "\u182F",
+    "/mong:lha": "\u1840",
+    "/mong:lhamanchualigali": "\u18AA",
+    "/mong:longvowelsigntodo": "\u1843",
+    "/mong:ma": "\u182E",
+    "/mong:matodo": "\u184F",
+    "/mong:na": "\u1828",
+    "/mong:ngaaligali": "\u188A",
+    "/mong:ngamanchualigali": "\u189B",
+    "/mong:niatodo": "\u185B",
+    "/mong:nine": "\u1819",
+    "/mong:nirugu": "\u180A",
+    "/mong:nnaaligali": "\u188F",
+    "/mong:o": "\u1823",
+    "/mong:oe": "\u1825",
+    "/mong:oetodo": "\u1848",
+    "/mong:one": "\u1811",
+    "/mong:otodo": "\u1846",
+    "/mong:pa": "\u182B",
+    "/mong:paaligali": "\u1892",
+    "/mong:pasibe": "\u1866",
+    "/mong:patodo": "\u184C",
+    "/mong:period": "\u1803",
+    "/mong:periodmanchu": "\u1809",
+    "/mong:phaaligali": "\u1893",
+    "/mong:qa": "\u182C",
+    "/mong:qatodo": "\u184D",
+    "/mong:ra": "\u1837",
+    "/mong:raasibe": "\u1870",
+    "/mong:ramanchu": "\u1875",
+    "/mong:sa": "\u1830",
+    "/mong:seven": "\u1817",
+    "/mong:sha": "\u1831",
+    "/mong:shasibe": "\u1867",
+    "/mong:six": "\u1816",
+    "/mong:softhyphentodo": "\u1806",
+    "/mong:ssaaligali": "\u1894",
+    "/mong:ssamanchualigali": "\u18A2",
+    "/mong:syllableboundarymarkersibe": "\u1807",
+    "/mong:ta": "\u1832",
+    "/mong:taaligali": "\u1890",
+    "/mong:tamanchualigali": "\u18A0",
+    "/mong:tasibe": "\u1868",
+    "/mong:tatodo": "\u1850",
+    "/mong:tatodoaligali": "\u1898",
+    "/mong:three": "\u1813",
+    "/mong:tsa": "\u183C",
+    "/mong:tsasibe": "\u186E",
+    "/mong:tsatodo": "\u1854",
+    "/mong:ttaaligali": "\u188C",
+    "/mong:ttamanchualigali": "\u189E",
+    "/mong:tthaaligali": "\u188D",
+    "/mong:two": "\u1812",
+    "/mong:u": "\u1824",
+    "/mong:ualigalihalf": "\u18A6",
+    "/mong:ubadamaaligali": "\u1883",
+    "/mong:ubadamaaligaliinverted": "\u1884",
+    "/mong:ue": "\u1826",
+    "/mong:uesibe": "\u1860",
+    "/mong:uetodo": "\u1849",
+    "/mong:usibe": "\u1861",
+    "/mong:utodo": "\u1847",
+    "/mong:visargaonealigali": "\u1881",
+    "/mong:vowelseparator": "\u180E",
+    "/mong:wa": "\u1838",
+    "/mong:watodo": "\u1856",
+    "/mong:ya": "\u1836",
+    "/mong:yaaligalihalf": "\u18A7",
+    "/mong:yatodo": "\u1855",
+    "/mong:za": "\u183D",
+    "/mong:zaaligali": "\u1896",
+    "/mong:zamanchualigali": "\u18A5",
+    "/mong:zasibe": "\u186F",
+    "/mong:zero": "\u1810",
+    "/mong:zhaaligali": "\u1895",
+    "/mong:zhamanchu": "\u1877",
+    "/mong:zhamanchualigali": "\u18A4",
+    "/mong:zhasibe": "\u1872",
+    "/mong:zhatodoaligali": "\u1899",
+    "/mong:zhi": "\u1841",
+    "/mong:zra": "\u183F",
+    "/monkey": "\u1F412",
+    "/monkeyFace": "\u1F435",
+    "/monogramyang": "\u268A",
+    "/monogramyin": "\u268B",
+    "/monorail": "\u1F69D",
+    "/monostable": "\u238D",
+    "/moodBubble": "\u1F5F0",
+    "/moonViewingCeremony": "\u1F391",
+    "/moonideographiccircled": "\u328A",
+    "/moonideographicparen": "\u322A",
+    "/moonlilithblack": "\u26B8",
+    "/mosque": "\u1F54C",
+    "/motorBoat": "\u1F6E5",
+    "/motorScooter": "\u1F6F5",
+    "/motorway": "\u1F6E3",
+    "/mountFuji": "\u1F5FB",
+    "/mountain": "\u26F0",
+    "/mountainBicyclist": "\u1F6B5",
+    "/mountainCableway": "\u1F6A0",
+    "/mountainRailway": "\u1F69E",
+    "/mouse": "\u1F401",
+    "/mouseFace": "\u1F42D",
+    "/mouth": "\u1F444",
+    "/movers2fullwidth": "\u33A8",
+    "/moversfullwidth": "\u33A7",
+    "/moverssquare": "\u33A7",
+    "/moverssquaredsquare": "\u33A8",
+    "/movieCamera": "\u1F3A5",
+    "/moyai": "\u1F5FF",
+    "/mpafullwidth": "\u33AB",
+    "/mparen": "\u24A8",
+    "/mparenthesized": "\u24A8",
+    "/mpasquare": "\u33AB",
+    "/msfullwidth": "\u33B3",
+    "/mssquare": "\u33B3",
+    "/msuperior": "\uF6EF",
+    "/mturned": "\u026F",
+    "/mu": "\u00B5",
+    "/mu.math": "\u00B5",
+    "/mu1": "\u00B5",
+    "/muafullwidth": "\u3382",
+    "/muasquare": "\u3382",
+    "/muchgreater": "\u226B",
+    "/muchless": "\u226A",
+    "/mucirclekatakana": "\u32F0",
+    "/muffullwidth": "\u338C",
+    "/mufsquare": "\u338C",
+    "/mugfullwidth": "\u338D",
+    "/mugreek": "\u03BC",
+    "/mugsquare": "\u338D",
+    "/muhiragana": "\u3080",
+    "/mukatakana": "\u30E0",
+    "/mukatakanahalfwidth": "\uFF91",
+    "/mulfullwidth": "\u3395",
+    "/mulsquare": "\u3395",
+    "/multimap": "\u22B8",
+    "/multimapleft": "\u27DC",
+    "/multipleMusicalNotes": "\u1F3B6",
+    "/multiply": "\u00D7",
+    "/multiset": "\u228C",
+    "/multisetmultiplication": "\u228D",
+    "/multisetunion": "\u228E",
+    "/mum": "\uA773",
+    "/mumfullwidth": "\u339B",
+    "/mumsquare": "\u339B",
+    "/munach:hb": "\u05A3",
+    "/munahhebrew": "\u05A3",
+    "/munahlefthebrew": "\u05A3",
+    "/musfullwidth": "\u33B2",
+    "/mushroom": "\u1F344",
+    "/musicalKeyboard": "\u1F3B9",
+    "/musicalKeyboardJacks": "\u1F398",
+    "/musicalNote": "\u1F3B5",
+    "/musicalScore": "\u1F3BC",
+    "/musicalnote": "\u266A",
+    "/musicalnotedbl": "\u266B",
+    "/musicflat": "\u266D",
+    "/musicflatsign": "\u266D",
+    "/musicnatural": "\u266E",
+    "/musicsharp": "\u266F",
+    "/musicsharpsign": "\u266F",
+    "/mussquare": "\u33B2",
+    "/muvfullwidth": "\u33B6",
+    "/muvsquare": "\u33B6",
+    "/muwfullwidth": "\u33BC",
+    "/muwsquare": "\u33BC",
+    "/mvfullwidth": "\u33B7",
+    "/mvmegafullwidth": "\u33B9",
+    "/mvmegasquare": "\u33B9",
+    "/mvsquare": "\u33B7",
+    "/mwfullwidth": "\u33BD",
+    "/mwmegafullwidth": "\u33BF",
+    "/mwmegasquare": "\u33BF",
+    "/mwsquare": "\u33BD",
+    "/n": "\u006E",
+    "/n.inferior": "\u2099",
+    "/n.superior": "\u207F",
+    "/nabengali": "\u09A8",
+    "/nabla": "\u2207",
+    "/nacirclekatakana": "\u32E4",
+    "/nacute": "\u0144",
+    "/nadeva": "\u0928",
+    "/nafullwidth": "\u3381",
+    "/nagujarati": "\u0AA8",
+    "/nagurmukhi": "\u0A28",
+    "/nahiragana": "\u306A",
+    "/nailPolish": "\u1F485",
+    "/naira": "\u20A6",
+    "/nakatakana": "\u30CA",
+    "/nakatakanahalfwidth": "\uFF85",
+    "/nameBadge": "\u1F4DB",
+    "/nameideographiccircled": "\u3294",
+    "/nameideographicparen": "\u3234",
+    "/namurda": "\uA99F",
+    "/nand": "\u22BC",
+    "/nanosquare": "\u3328",
+    "/napostrophe": "\u0149",
+    "/narrownobreakspace": "\u202F",
+    "/nasquare": "\u3381",
+    "/nationalPark": "\u1F3DE",
+    "/nationaldigitshapes": "\u206E",
+    "/nbopomofo": "\u310B",
+    "/nbspace": "\u00A0",
+    "/ncaron": "\u0148",
+    "/ncedilla": "\u0146",
+    "/ncircle": "\u24DD",
+    "/ncircumflexbelow": "\u1E4B",
+    "/ncommaaccent": "\u0146",
+    "/ncurl": "\u0235",
+    "/ndescender": "\uA791",
+    "/ndot": "\u1E45",
+    "/ndotaccent": "\u1E45",
+    "/ndotbelow": "\u1E47",
+    "/necirclekatakana": "\u32E7",
+    "/necktie": "\u1F454",
+    "/negatedturnstiledblverticalbarright": "\u22AF",
+    "/nehiragana": "\u306D",
+    "/neirapproximatelynoractuallyequal": "\u2247",
+    "/neirasersetnorequalup": "\u2289",
+    "/neirasubsetnorequal": "\u2288",
+    "/neirgreaternorequal": "\u2271",
+    "/neirgreaternorequivalent": "\u2275",
+    "/neirgreaternorless": "\u2279",
+    "/neirlessnorequal": "\u2270",
+    "/neirlessnorequivalent": "\u2274",
+    "/neirlessnorgreater": "\u2278",
+    "/nekatakana": "\u30CD",
+    "/nekatakanahalfwidth": "\uFF88",
+    "/neptune": "\u2646",
+    "/neuter": "\u26B2",
+    "/neutralFace": "\u1F610",
+    "/newMoon": "\u1F311",
+    "/newMoonFace": "\u1F31A",
+    "/newsheqel": "\u20AA",
+    "/newsheqelsign": "\u20AA",
+    "/newspaper": "\u1F4F0",
+    "/newsquare": "\u1F195",
+    "/nextpage": "\u2398",
+    "/nffullwidth": "\u338B",
+    "/nfsquare": "\u338B",
+    "/ng.fina": "\uFBD4",
+    "/ng.init": "\uFBD5",
+    "/ng.isol": "\uFBD3",
+    "/ng.medi": "\uFBD6",
+    "/ngabengali": "\u0999",
+    "/ngadeva": "\u0919",
+    "/ngagujarati": "\u0A99",
+    "/ngagurmukhi": "\u0A19",
+    "/ngalelet": "\uA98A",
+    "/ngaleletraswadi": "\uA98B",
+    "/ngoeh": "\u06B1",
+    "/ngoeh.fina": "\uFB9B",
+    "/ngoeh.init": "\uFB9C",
+    "/ngoeh.isol": "\uFB9A",
+    "/ngoeh.medi": "\uFB9D",
+    "/ngonguthai": "\u0E07",
+    "/ngrave": "\u01F9",
+    "/ngsquare": "\u1F196",
+    "/nhiragana": "\u3093",
+    "/nhookleft": "\u0272",
+    "/nhookretroflex": "\u0273",
+    "/nicirclekatakana": "\u32E5",
+    "/nieunacirclekorean": "\u326F",
+    "/nieunaparenkorean": "\u320F",
+    "/nieuncieuckorean": "\u3135",
+    "/nieuncirclekorean": "\u3261",
+    "/nieunhieuhkorean": "\u3136",
+    "/nieunkorean": "\u3134",
+    "/nieunpansioskorean": "\u3168",
+    "/nieunparenkorean": "\u3201",
+    "/nieunsioskorean": "\u3167",
+    "/nieuntikeutkorean": "\u3166",
+    "/nightStars": "\u1F303",
+    "/nightideographiccircled": "\u32B0",
+    "/nihiragana": "\u306B",
+    "/nikatakana": "\u30CB",
+    "/nikatakanahalfwidth": "\uFF86",
+    "/nikhahitleftthai": "\uF899",
+    "/nikhahitthai": "\u0E4D",
+    "/nine": "\u0039",
+    "/nine.inferior": "\u2089",
+    "/nine.roman": "\u2168",
+    "/nine.romansmall": "\u2178",
+    "/nine.superior": "\u2079",
+    "/ninearabic": "\u0669",
+    "/ninebengali": "\u09EF",
+    "/ninecircle": "\u2468",
+    "/ninecircledbl": "\u24FD",
+    "/ninecircleinversesansserif": "\u2792",
+    "/ninecomma": "\u1F10A",
+    "/ninedeva": "\u096F",
+    "/ninefar": "\u06F9",
+    "/ninegujarati": "\u0AEF",
+    "/ninegurmukhi": "\u0A6F",
+    "/ninehackarabic": "\u0669",
+    "/ninehangzhou": "\u3029",
+    "/nineideographiccircled": "\u3288",
+    "/nineideographicparen": "\u3228",
+    "/nineinferior": "\u2089",
+    "/ninemonospace": "\uFF19",
+    "/nineoldstyle": "\uF739",
+    "/nineparen": "\u247C",
+    "/nineparenthesized": "\u247C",
+    "/nineperiod": "\u2490",
+    "/ninepersian": "\u06F9",
+    "/nineroman": "\u2178",
+    "/ninesuperior": "\u2079",
+    "/nineteencircle": "\u2472",
+    "/nineteencircleblack": "\u24F3",
+    "/nineteenparen": "\u2486",
+    "/nineteenparenthesized": "\u2486",
+    "/nineteenperiod": "\u249A",
+    "/ninethai": "\u0E59",
+    "/nj": "\u01CC",
+    "/njecyr": "\u045A",
+    "/njecyrillic": "\u045A",
+    "/njekomicyr": "\u050B",
+    "/nkatakana": "\u30F3",
+    "/nkatakanahalfwidth": "\uFF9D",
+    "/nlegrightlong": "\u019E",
+    "/nlinebelow": "\u1E49",
+    "/nlongrightleg": "\u019E",
+    "/nmbr:oneeighth": "\u215B",
+    "/nmbr:onefifth": "\u2155",
+    "/nmbr:onetenth": "\u2152",
+    "/nmfullwidth": "\u339A",
+    "/nmonospace": "\uFF4E",
+    "/nmsquare": "\u339A",
+    "/nnabengali": "\u09A3",
+    "/nnadeva": "\u0923",
+    "/nnagujarati": "\u0AA3",
+    "/nnagurmukhi": "\u0A23",
+    "/nnnadeva": "\u0929",
+    "/noBicycles": "\u1F6B3",
+    "/noEntrySign": "\u1F6AB",
+    "/noMobilePhones": "\u1F4F5",
+    "/noOneUnderEighteen": "\u1F51E",
+    "/noPedestrians": "\u1F6B7",
+    "/noPiracy": "\u1F572",
+    "/noSmoking": "\u1F6AD",
+    "/nobliquestroke": "\uA7A5",
+    "/nocirclekatakana": "\u32E8",
+    "/nodeascending": "\u260A",
+    "/nodedescending": "\u260B",
+    "/noentry": "\u26D4",
+    "/nohiragana": "\u306E",
+    "/nokatakana": "\u30CE",
+    "/nokatakanahalfwidth": "\uFF89",
+    "/nominaldigitshapes": "\u206F",
+    "/nonPotableWater": "\u1F6B1",
+    "/nonbreakinghyphen": "\u2011",
+    "/nonbreakingspace": "\u00A0",
+    "/nonenthai": "\u0E13",
+    "/nonuthai": "\u0E19",
+    "/noon": "\u0646",
+    "/noon.fina": "\uFEE6",
+    "/noon.init": "\uFEE7",
+    "/noon.init_alefmaksura.fina": "\uFC4F",
+    "/noon.init_hah.fina": "\uFC4C",
+    "/noon.init_hah.medi": "\uFCD3",
+    "/noon.init_hah.medi_meem.medi": "\uFD95",
+    "/noon.init_heh.medi": "\uFCD6",
+    "/noon.init_jeem.fina": "\uFC4B",
+    "/noon.init_jeem.medi": "\uFCD2",
+    "/noon.init_jeem.medi_hah.medi": "\uFDB8",
+    "/noon.init_jeem.medi_meem.medi": "\uFD98",
+    "/noon.init_khah.fina": "\uFC4D",
+    "/noon.init_khah.medi": "\uFCD4",
+    "/noon.init_meem.fina": "\uFC4E",
+    "/noon.init_meem.medi": "\uFCD5",
+    "/noon.init_yeh.fina": "\uFC50",
+    "/noon.isol": "\uFEE5",
+    "/noon.medi": "\uFEE8",
+    "/noon.medi_alefmaksura.fina": "\uFC8E",
+    "/noon.medi_hah.medi_alefmaksura.fina": "\uFD96",
+    "/noon.medi_hah.medi_yeh.fina": "\uFDB3",
+    "/noon.medi_heh.medi": "\uFCEF",
+    "/noon.medi_jeem.medi_alefmaksura.fina": "\uFD99",
+    "/noon.medi_jeem.medi_hah.fina": "\uFDBD",
+    "/noon.medi_jeem.medi_meem.fina": "\uFD97",
+    "/noon.medi_jeem.medi_yeh.fina": "\uFDC7",
+    "/noon.medi_meem.fina": "\uFC8C",
+    "/noon.medi_meem.medi": "\uFCEE",
+    "/noon.medi_meem.medi_alefmaksura.fina": "\uFD9B",
+    "/noon.medi_meem.medi_yeh.fina": "\uFD9A",
+    "/noon.medi_noon.fina": "\uFC8D",
+    "/noon.medi_reh.fina": "\uFC8A",
+    "/noon.medi_yeh.fina": "\uFC8F",
+    "/noon.medi_zain.fina": "\uFC8B",
+    "/noonSmallTah": "\u0768",
+    "/noonSmallV": "\u0769",
+    "/noonTwoDotsBelow": "\u0767",
+    "/noonabove": "\u06E8",
+    "/noonarabic": "\u0646",
+    "/noondotbelow": "\u06B9",
+    "/noonfinalarabic": "\uFEE6",
+    "/noonghunna": "\u06BA",
+    "/noonghunna.fina": "\uFB9F",
+    "/noonghunna.isol": "\uFB9E",
+    "/noonghunnaarabic": "\u06BA",
+    "/noonghunnafinalarabic": "\uFB9F",
+    "/noonhehinitialarabic": "\uFEE7",
+    "/nooninitialarabic": "\uFEE7",
+    "/noonjeeminitialarabic": "\uFCD2",
+    "/noonjeemisolatedarabic": "\uFC4B",
+    "/noonmedialarabic": "\uFEE8",
+    "/noonmeeminitialarabic": "\uFCD5",
+    "/noonmeemisolatedarabic": "\uFC4E",
+    "/noonnoonfinalarabic": "\uFC8D",
+    "/noonring": "\u06BC",
+    "/noonthreedotsabove": "\u06BD",
+    "/nor": "\u22BD",
+    "/nordicmark": "\u20BB",
+    "/normalfacrsemidirectproductleft": "\u22C9",
+    "/normalfacrsemidirectproductright": "\u22CA",
+    "/normalsubgroorequalup": "\u22B4",
+    "/normalsubgroup": "\u22B2",
+    "/northeastPointingAirplane": "\u1F6EA",
+    "/nose": "\u1F443",
+    "/notalmostequal": "\u2249",
+    "/notasersetup": "\u2285",
+    "/notasympticallyequal": "\u2244",
+    "/notcheckmark": "\u237B",
+    "/notchedLeftSemicircleThreeDots": "\u1F543",
+    "/notchedRightSemicircleThreeDots": "\u1F544",
+    "/notcontains": "\u220C",
+    "/note": "\u1F5C8",
+    "/notePad": "\u1F5CA",
+    "/notePage": "\u1F5C9",
+    "/notebook": "\u1F4D3",
+    "/notebookDecorativeCover": "\u1F4D4",
+    "/notelement": "\u2209",
+    "/notelementof": "\u2209",
+    "/notequal": "\u2260",
+    "/notequivalent": "\u226D",
+    "/notexistential": "\u2204",
+    "/notgreater": "\u226F",
+    "/notgreaternorequal": "\u2271",
+    "/notgreaternorless": "\u2279",
+    "/notidentical": "\u2262",
+    "/notless": "\u226E",
+    "/notlessnorequal": "\u2270",
+    "/notnormalsubgroorequalup": "\u22EC",
+    "/notnormalsubgroup": "\u22EA",
+    "/notparallel": "\u2226",
+    "/notprecedes": "\u2280",
+    "/notsignturned": "\u2319",
+    "/notsquareimageorequal": "\u22E2",
+    "/notsquareoriginalorequal": "\u22E3",
+    "/notsubset": "\u2284",
+    "/notsucceeds": "\u2281",
+    "/notsuperset": "\u2285",
+    "/nottilde": "\u2241",
+    "/nottosquare": "\u3329",
+    "/nottrue": "\u22AD",
+    "/novembertelegraph": "\u32CA",
+    "/nowarmenian": "\u0576",
+    "/nparen": "\u24A9",
+    "/nparenthesized": "\u24A9",
+    "/nretroflex": "\u0273",
+    "/nsfullwidth": "\u33B1",
+    "/nssquare": "\u33B1",
+    "/nsuperior": "\u207F",
+    "/ntilde": "\u00F1",
+    "/nu": "\u03BD",
+    "/nucirclekatakana": "\u32E6",
+    "/nuhiragana": "\u306C",
+    "/nukatakana": "\u30CC",
+    "/nukatakanahalfwidth": "\uFF87",
+    "/nuktabengali": "\u09BC",
+    "/nuktadeva": "\u093C",
+    "/nuktagujarati": "\u0ABC",
+    "/nuktagurmukhi": "\u0A3C",
+    "/num": "\uA774",
+    "/numbermarkabove": "\u0605",
+    "/numbersign": "\u0023",
+    "/numbersignmonospace": "\uFF03",
+    "/numbersignsmall": "\uFE5F",
+    "/numeralsign": "\u0374",
+    "/numeralsigngreek": "\u0374",
+    "/numeralsignlowergreek": "\u0375",
+    "/numero": "\u2116",
+    "/nun": "\u05E0",
+    "/nun:hb": "\u05E0",
+    "/nunHafukha:hb": "\u05C6",
+    "/nundagesh": "\uFB40",
+    "/nundageshhebrew": "\uFB40",
+    "/nunhebrew": "\u05E0",
+    "/nunwithdagesh:hb": "\uFB40",
+    "/nutAndBolt": "\u1F529",
+    "/nvfullwidth": "\u33B5",
+    "/nvsquare": "\u33B5",
+    "/nwfullwidth": "\u33BB",
+    "/nwsquare": "\u33BB",
+    "/nyabengali": "\u099E",
+    "/nyadeva": "\u091E",
+    "/nyagujarati": "\u0A9E",
+    "/nyagurmukhi": "\u0A1E",
+    "/nyamurda": "\uA998",
+    "/nyeh": "\u0683",
+    "/nyeh.fina": "\uFB77",
+    "/nyeh.init": "\uFB78",
+    "/nyeh.isol": "\uFB76",
+    "/nyeh.medi": "\uFB79",
+    "/o": "\u006F",
+    "/o.inferior": "\u2092",
+    "/oacute": "\u00F3",
+    "/oangthai": "\u0E2D",
+    "/obarcyr": "\u04E9",
+    "/obardieresiscyr": "\u04EB",
+    "/obarred": "\u0275",
+    "/obarredcyrillic": "\u04E9",
+    "/obarreddieresiscyrillic": "\u04EB",
+    "/obelosdotted": "\u2E13",
+    "/obengali": "\u0993",
+    "/obopomofo": "\u311B",
+    "/obreve": "\u014F",
+    "/observereye": "\u23FF",
+    "/ocandradeva": "\u0911",
+    "/ocandragujarati": "\u0A91",
+    "/ocandravowelsigndeva": "\u0949",
+    "/ocandravowelsigngujarati": "\u0AC9",
+    "/ocaron": "\u01D2",
+    "/ocircle": "\u24DE",
+    "/ocirclekatakana": "\u32D4",
+    "/ocircumflex": "\u00F4",
+    "/ocircumflexacute": "\u1ED1",
+    "/ocircumflexdotbelow": "\u1ED9",
+    "/ocircumflexgrave": "\u1ED3",
+    "/ocircumflexhoi": "\u1ED5",
+    "/ocircumflexhookabove": "\u1ED5",
+    "/ocircumflextilde": "\u1ED7",
+    "/ocr:bowtie": "\u2445",
+    "/ocr:dash": "\u2448",
+    "/octagonalSign": "\u1F6D1",
+    "/octobertelegraph": "\u32C9",
+    "/octopus": "\u1F419",
+    "/ocyr": "\u043E",
+    "/ocyrillic": "\u043E",
+    "/odblacute": "\u0151",
+    "/odblgrave": "\u020D",
+    "/oden": "\u1F362",
+    "/odeva": "\u0913",
+    "/odieresis": "\u00F6",
+    "/odieresiscyr": "\u04E7",
+    "/odieresiscyrillic": "\u04E7",
+    "/odieresismacron": "\u022B",
+    "/odot": "\u022F",
+    "/odotbelow": "\u1ECD",
+    "/odotmacron": "\u0231",
+    "/oe": "\u0153",
+    "/oe.fina": "\uFBDA",
+    "/oe.isol": "\uFBD9",
+    "/oekirghiz": "\u06C5",
+    "/oekirghiz.fina": "\uFBE1",
+    "/oekirghiz.isol": "\uFBE0",
+    "/oekorean": "\u315A",
+    "/officeBuilding": "\u1F3E2",
+    "/ogonek": "\u02DB",
+    "/ogonekcmb": "\u0328",
+    "/ograve": "\u00F2",
+    "/ogravedbl": "\u020D",
+    "/ogujarati": "\u0A93",
+    "/oharmenian": "\u0585",
+    "/ohiragana": "\u304A",
+    "/ohm": "\u2126",
+    "/ohminverted": "\u2127",
+    "/ohoi": "\u1ECF",
+    "/ohookabove": "\u1ECF",
+    "/ohorn": "\u01A1",
+    "/ohornacute": "\u1EDB",
+    "/ohorndotbelow": "\u1EE3",
+    "/ohorngrave": "\u1EDD",
+    "/ohornhoi": "\u1EDF",
+    "/ohornhookabove": "\u1EDF",
+    "/ohorntilde": "\u1EE1",
+    "/ohungarumlaut": "\u0151",
+    "/ohuparen": "\u321E",
+    "/oi": "\u01A3",
+    "/oilDrum": "\u1F6E2",
+    "/oinvertedbreve": "\u020F",
+    "/ojeonparen": "\u321D",
+    "/okHandSign": "\u1F44C",
+    "/okatakana": "\u30AA",
+    "/okatakanahalfwidth": "\uFF75",
+    "/okorean": "\u3157",
+    "/oksquare": "\u1F197",
+    "/oldKey": "\u1F5DD",
+    "/oldPersonalComputer": "\u1F5B3",
+    "/olderMan": "\u1F474",
+    "/olderWoman": "\u1F475",
+    "/ole:hb": "\u05AB",
+    "/olehebrew": "\u05AB",
+    "/oloop": "\uA74D",
+    "/olowringinside": "\u2C7A",
+    "/omacron": "\u014D",
+    "/omacronacute": "\u1E53",
+    "/omacrongrave": "\u1E51",
+    "/omdeva": "\u0950",
+    "/omega": "\u03C9",
+    "/omega1": "\u03D6",
+    "/omegaacute": "\u1F7D",
+    "/omegaacuteiotasub": "\u1FF4",
+    "/omegaasper": "\u1F61",
+    "/omegaasperacute": "\u1F65",
+    "/omegaasperacuteiotasub": "\u1FA5",
+    "/omegaaspergrave": "\u1F63",
+    "/omegaaspergraveiotasub": "\u1FA3",
+    "/omegaasperiotasub": "\u1FA1",
+    "/omegaaspertilde": "\u1F67",
+    "/omegaaspertildeiotasub": "\u1FA7",
+    "/omegaclosed": "\u0277",
+    "/omegacyr": "\u0461",
+    "/omegacyrillic": "\u0461",
+    "/omegafunc": "\u2375",
+    "/omegagrave": "\u1F7C",
+    "/omegagraveiotasub": "\u1FF2",
+    "/omegaiotasub": "\u1FF3",
+    "/omegalatinclosed": "\u0277",
+    "/omegalenis": "\u1F60",
+    "/omegalenisacute": "\u1F64",
+    "/omegalenisacuteiotasub": "\u1FA4",
+    "/omegalenisgrave": "\u1F62",
+    "/omegalenisgraveiotasub": "\u1FA2",
+    "/omegalenisiotasub": "\u1FA0",
+    "/omegalenistilde": "\u1F66",
+    "/omegalenistildeiotasub": "\u1FA6",
+    "/omegaroundcyr": "\u047B",
+    "/omegaroundcyrillic": "\u047B",
+    "/omegatilde": "\u1FF6",
+    "/omegatildeiotasub": "\u1FF7",
+    "/omegatitlocyr": "\u047D",
+    "/omegatitlocyrillic": "\u047D",
+    "/omegatonos": "\u03CE",
+    "/omegaunderlinefunc": "\u2379",
+    "/omgujarati": "\u0AD0",
+    "/omicron": "\u03BF",
+    "/omicronacute": "\u1F79",
+    "/omicronasper": "\u1F41",
+    "/omicronasperacute": "\u1F45",
+    "/omicronaspergrave": "\u1F43",
+    "/omicrongrave": "\u1F78",
+    "/omicronlenis": "\u1F40",
+    "/omicronlenisacute": "\u1F44",
+    "/omicronlenisgrave": "\u1F42",
+    "/omicrontonos": "\u03CC",
+    "/omonospace": "\uFF4F",
+    "/onExclamationMarkLeftRightArrowAbove": "\u1F51B",
+    "/oncomingAutomobile": "\u1F698",
+    "/oncomingBus": "\u1F68D",
+    "/oncomingFireEngine": "\u1F6F1",
+    "/oncomingPoliceCar": "\u1F694",
+    "/oncomingTaxi": "\u1F696",
+    "/one": "\u0031",
+    "/one.inferior": "\u2081",
+    "/one.roman": "\u2160",
+    "/one.romansmall": "\u2170",
+    "/oneButtonMouse": "\u1F5AF",
+    "/onearabic": "\u0661",
+    "/onebengali": "\u09E7",
+    "/onecircle": "\u2460",
+    "/onecircledbl": "\u24F5",
+    "/onecircleinversesansserif": "\u278A",
+    "/onecomma": "\u1F102",
+    "/onedeva": "\u0967",
+    "/onedotenleader": "\u2024",
+    "/onedotovertwodots": "\u2E2B",
+    "/oneeighth": "\u215B",
+    "/onefar": "\u06F1",
+    "/onefitted": "\uF6DC",
+    "/onefraction": "\u215F",
+    "/onegujarati": "\u0AE7",
+    "/onegurmukhi": "\u0A67",
+    "/onehackarabic": "\u0661",
+    "/onehalf": "\u00BD",
+    "/onehangzhou": "\u3021",
+    "/onehundred.roman": "\u216D",
+    "/onehundred.romansmall": "\u217D",
+    "/onehundredthousand.roman": "\u2188",
+    "/onehundredtwentypsquare": "\u1F1A4",
+    "/oneideographiccircled": "\u3280",
+    "/oneideographicparen": "\u3220",
+    "/oneinferior": "\u2081",
+    "/onemonospace": "\uFF11",
+    "/oneninth": "\u2151",
+    "/onenumeratorbengali": "\u09F4",
+    "/oneoldstyle": "\uF731",
+    "/oneparen": "\u2474",
+    "/oneparenthesized": "\u2474",
+    "/oneperiod": "\u2488",
+    "/onepersian": "\u06F1",
+    "/onequarter": "\u00BC",
+    "/oneroman": "\u2170",
+    "/oneseventh": "\u2150",
+    "/onesixth": "\u2159",
+    "/onesuperior": "\u00B9",
+    "/onethai": "\u0E51",
+    "/onethird": "\u2153",
+    "/onethousand.roman": "\u216F",
+    "/onethousand.romansmall": "\u217F",
+    "/onethousandcd.roman": "\u2180",
+    "/onsusquare": "\u3309",
+    "/oo": "\uA74F",
+    "/oogonek": "\u01EB",
+    "/oogonekmacron": "\u01ED",
+    "/oogurmukhi": "\u0A13",
+    "/oomatragurmukhi": "\u0A4B",
+    "/oomusquare": "\u330A",
+    "/oopen": "\u0254",
+    "/oparen": "\u24AA",
+    "/oparenthesized": "\u24AA",
+    "/openBook": "\u1F4D6",
+    "/openFileFolder": "\u1F4C2",
+    "/openFolder": "\u1F5C1",
+    "/openHandsSign": "\u1F450",
+    "/openLock": "\u1F513",
+    "/openMailboxLoweredFlag": "\u1F4ED",
+    "/openMailboxRaisedFlag": "\u1F4EC",
+    "/openbullet": "\u25E6",
+    "/openheadarrowleft": "\u21FD",
+    "/openheadarrowleftright": "\u21FF",
+    "/openheadarrowright": "\u21FE",
+    "/opensubset": "\u27C3",
+    "/opensuperset": "\u27C4",
+    "/ophiuchus": "\u26CE",
+    "/opposition": "\u260D",
+    "/opticalDisc": "\u1F4BF",
+    "/opticalDiscIcon": "\u1F5B8",
+    "/option": "\u2325",
+    "/orangeBook": "\u1F4D9",
+    "/ordfeminine": "\u00AA",
+    "/ordmasculine": "\u00BA",
+    "/ordotinside": "\u27C7",
+    "/original": "\u22B6",
+    "/ornateleftparenthesis": "\uFD3E",
+    "/ornaterightparenthesis": "\uFD3F",
+    "/orthodoxcross": "\u2626",
+    "/orthogonal": "\u221F",
+    "/orya:a": "\u0B05",
+    "/orya:aa": "\u0B06",
+    "/orya:aasign": "\u0B3E",
+    "/orya:ai": "\u0B10",
+    "/orya:ailengthmark": "\u0B56",
+    "/orya:aisign": "\u0B48",
+    "/orya:anusvara": "\u0B02",
+    "/orya:au": "\u0B14",
+    "/orya:aulengthmark": "\u0B57",
+    "/orya:ausign": "\u0B4C",
+    "/orya:avagraha": "\u0B3D",
+    "/orya:ba": "\u0B2C",
+    "/orya:bha": "\u0B2D",
+    "/orya:ca": "\u0B1A",
+    "/orya:candrabindu": "\u0B01",
+    "/orya:cha": "\u0B1B",
+    "/orya:da": "\u0B26",
+    "/orya:dda": "\u0B21",
+    "/orya:ddha": "\u0B22",
+    "/orya:dha": "\u0B27",
+    "/orya:e": "\u0B0F",
+    "/orya:eight": "\u0B6E",
+    "/orya:esign": "\u0B47",
+    "/orya:five": "\u0B6B",
+    "/orya:four": "\u0B6A",
+    "/orya:fractiononeeighth": "\u0B76",
+    "/orya:fractiononehalf": "\u0B73",
+    "/orya:fractiononequarter": "\u0B72",
+    "/orya:fractiononesixteenth": "\u0B75",
+    "/orya:fractionthreequarters": "\u0B74",
+    "/orya:fractionthreesixteenths": "\u0B77",
+    "/orya:ga": "\u0B17",
+    "/orya:gha": "\u0B18",
+    "/orya:ha": "\u0B39",
+    "/orya:i": "\u0B07",
+    "/orya:ii": "\u0B08",
+    "/orya:iisign": "\u0B40",
+    "/orya:isign": "\u0B3F",
+    "/orya:isshar": "\u0B70",
+    "/orya:ja": "\u0B1C",
+    "/orya:jha": "\u0B1D",
+    "/orya:ka": "\u0B15",
+    "/orya:kha": "\u0B16",
+    "/orya:la": "\u0B32",
+    "/orya:lla": "\u0B33",
+    "/orya:llvocal": "\u0B61",
+    "/orya:llvocalsign": "\u0B63",
+    "/orya:lvocal": "\u0B0C",
+    "/orya:lvocalsign": "\u0B62",
+    "/orya:ma": "\u0B2E",
+    "/orya:na": "\u0B28",
+    "/orya:nga": "\u0B19",
+    "/orya:nine": "\u0B6F",
+    "/orya:nna": "\u0B23",
+    "/orya:nukta": "\u0B3C",
+    "/orya:nya": "\u0B1E",
+    "/orya:o": "\u0B13",
+    "/orya:one": "\u0B67",
+    "/orya:osign": "\u0B4B",
+    "/orya:pa": "\u0B2A",
+    "/orya:pha": "\u0B2B",
+    "/orya:ra": "\u0B30",
+    "/orya:rha": "\u0B5D",
+    "/orya:rra": "\u0B5C",
+    "/orya:rrvocal": "\u0B60",
+    "/orya:rrvocalsign": "\u0B44",
+    "/orya:rvocal": "\u0B0B",
+    "/orya:rvocalsign": "\u0B43",
+    "/orya:sa": "\u0B38",
+    "/orya:seven": "\u0B6D",
+    "/orya:sha": "\u0B36",
+    "/orya:six": "\u0B6C",
+    "/orya:ssa": "\u0B37",
+    "/orya:ta": "\u0B24",
+    "/orya:tha": "\u0B25",
+    "/orya:three": "\u0B69",
+    "/orya:tta": "\u0B1F",
+    "/orya:ttha": "\u0B20",
+    "/orya:two": "\u0B68",
+    "/orya:u": "\u0B09",
+    "/orya:usign": "\u0B41",
+    "/orya:uu": "\u0B0A",
+    "/orya:uusign": "\u0B42",
+    "/orya:va": "\u0B35",
+    "/orya:virama": "\u0B4D",
+    "/orya:visarga": "\u0B03",
+    "/orya:wa": "\u0B71",
+    "/orya:ya": "\u0B2F",
+    "/orya:yya": "\u0B5F",
+    "/orya:zero": "\u0B66",
+    "/oscript": "\u2134",
+    "/oshortdeva": "\u0912",
+    "/oshortvowelsigndeva": "\u094A",
+    "/oslash": "\u00F8",
+    "/oslashacute": "\u01FF",
+    "/osmallhiragana": "\u3049",
+    "/osmallkatakana": "\u30A9",
+    "/osmallkatakanahalfwidth": "\uFF6B",
+    "/ostroke": "\uA74B",
+    "/ostrokeacute": "\u01FF",
+    "/osuperior": "\uF6F0",
+    "/otcyr": "\u047F",
+    "/otcyrillic": "\u047F",
+    "/otilde": "\u00F5",
+    "/otildeacute": "\u1E4D",
+    "/otildedieresis": "\u1E4F",
+    "/otildemacron": "\u022D",
+    "/ou": "\u0223",
+    "/oubopomofo": "\u3121",
+    "/ounce": "\u2125",
+    "/outboxTray": "\u1F4E4",
+    "/outerjoinfull": "\u27D7",
+    "/outerjoinleft": "\u27D5",
+    "/outerjoinright": "\u27D6",
+    "/outputpassiveup": "\u2392",
+    "/overlap": "\u1F5D7",
+    "/overline": "\u203E",
+    "/overlinecenterline": "\uFE4A",
+    "/overlinecmb": "\u0305",
+    "/overlinedashed": "\uFE49",
+    "/overlinedblwavy": "\uFE4C",
+    "/overlinewavy": "\uFE4B",
+    "/overscore": "\u00AF",
+    "/ovfullwidth": "\u3375",
+    "/ovowelsignbengali": "\u09CB",
+    "/ovowelsigndeva": "\u094B",
+    "/ovowelsigngujarati": "\u0ACB",
+    "/ox": "\u1F402",
+    "/p": "\u0070",
+    "/p.inferior": "\u209A",
+    "/paampsfullwidth": "\u3380",
+    "/paampssquare": "\u3380",
+    "/paasentosquare": "\u332B",
+    "/paatusquare": "\u332C",
+    "/pabengali": "\u09AA",
+    "/pacerek": "\uA989",
+    "/package": "\u1F4E6",
+    "/pacute": "\u1E55",
+    "/padeva": "\u092A",
+    "/pafullwidth": "\u33A9",
+    "/page": "\u1F5CF",
+    "/pageCircledText": "\u1F5DF",
+    "/pageCurl": "\u1F4C3",
+    "/pageFacingUp": "\u1F4C4",
+    "/pagedown": "\u21DF",
+    "/pager": "\u1F4DF",
+    "/pages": "\u1F5D0",
+    "/pageup": "\u21DE",
+    "/pagoda": "\u1F6D4",
+    "/pagujarati": "\u0AAA",
+    "/pagurmukhi": "\u0A2A",
+    "/pahiragana": "\u3071",
+    "/paiyannoithai": "\u0E2F",
+    "/pakatakana": "\u30D1",
+    "/palatalizationcyrilliccmb": "\u0484",
+    "/palatcmbcyr": "\u0484",
+    "/pallas": "\u26B4",
+    "/palmTree": "\u1F334",
+    "/palmbranch": "\u2E19",
+    "/palochkacyr": "\u04CF",
+    "/palochkacyrillic": "\u04C0",
+    "/pamurda": "\uA9A6",
+    "/pandaFace": "\u1F43C",
+    "/pangkatpada": "\uA9C7",
+    "/pangkon": "\uA9C0",
+    "/pangrangkep": "\uA9CF",
+    "/pansioskorean": "\u317F",
+    "/panyangga": "\uA980",
+    "/paperclip": "\u1F4CE",
+    "/paragraph": "\u00B6",
+    "/paragraphos": "\u2E0F",
+    "/paragraphosforked": "\u2E10",
+    "/paragraphosforkedreversed": "\u2E11",
+    "/paragraphseparator": "\u2029",
+    "/parallel": "\u2225",
+    "/parallelogramblack": "\u25B0",
+    "/parallelogramwhite": "\u25B1",
+    "/parenbottom": "\u23DD",
+    "/parendblleft": "\u2E28",
+    "/parendblright": "\u2E29",
+    "/parenextensionleft": "\u239C",
+    "/parenextensionright": "\u239F",
+    "/parenflatleft": "\u27EE",
+    "/parenflatright": "\u27EF",
+    "/parenhookupleft": "\u239B",
+    "/parenhookupright": "\u239E",
+    "/parenleft": "\u0028",
+    "/parenleft.inferior": "\u208D",
+    "/parenleft.superior": "\u207D",
+    "/parenleftaltonearabic": "\uFD3E",
+    "/parenleftbt": "\uF8ED",
+    "/parenleftex": "\uF8EC",
+    "/parenleftinferior": "\u208D",
+    "/parenleftmonospace": "\uFF08",
+    "/parenleftsmall": "\uFE59",
+    "/parenleftsuperior": "\u207D",
+    "/parenlefttp": "\uF8EB",
+    "/parenleftvertical": "\uFE35",
+    "/parenlowerhookleft": "\u239D",
+    "/parenlowerhookright": "\u23A0",
+    "/parenright": "\u0029",
+    "/parenright.inferior": "\u208E",
+    "/parenright.superior": "\u207E",
+    "/parenrightaltonearabic": "\uFD3F",
+    "/parenrightbt": "\uF8F8",
+    "/parenrightex": "\uF8F7",
+    "/parenrightinferior": "\u208E",
+    "/parenrightmonospace": "\uFF09",
+    "/parenrightsmall": "\uFE5A",
+    "/parenrightsuperior": "\u207E",
+    "/parenrighttp": "\uF8F6",
+    "/parenrightvertical": "\uFE36",
+    "/parentop": "\u23DC",
+    "/partalternationmark": "\u303D",
+    "/partialdiff": "\u2202",
+    "/partnership": "\u3250",
+    "/partyPopper": "\u1F389",
+    "/paseq:hb": "\u05C0",
+    "/paseqhebrew": "\u05C0",
+    "/pashta:hb": "\u0599",
+    "/pashtahebrew": "\u0599",
+    "/pasquare": "\u33A9",
+    "/passengerShip": "\u1F6F3",
+    "/passivedown": "\u2391",
+    "/passportControl": "\u1F6C2",
+    "/patah": "\u05B7",
+    "/patah11": "\u05B7",
+    "/patah1d": "\u05B7",
+    "/patah2a": "\u05B7",
+    "/patah:hb": "\u05B7",
+    "/patahhebrew": "\u05B7",
+    "/patahnarrowhebrew": "\u05B7",
+    "/patahquarterhebrew": "\u05B7",
+    "/patahwidehebrew": "\u05B7",
+    "/pawPrints": "\u1F43E",
+    "/pawnblack": "\u265F",
+    "/pawnwhite": "\u2659",
+    "/pazer:hb": "\u05A1",
+    "/pazerhebrew": "\u05A1",
+    "/pbopomofo": "\u3106",
+    "/pcfullwidth": "\u3376",
+    "/pcircle": "\u24DF",
+    "/pdot": "\u1E57",
+    "/pdotaccent": "\u1E57",
+    "/pe": "\u05E4",
+    "/pe:hb": "\u05E4",
+    "/peace": "\u262E",
+    "/peach": "\u1F351",
+    "/pear": "\u1F350",
+    "/pecyr": "\u043F",
+    "/pecyrillic": "\u043F",
+    "/pedagesh": "\uFB44",
+    "/pedageshhebrew": "\uFB44",
+    "/pedestrian": "\u1F6B6",
+    "/peezisquare": "\u333B",
+    "/pefinaldageshhebrew": "\uFB43",
+    "/peh.fina": "\uFB57",
+    "/peh.init": "\uFB58",
+    "/peh.isol": "\uFB56",
+    "/peh.medi": "\uFB59",
+    "/peharabic": "\u067E",
+    "/peharmenian": "\u057A",
+    "/pehebrew": "\u05E4",
+    "/peheh": "\u06A6",
+    "/peheh.fina": "\uFB6F",
+    "/peheh.init": "\uFB70",
+    "/peheh.isol": "\uFB6E",
+    "/peheh.medi": "\uFB71",
+    "/pehfinalarabic": "\uFB57",
+    "/pehinitialarabic": "\uFB58",
+    "/pehiragana": "\u307A",
+    "/pehmedialarabic": "\uFB59",
+    "/pehookcyr": "\u04A7",
+    "/pekatakana": "\u30DA",
+    "/pemiddlehookcyrillic": "\u04A7",
+    "/penOverStampedEnvelope": "\u1F586",
+    "/pengkalconsonant": "\uA9BE",
+    "/penguin": "\u1F427",
+    "/penihisquare": "\u3338",
+    "/pensiveFace": "\u1F614",
+    "/pensusquare": "\u333A",
+    "/pentagram": "\u26E4",
+    "/pentasememetrical": "\u23D9",
+    "/pepetvowel": "\uA9BC",
+    "/per": "\u214C",
+    "/perafehebrew": "\uFB4E",
+    "/percent": "\u0025",
+    "/percentarabic": "\u066A",
+    "/percentmonospace": "\uFF05",
+    "/percentsmall": "\uFE6A",
+    "/percussivebidental": "\u02AD",
+    "/percussivebilabial": "\u02AC",
+    "/performingArts": "\u1F3AD",
+    "/period": "\u002E",
+    "/periodarmenian": "\u0589",
+    "/periodcentered": "\u00B7",
+    "/periodhalfwidth": "\uFF61",
+    "/periodinferior": "\uF6E7",
+    "/periodmonospace": "\uFF0E",
+    "/periodsmall": "\uFE52",
+    "/periodsuperior": "\uF6E8",
+    "/periodurdu": "\u06D4",
+    "/perispomenigreekcmb": "\u0342",
+    "/permanentpaper": "\u267E",
+    "/permille": "\u0609",
+    "/perpendicular": "\u22A5",
+    "/perseveringFace": "\u1F623",
+    "/personBlondHair": "\u1F471",
+    "/personBowingDeeply": "\u1F647",
+    "/personFrowning": "\u1F64D",
+    "/personRaisingBothHandsInCelebration": "\u1F64C",
+    "/personWithFoldedHands": "\u1F64F",
+    "/personWithPoutingFace": "\u1F64E",
+    "/personalComputer": "\u1F4BB",
+    "/personball": "\u26F9",
+    "/perspective": "\u2306",
+    "/pertenthousandsign": "\u2031",
+    "/perthousand": "\u2030",
+    "/peseta": "\u20A7",
+    "/peso": "\u20B1",
+    "/pesosquare": "\u3337",
+    "/petailcyr": "\u0525",
+    "/pewithdagesh:hb": "\uFB44",
+    "/pewithrafe:hb": "\uFB4E",
+    "/pffullwidth": "\u338A",
+    "/pflourish": "\uA753",
+    "/pfsquare": "\u338A",
+    "/phabengali": "\u09AB",
+    "/phadeva": "\u092B",
+    "/phagujarati": "\u0AAB",
+    "/phagurmukhi": "\u0A2B",
+    "/pharyngealvoicedfricative": "\u0295",
+    "/phfullwidth": "\u33D7",
+    "/phi": "\u03C6",
+    "/phi.math": "\u03D5",
+    "/phi1": "\u03D5",
+    "/phieuphacirclekorean": "\u327A",
+    "/phieuphaparenkorean": "\u321A",
+    "/phieuphcirclekorean": "\u326C",
+    "/phieuphkorean": "\u314D",
+    "/phieuphparenkorean": "\u320C",
+    "/philatin": "\u0278",
+    "/phinthuthai": "\u0E3A",
+    "/phisymbolgreek": "\u03D5",
+    "/phitailless": "\u2C77",
+    "/phon:AEsmall": "\u1D01",
+    "/phon:Aemod": "\u1D2D",
+    "/phon:Amod": "\u1D2C",
+    "/phon:Asmall": "\u1D00",
+    "/phon:Bbarmod": "\u1D2F",
+    "/phon:Bbarsmall": "\u1D03",
+    "/phon:Bmod": "\u1D2E",
+    "/phon:Csmall": "\u1D04",
+    "/phon:Dmod": "\u1D30",
+    "/phon:Dsmall": "\u1D05",
+    "/phon:ENcyrmod": "\u1D78",
+    "/phon:Elsmallcyr": "\u1D2B",
+    "/phon:Emod": "\u1D31",
+    "/phon:Ereversedmod": "\u1D32",
+    "/phon:Esmall": "\u1D07",
+    "/phon:Ethsmall": "\u1D06",
+    "/phon:Ezhsmall": "\u1D23",
+    "/phon:Gmod": "\u1D33",
+    "/phon:Hmod": "\u1D34",
+    "/phon:Imod": "\u1D35",
+    "/phon:Ismallmod": "\u1DA6",
+    "/phon:Ismallstroke": "\u1D7B",
+    "/phon:Istrokesmallmod": "\u1DA7",
+    "/phon:Jmod": "\u1D36",
+    "/phon:Jsmall": "\u1D0A",
+    "/phon:Kmod": "\u1D37",
+    "/phon:Ksmall": "\u1D0B",
+    "/phon:Lmod": "\u1D38",
+    "/phon:Lsmallmod": "\u1DAB",
+    "/phon:Lsmallstroke": "\u1D0C",
+    "/phon:Mmod": "\u1D39",
+    "/phon:Msmall": "\u1D0D",
+    "/phon:Nmod": "\u1D3A",
+    "/phon:Nreversedmod": "\u1D3B",
+    "/phon:Nsmallmod": "\u1DB0",
+    "/phon:Nsmallreversed": "\u1D0E",
+    "/phon:OUsmall": "\u1D15",
+    "/phon:Omod": "\u1D3C",
+    "/phon:Oopensmall": "\u1D10",
+    "/phon:Osmall": "\u1D0F",
+    "/phon:Oumod": "\u1D3D",
+    "/phon:Pmod": "\u1D3E",
+    "/phon:Psmall": "\u1D18",
+    "/phon:Rmod": "\u1D3F",
+    "/phon:Rsmallreversed": "\u1D19",
+    "/phon:Rsmallturned": "\u1D1A",
+    "/phon:Tmod": "\u1D40",
+    "/phon:Tsmall": "\u1D1B",
+    "/phon:Umod": "\u1D41",
+    "/phon:Usmall": "\u1D1C",
+    "/phon:Usmallmod": "\u1DB8",
+    "/phon:Usmallstroke": "\u1D7E",
+    "/phon:Vsmall": "\u1D20",
+    "/phon:Wmod": "\u1D42",
+    "/phon:Wsmall": "\u1D21",
+    "/phon:Zsmall": "\u1D22",
+    "/phon:aeturned": "\u1D02",
+    "/phon:aeturnedmod": "\u1D46",
+    "/phon:ain": "\u1D25",
+    "/phon:ainmod": "\u1D5C",
+    "/phon:alphamod": "\u1D45",
+    "/phon:alpharetroflexhook": "\u1D90",
+    "/phon:alphaturnedmod": "\u1D9B",
+    "/phon:amod": "\u1D43",
+    "/phon:aretroflexhook": "\u1D8F",
+    "/phon:aturnedmod": "\u1D44",
+    "/phon:betamod": "\u1D5D",
+    "/phon:bmiddletilde": "\u1D6C",
+    "/phon:bmod": "\u1D47",
+    "/phon:bpalatalhook": "\u1D80",
+    "/phon:ccurlmod": "\u1D9D",
+    "/phon:chimod": "\u1D61",
+    "/phon:cmod": "\u1D9C",
+    "/phon:deltamod": "\u1D5F",
+    "/phon:dhooktail": "\u1D91",
+    "/phon:dmiddletilde": "\u1D6D",
+    "/phon:dmod": "\u1D48",
+    "/phon:dotlessjstrokemod": "\u1DA1",
+    "/phon:dpalatalhook": "\u1D81",
+    "/phon:emod": "\u1D49",
+    "/phon:engmod": "\u1D51",
+    "/phon:eopenmod": "\u1D4B",
+    "/phon:eopenretroflexhook": "\u1D93",
+    "/phon:eopenreversedmod": "\u1D9F",
+    "/phon:eopenreversedretroflexhook": "\u1D94",
+    "/phon:eopenturned": "\u1D08",
+    "/phon:eopenturnedmod": "\u1D4C",
+    "/phon:eretroflexhook": "\u1D92",
+    "/phon:eshmod": "\u1DB4",
+    "/phon:eshpalatalhook": "\u1D8B",
+    "/phon:eshretroflexhook": "\u1D98",
+    "/phon:ethmod": "\u1D9E",
+    "/phon:ezhmod": "\u1DBE",
+    "/phon:ezhretroflexhook": "\u1D9A",
+    "/phon:fmiddletilde": "\u1D6E",
+    "/phon:fmod": "\u1DA0",
+    "/phon:fpalatalhook": "\u1D82",
+    "/phon:ginsular": "\u1D79",
+    "/phon:gmod": "\u1D4D",
+    "/phon:gpalatalhook": "\u1D83",
+    "/phon:gr:Gammasmall": "\u1D26",
+    "/phon:gr:Lambdasmall": "\u1D27",
+    "/phon:gr:Pismall": "\u1D28",
+    "/phon:gr:Psismall": "\u1D2A",
+    "/phon:gr:RsmallHO": "\u1D29",
+    "/phon:gr:betasubscript": "\u1D66",
+    "/phon:gr:chisubscript": "\u1D6A",
+    "/phon:gr:gammamod": "\u1D5E",
+    "/phon:gr:gammasubscript": "\u1D67",
+    "/phon:gr:phimod": "\u1D60",
+    "/phon:gr:phisubscript": "\u1D69",
+    "/phon:gr:rhosubscript": "\u1D68",
+    "/phon:gscriptmod": "\u1DA2",
+    "/phon:gturned": "\u1D77",
+    "/phon:hturnedmod": "\u1DA3",
+    "/phon:iotamod": "\u1DA5",
+    "/phon:iotastroke": "\u1D7C",
+    "/phon:iretroflexhook": "\u1D96",
+    "/phon:istrokemod": "\u1DA4",
+    "/phon:isubscript": "\u1D62",
+    "/phon:iturned": "\u1D09",
+    "/phon:iturnedmod": "\u1D4E",
+    "/phon:jcrossedtailmod": "\u1DA8",
+    "/phon:kmod": "\u1D4F",
+    "/phon:kpalatalhook": "\u1D84",
+    "/phon:lpalatalhook": "\u1D85",
+    "/phon:lpalatalhookmod": "\u1DAA",
+    "/phon:lretroflexhookmod": "\u1DA9",
+    "/phon:mhookmod": "\u1DAC",
+    "/phon:mlonglegturnedmod": "\u1DAD",
+    "/phon:mmiddletilde": "\u1D6F",
+    "/phon:mmod": "\u1D50",
+    "/phon:mpalatalhook": "\u1D86",
+    "/phon:mturnedmod": "\u1D5A",
+    "/phon:mturnedsideways": "\u1D1F",
+    "/phon:nlefthookmod": "\u1DAE",
+    "/phon:nmiddletilde": "\u1D70",
+    "/phon:npalatalhook": "\u1D87",
+    "/phon:nretroflexhookmod": "\u1DAF",
+    "/phon:obarmod": "\u1DB1",
+    "/phon:obottomhalf": "\u1D17",
+    "/phon:obottomhalfmod": "\u1D55",
+    "/phon:oeturned": "\u1D14",
+    "/phon:omod": "\u1D52",
+    "/phon:oopenmod": "\u1D53",
+    "/phon:oopenretroflexhook": "\u1D97",
+    "/phon:oopensideways": "\u1D12",
+    "/phon:osideways": "\u1D11",
+    "/phon:ostrokesideways": "\u1D13",
+    "/phon:otophalf": "\u1D16",
+    "/phon:otophalfmod": "\u1D54",
+    "/phon:phimod": "\u1DB2",
+    "/phon:pmiddletilde": "\u1D71",
+    "/phon:pmod": "\u1D56",
+    "/phon:ppalatalhook": "\u1D88",
+    "/phon:pstroke": "\u1D7D",
+    "/phon:rfishmiddletilde": "\u1D73",
+    "/phon:rmiddletilde": "\u1D72",
+    "/phon:rpalatalhook": "\u1D89",
+    "/phon:rsubscript": "\u1D63",
+    "/phon:schwamod": "\u1D4A",
+    "/phon:schwaretroflexhook": "\u1D95",
+    "/phon:shookmod": "\u1DB3",
+    "/phon:smiddletilde": "\u1D74",
+    "/phon:spalatalhook": "\u1D8A",
+    "/phon:spirantvoicedlaryngeal": "\u1D24",
+    "/phon:thetamod": "\u1DBF",
+    "/phon:thstrike": "\u1D7A",
+    "/phon:tmiddletilde": "\u1D75",
+    "/phon:tmod": "\u1D57",
+    "/phon:tpalatalhookmod": "\u1DB5",
+    "/phon:ubarmod": "\u1DB6",
+    "/phon:ue": "\u1D6B",
+    "/phon:umod": "\u1D58",
+    "/phon:upsilonmod": "\u1DB7",
+    "/phon:upsilonstroke": "\u1D7F",
+    "/phon:uretroflexhook": "\u1D99",
+    "/phon:usideways": "\u1D1D",
+    "/phon:usidewaysdieresised": "\u1D1E",
+    "/phon:usidewaysmod": "\u1D59",
+    "/phon:usubscript": "\u1D64",
+    "/phon:vhookmod": "\u1DB9",
+    "/phon:vmod": "\u1D5B",
+    "/phon:vpalatalhook": "\u1D8C",
+    "/phon:vsubscript": "\u1D65",
+    "/phon:vturnedmod": "\u1DBA",
+    "/phon:xpalatalhook": "\u1D8D",
+    "/phon:zcurlmod": "\u1DBD",
+    "/phon:zmiddletilde": "\u1D76",
+    "/phon:zmod": "\u1DBB",
+    "/phon:zpalatalhook": "\u1D8E",
+    "/phon:zretroflexhookmod": "\u1DBC",
+    "/phook": "\u01A5",
+    "/phophanthai": "\u0E1E",
+    "/phophungthai": "\u0E1C",
+    "/phosamphaothai": "\u0E20",
+    "/pi": "\u03C0",
+    "/pi.math": "\u03D6",
+    "/piasutorusquare": "\u332E",
+    "/pick": "\u26CF",
+    "/pidblstruck": "\u213C",
+    "/pieupacirclekorean": "\u3273",
+    "/pieupaparenkorean": "\u3213",
+    "/pieupcieuckorean": "\u3176",
+    "/pieupcirclekorean": "\u3265",
+    "/pieupkiyeokkorean": "\u3172",
+    "/pieupkorean": "\u3142",
+    "/pieupparenkorean": "\u3205",
+    "/pieupsioskiyeokkorean": "\u3174",
+    "/pieupsioskorean": "\u3144",
+    "/pieupsiostikeutkorean": "\u3175",
+    "/pieupthieuthkorean": "\u3177",
+    "/pieuptikeutkorean": "\u3173",
+    "/pig": "\u1F416",
+    "/pigFace": "\u1F437",
+    "/pigNose": "\u1F43D",
+    "/pihiragana": "\u3074",
+    "/pikatakana": "\u30D4",
+    "/pikosquare": "\u3330",
+    "/pikurusquare": "\u332F",
+    "/pilcrowsignreversed": "\u204B",
+    "/pileOfPoo": "\u1F4A9",
+    "/pill": "\u1F48A",
+    "/pineDecoration": "\u1F38D",
+    "/pineapple": "\u1F34D",
+    "/pisces": "\u2653",
+    "/piselehpada": "\uA9CC",
+    "/pistol": "\u1F52B",
+    "/pisymbolgreek": "\u03D6",
+    "/pitchfork": "\u22D4",
+    "/piwrarmenian": "\u0583",
+    "/placeOfWorship": "\u1F6D0",
+    "/placeofinterestsign": "\u2318",
+    "/planck": "\u210E",
+    "/plancktwopi": "\u210F",
+    "/plus": "\u002B",
+    "/plus.inferior": "\u208A",
+    "/plus.superior": "\u207A",
+    "/plusbelowcmb": "\u031F",
+    "/pluscircle": "\u2295",
+    "/plusminus": "\u00B1",
+    "/plusmod": "\u02D6",
+    "/plusmonospace": "\uFF0B",
+    "/plussignalt:hb": "\uFB29",
+    "/plussignmod": "\u02D6",
+    "/plussmall": "\uFE62",
+    "/plussuperior": "\u207A",
+    "/pluto": "\u2647",
+    "/pmfullwidth": "\u33D8",
+    "/pmonospace": "\uFF50",
+    "/pmsquare": "\u33D8",
+    "/pocketCalculator": "\u1F5A9",
+    "/poeticverse": "\u060E",
+    "/pohiragana": "\u307D",
+    "/pointerleftblack": "\u25C4",
+    "/pointerleftwhite": "\u25C5",
+    "/pointerrightblack": "\u25BA",
+    "/pointerrightwhite": "\u25BB",
+    "/pointingindexdownwhite": "\u261F",
+    "/pointingindexleftblack": "\u261A",
+    "/pointingindexleftwhite": "\u261C",
+    "/pointingindexrightblack": "\u261B",
+    "/pointingindexrightwhite": "\u261E",
+    "/pointingindexupwhite": "\u261D",
+    "/pointingtriangledownheavywhite": "\u26DB",
+    "/pointosquare": "\u333D",
+    "/pointring": "\u2E30",
+    "/pokatakana": "\u30DD",
+    "/pokrytiecmbcyr": "\u0487",
+    "/policeCar": "\u1F693",
+    "/policeCarsRevolvingLight": "\u1F6A8",
+    "/policeOfficer": "\u1F46E",
+    "/pondosquare": "\u3340",
+    "/poodle": "\u1F429",
+    "/popcorn": "\u1F37F",
+    "/popdirectionalformatting": "\u202C",
+    "/popdirectionalisolate": "\u2069",
+    "/poplathai": "\u0E1B",
+    "/portableStereo": "\u1F4FE",
+    "/positionindicator": "\u2316",
+    "/postalHorn": "\u1F4EF",
+    "/postalmark": "\u3012",
+    "/postalmarkface": "\u3020",
+    "/postbox": "\u1F4EE",
+    "/potOfFood": "\u1F372",
+    "/potableWater": "\u1F6B0",
+    "/pouch": "\u1F45D",
+    "/poultryLeg": "\u1F357",
+    "/poutingCatFace": "\u1F63E",
+    "/poutingFace": "\u1F621",
+    "/power": "\u23FB",
+    "/poweron": "\u23FD",
+    "/poweronoff": "\u23FC",
+    "/powersleep": "\u23FE",
+    "/pparen": "\u24AB",
+    "/pparenthesized": "\u24AB",
+    "/ppmfullwidth": "\u33D9",
+    "/prayerBeads": "\u1F4FF",
+    "/precedes": "\u227A",
+    "/precedesbutnotequivalent": "\u22E8",
+    "/precedesorequal": "\u227C",
+    "/precedesorequivalent": "\u227E",
+    "/precedesunderrelation": "\u22B0",
+    "/prescription": "\u211E",
+    "/preversedepigraphic": "\uA7FC",
+    "/previouspage": "\u2397",
+    "/prfullwidth": "\u33DA",
+    "/primedblmod": "\u02BA",
+    "/primemod": "\u02B9",
+    "/primereversed": "\u2035",
+    "/princess": "\u1F478",
+    "/printer": "\u1F5A8",
+    "/printerIcon": "\u1F5B6",
+    "/printideographiccircled": "\u329E",
+    "/printscreen": "\u2399",
+    "/product": "\u220F",
+    "/prohibitedSign": "\u1F6C7",
+    "/projective": "\u2305",
+    "/prolongedkana": "\u30FC",
+    "/propellor": "\u2318",
+    "/propersubset": "\u2282",
+    "/propersuperset": "\u2283",
+    "/propertyline": "\u214A",
+    "/proportion": "\u2237",
+    "/proportional": "\u221D",
+    "/psfullwidth": "\u33B0",
+    "/psi": "\u03C8",
+    "/psicyr": "\u0471",
+    "/psicyrillic": "\u0471",
+    "/psilicmbcyr": "\u0486",
+    "/psilipneumatacyrilliccmb": "\u0486",
+    "/pssquare": "\u33B0",
+    "/pstrokedescender": "\uA751",
+    "/ptail": "\uA755",
+    "/publicAddressLoudspeaker": "\u1F4E2",
+    "/puhiragana": "\u3077",
+    "/pukatakana": "\u30D7",
+    "/punctuationspace": "\u2008",
+    "/purpleHeart": "\u1F49C",
+    "/purse": "\u1F45B",
+    "/pushpin": "\u1F4CC",
+    "/putLitterInItsPlace": "\u1F6AE",
+    "/pvfullwidth": "\u33B4",
+    "/pvsquare": "\u33B4",
+    "/pwfullwidth": "\u33BA",
+    "/pwsquare": "\u33BA",
+    "/q": "\u0071",
+    "/qacyr": "\u051B",
+    "/qadeva": "\u0958",
+    "/qadma:hb": "\u05A8",
+    "/qadmahebrew": "\u05A8",
+    "/qaf": "\u0642",
+    "/qaf.fina": "\uFED6",
+    "/qaf.init": "\uFED7",
+    "/qaf.init_alefmaksura.fina": "\uFC35",
+    "/qaf.init_hah.fina": "\uFC33",
+    "/qaf.init_hah.medi": "\uFCC2",
+    "/qaf.init_meem.fina": "\uFC34",
+    "/qaf.init_meem.medi": "\uFCC3",
+    "/qaf.init_meem.medi_hah.medi": "\uFDB4",
+    "/qaf.init_yeh.fina": "\uFC36",
+    "/qaf.isol": "\uFED5",
+    "/qaf.medi": "\uFED8",
+    "/qaf.medi_alefmaksura.fina": "\uFC7E",
+    "/qaf.medi_meem.medi_hah.fina": "\uFD7E",
+    "/qaf.medi_meem.medi_meem.fina": "\uFD7F",
+    "/qaf.medi_meem.medi_yeh.fina": "\uFDB2",
+    "/qaf.medi_yeh.fina": "\uFC7F",
+    "/qaf_lam_alefmaksuraabove": "\u06D7",
+    "/qafarabic": "\u0642",
+    "/qafdotabove": "\u06A7",
+    "/qaffinalarabic": "\uFED6",
+    "/qafinitialarabic": "\uFED7",
+    "/qafmedialarabic": "\uFED8",
+    "/qafthreedotsabove": "\u06A8",
+    "/qamats": "\u05B8",
+    "/qamats10": "\u05B8",
+    "/qamats1a": "\u05B8",
+    "/qamats1c": "\u05B8",
+    "/qamats27": "\u05B8",
+    "/qamats29": "\u05B8",
+    "/qamats33": "\u05B8",
+    "/qamats:hb": "\u05B8",
+    "/qamatsQatan:hb": "\u05C7",
+    "/qamatsde": "\u05B8",
+    "/qamatshebrew": "\u05B8",
+    "/qamatsnarrowhebrew": "\u05B8",
+    "/qamatsqatanhebrew": "\u05B8",
+    "/qamatsqatannarrowhebrew": "\u05B8",
+    "/qamatsqatanquarterhebrew": "\u05B8",
+    "/qamatsqatanwidehebrew": "\u05B8",
+    "/qamatsquarterhebrew": "\u05B8",
+    "/qamatswidehebrew": "\u05B8",
+    "/qarneFarah:hb": "\u059F",
+    "/qarneyparahebrew": "\u059F",
+    "/qbopomofo": "\u3111",
+    "/qcircle": "\u24E0",
+    "/qdiagonalstroke": "\uA759",
+    "/qhook": "\u02A0",
+    "/qhooktail": "\u024B",
+    "/qmonospace": "\uFF51",
+    "/qof": "\u05E7",
+    "/qof:hb": "\u05E7",
+    "/qofdagesh": "\uFB47",
+    "/qofdageshhebrew": "\uFB47",
+    "/qofhatafpatah": "\u05E7",
+    "/qofhatafpatahhebrew": "\u05E7",
+    "/qofhatafsegol": "\u05E7",
+    "/qofhatafsegolhebrew": "\u05E7",
+    "/qofhebrew": "\u05E7",
+    "/qofhiriq": "\u05E7",
+    "/qofhiriqhebrew": "\u05E7",
+    "/qofholam": "\u05E7",
+    "/qofholamhebrew": "\u05E7",
+    "/qofpatah": "\u05E7",
+    "/qofpatahhebrew": "\u05E7",
+    "/qofqamats": "\u05E7",
+    "/qofqamatshebrew": "\u05E7",
+    "/qofqubuts": "\u05E7",
+    "/qofqubutshebrew": "\u05E7",
+    "/qofsegol": "\u05E7",
+    "/qofsegolhebrew": "\u05E7",
+    "/qofsheva": "\u05E7",
+    "/qofshevahebrew": "\u05E7",
+    "/qoftsere": "\u05E7",
+    "/qoftserehebrew": "\u05E7",
+    "/qofwithdagesh:hb": "\uFB47",
+    "/qparen": "\u24AC",
+    "/qparenthesized": "\u24AC",
+    "/qpdigraph": "\u0239",
+    "/qstrokedescender": "\uA757",
+    "/quadarrowdownfunc": "\u2357",
+    "/quadarrowleftfunc": "\u2347",
+    "/quadarrowrightfunc": "\u2348",
+    "/quadarrowupfunc": "\u2350",
+    "/quadbackslashfunc": "\u2342",
+    "/quadcaretdownfunc": "\u234C",
+    "/quadcaretupfunc": "\u2353",
+    "/quadcirclefunc": "\u233C",
+    "/quadcolonfunc": "\u2360",
+    "/quaddelfunc": "\u2354",
+    "/quaddeltafunc": "\u234D",
+    "/quaddiamondfunc": "\u233A",
+    "/quaddividefunc": "\u2339",
+    "/quadequalfunc": "\u2338",
+    "/quadfunc": "\u2395",
+    "/quadgreaterfunc": "\u2344",
+    "/quadjotfunc": "\u233B",
+    "/quadlessfunc": "\u2343",
+    "/quadnotequalfunc": "\u236F",
+    "/quadquestionfunc": "\u2370",
+    "/quadrantLowerLeft": "\u2596",
+    "/quadrantLowerRight": "\u2597",
+    "/quadrantUpperLeft": "\u2598",
+    "/quadrantUpperLeftAndLowerLeftAndLowerRight": "\u2599",
+    "/quadrantUpperLeftAndLowerRight": "\u259A",
+    "/quadrantUpperLeftAndUpperRightAndLowerLeft": "\u259B",
+    "/quadrantUpperLeftAndUpperRightAndLowerRight": "\u259C",
+    "/quadrantUpperRight": "\u259D",
+    "/quadrantUpperRightAndLowerLeft": "\u259E",
+    "/quadrantUpperRightAndLowerLeftAndLowerRight": "\u259F",
+    "/quadrupleminute": "\u2057",
+    "/quadslashfunc": "\u2341",
+    "/quarternote": "\u2669",
+    "/qubuts": "\u05BB",
+    "/qubuts18": "\u05BB",
+    "/qubuts25": "\u05BB",
+    "/qubuts31": "\u05BB",
+    "/qubuts:hb": "\u05BB",
+    "/qubutshebrew": "\u05BB",
+    "/qubutsnarrowhebrew": "\u05BB",
+    "/qubutsquarterhebrew": "\u05BB",
+    "/qubutswidehebrew": "\u05BB",
+    "/queenblack": "\u265B",
+    "/queenwhite": "\u2655",
+    "/question": "\u003F",
+    "/questionarabic": "\u061F",
+    "/questionarmenian": "\u055E",
+    "/questiondbl": "\u2047",
+    "/questiondown": "\u00BF",
+    "/questiondownsmall": "\uF7BF",
+    "/questionedequal": "\u225F",
+    "/questionexclamationmark": "\u2048",
+    "/questiongreek": "\u037E",
+    "/questionideographiccircled": "\u3244",
+    "/questionmonospace": "\uFF1F",
+    "/questionreversed": "\u2E2E",
+    "/questionsmall": "\uF73F",
+    "/quincunx": "\u26BB",
+    "/quotedbl": "\u0022",
+    "/quotedblbase": "\u201E",
+    "/quotedblleft": "\u201C",
+    "/quotedbllowreversed": "\u2E42",
+    "/quotedblmonospace": "\uFF02",
+    "/quotedblprime": "\u301E",
+    "/quotedblprimereversed": "\u301D",
+    "/quotedblreversed": "\u201F",
+    "/quotedblright": "\u201D",
+    "/quoteleft": "\u2018",
+    "/quoteleftreversed": "\u201B",
+    "/quotequadfunc": "\u235E",
+    "/quotereversed": "\u201B",
+    "/quoteright": "\u2019",
+    "/quoterightn": "\u0149",
+    "/quotesinglbase": "\u201A",
+    "/quotesingle": "\u0027",
+    "/quotesinglemonospace": "\uFF07",
+    "/quoteunderlinefunc": "\u2358",
+    "/r": "\u0072",
+    "/raagung": "\uA9AC",
+    "/raarmenian": "\u057C",
+    "/rabbit": "\u1F407",
+    "/rabbitFace": "\u1F430",
+    "/rabengali": "\u09B0",
+    "/racingCar": "\u1F3CE",
+    "/racingMotorcycle": "\u1F3CD",
+    "/racirclekatakana": "\u32F6",
+    "/racute": "\u0155",
+    "/radeva": "\u0930",
+    "/radfullwidth": "\u33AD",
+    "/radical": "\u221A",
+    "/radicalbottom": "\u23B7",
+    "/radicalex": "\uF8E5",
+    "/radio": "\u1F4FB",
+    "/radioButton": "\u1F518",
+    "/radioactive": "\u2622",
+    "/radovers2fullwidth": "\u33AF",
+    "/radoversfullwidth": "\u33AE",
+    "/radoverssquare": "\u33AE",
+    "/radoverssquaredsquare": "\u33AF",
+    "/radsquare": "\u33AD",
+    "/rafe": "\u05BF",
+    "/rafe:hb": "\u05BF",
+    "/rafehebrew": "\u05BF",
+    "/ragujarati": "\u0AB0",
+    "/ragurmukhi": "\u0A30",
+    "/rahiragana": "\u3089",
+    "/railwayCar": "\u1F683",
+    "/railwayTrack": "\u1F6E4",
+    "/rain": "\u26C6",
+    "/rainbow": "\u1F308",
+    "/raisedHandFingersSplayed": "\u1F590",
+    "/raisedHandPartBetweenMiddleAndRingFingers": "\u1F596",
+    "/raisedmcsign": "\u1F16A",
+    "/raisedmdsign": "\u1F16B",
+    "/rakatakana": "\u30E9",
+    "/rakatakanahalfwidth": "\uFF97",
+    "/ralowerdiagonalbengali": "\u09F1",
+    "/ram": "\u1F40F",
+    "/ramiddlediagonalbengali": "\u09F0",
+    "/ramshorn": "\u0264",
+    "/rat": "\u1F400",
+    "/ratio": "\u2236",
+    "/ray": "\u0608",
+    "/rbopomofo": "\u3116",
+    "/rcaron": "\u0159",
+    "/rcedilla": "\u0157",
+    "/rcircle": "\u24E1",
+    "/rcommaaccent": "\u0157",
+    "/rdblgrave": "\u0211",
+    "/rdot": "\u1E59",
+    "/rdotaccent": "\u1E59",
+    "/rdotbelow": "\u1E5B",
+    "/rdotbelowmacron": "\u1E5D",
+    "/reachideographicparen": "\u3243",
+    "/recirclekatakana": "\u32F9",
+    "/recreationalVehicle": "\u1F699",
+    "/rectangleblack": "\u25AC",
+    "/rectangleverticalblack": "\u25AE",
+    "/rectangleverticalwhite": "\u25AF",
+    "/rectanglewhite": "\u25AD",
+    "/recycledpaper": "\u267C",
+    "/recyclefiveplastics": "\u2677",
+    "/recyclefourplastics": "\u2676",
+    "/recyclegeneric": "\u267A",
+    "/recycleoneplastics": "\u2673",
+    "/recyclepartiallypaper": "\u267D",
+    "/recyclesevenplastics": "\u2679",
+    "/recyclesixplastics": "\u2678",
+    "/recyclethreeplastics": "\u2675",
+    "/recycletwoplastics": "\u2674",
+    "/recycleuniversal": "\u2672",
+    "/recycleuniversalblack": "\u267B",
+    "/redApple": "\u1F34E",
+    "/redTriangleDOwn": "\u1F53B",
+    "/redTriangleUp": "\u1F53A",
+    "/referencemark": "\u203B",
+    "/reflexsubset": "\u2286",
+    "/reflexsuperset": "\u2287",
+    "/regionalindicatorsymbollettera": "\u1F1E6",
+    "/regionalindicatorsymbolletterb": "\u1F1E7",
+    "/regionalindicatorsymbolletterc": "\u1F1E8",
+    "/regionalindicatorsymbolletterd": "\u1F1E9",
+    "/regionalindicatorsymbollettere": "\u1F1EA",
+    "/regionalindicatorsymbolletterf": "\u1F1EB",
+    "/regionalindicatorsymbolletterg": "\u1F1EC",
+    "/regionalindicatorsymbolletterh": "\u1F1ED",
+    "/regionalindicatorsymbolletteri": "\u1F1EE",
+    "/regionalindicatorsymbolletterj": "\u1F1EF",
+    "/regionalindicatorsymbolletterk": "\u1F1F0",
+    "/regionalindicatorsymbolletterl": "\u1F1F1",
+    "/regionalindicatorsymbolletterm": "\u1F1F2",
+    "/regionalindicatorsymbollettern": "\u1F1F3",
+    "/regionalindicatorsymbollettero": "\u1F1F4",
+    "/regionalindicatorsymbolletterp": "\u1F1F5",
+    "/regionalindicatorsymbolletterq": "\u1F1F6",
+    "/regionalindicatorsymbolletterr": "\u1F1F7",
+    "/regionalindicatorsymbolletters": "\u1F1F8",
+    "/regionalindicatorsymbollettert": "\u1F1F9",
+    "/regionalindicatorsymbolletteru": "\u1F1FA",
+    "/regionalindicatorsymbolletterv": "\u1F1FB",
+    "/regionalindicatorsymbolletterw": "\u1F1FC",
+    "/regionalindicatorsymbolletterx": "\u1F1FD",
+    "/regionalindicatorsymbollettery": "\u1F1FE",
+    "/regionalindicatorsymbolletterz": "\u1F1FF",
+    "/registered": "\u00AE",
+    "/registersans": "\uF8E8",
+    "/registerserif": "\uF6DA",
+    "/reh.fina": "\uFEAE",
+    "/reh.init_superscriptalef.fina": "\uFC5C",
+    "/reh.isol": "\uFEAD",
+    "/rehHamzaAbove": "\u076C",
+    "/rehSmallTahTwoDots": "\u0771",
+    "/rehStroke": "\u075B",
+    "/rehTwoDotsVerticallyAbove": "\u076B",
+    "/rehVabove": "\u0692",
+    "/rehVbelow": "\u0695",
+    "/reharabic": "\u0631",
+    "/reharmenian": "\u0580",
+    "/rehdotbelow": "\u0694",
+    "/rehdotbelowdotabove": "\u0696",
+    "/rehfinalarabic": "\uFEAE",
+    "/rehfourdotsabove": "\u0699",
+    "/rehinvertedV": "\u06EF",
+    "/rehiragana": "\u308C",
+    "/rehring": "\u0693",
+    "/rehtwodotsabove": "\u0697",
+    "/rehyehaleflamarabic": "\u0631",
+    "/rekatakana": "\u30EC",
+    "/rekatakanahalfwidth": "\uFF9A",
+    "/relievedFace": "\u1F60C",
+    "/religionideographiccircled": "\u32AA",
+    "/reminderRibbon": "\u1F397",
+    "/remusquare": "\u3355",
+    "/rentogensquare": "\u3356",
+    "/replacementchar": "\uFFFD",
+    "/replacementcharobj": "\uFFFC",
+    "/representideographicparen": "\u3239",
+    "/rerengganleft": "\uA9C1",
+    "/rerengganright": "\uA9C2",
+    "/resh": "\u05E8",
+    "/resh:hb": "\u05E8",
+    "/reshdageshhebrew": "\uFB48",
+    "/reshhatafpatah": "\u05E8",
+    "/reshhatafpatahhebrew": "\u05E8",
+    "/reshhatafsegol": "\u05E8",
+    "/reshhatafsegolhebrew": "\u05E8",
+    "/reshhebrew": "\u05E8",
+    "/reshhiriq": "\u05E8",
+    "/reshhiriqhebrew": "\u05E8",
+    "/reshholam": "\u05E8",
+    "/reshholamhebrew": "\u05E8",
+    "/reshpatah": "\u05E8",
+    "/reshpatahhebrew": "\u05E8",
+    "/reshqamats": "\u05E8",
+    "/reshqamatshebrew": "\u05E8",
+    "/reshqubuts": "\u05E8",
+    "/reshqubutshebrew": "\u05E8",
+    "/reshsegol": "\u05E8",
+    "/reshsegolhebrew": "\u05E8",
+    "/reshsheva": "\u05E8",
+    "/reshshevahebrew": "\u05E8",
+    "/reshtsere": "\u05E8",
+    "/reshtserehebrew": "\u05E8",
+    "/reshwide:hb": "\uFB27",
+    "/reshwithdagesh:hb": "\uFB48",
+    "/resourceideographiccircled": "\u32AE",
+    "/resourceideographicparen": "\u323E",
+    "/response": "\u211F",
+    "/restideographiccircled": "\u32A1",
+    "/restideographicparen": "\u3241",
+    "/restrictedentryoneleft": "\u26E0",
+    "/restrictedentrytwoleft": "\u26E1",
+    "/restroom": "\u1F6BB",
+    "/return": "\u23CE",
+    "/reversedHandMiddleFingerExtended": "\u1F595",
+    "/reversedRaisedHandFingersSplayed": "\u1F591",
+    "/reversedThumbsDownSign": "\u1F593",
+    "/reversedThumbsUpSign": "\u1F592",
+    "/reversedVictoryHand": "\u1F594",
+    "/reversedonehundred.roman": "\u2183",
+    "/reversedtilde": "\u223D",
+    "/reversedzecyr": "\u0511",
+    "/revia:hb": "\u0597",
+    "/reviahebrew": "\u0597",
+    "/reviamugrashhebrew": "\u0597",
+    "/revlogicalnot": "\u2310",
+    "/revolvingHearts": "\u1F49E",
+    "/rfishhook": "\u027E",
+    "/rfishhookreversed": "\u027F",
+    "/rgravedbl": "\u0211",
+    "/rhabengali": "\u09DD",
+    "/rhacyr": "\u0517",
+    "/rhadeva": "\u095D",
+    "/rho": "\u03C1",
+    "/rhoasper": "\u1FE5",
+    "/rhofunc": "\u2374",
+    "/rholenis": "\u1FE4",
+    "/rhook": "\u027D",
+    "/rhookturned": "\u027B",
+    "/rhookturnedsuperior": "\u02B5",
+    "/rhookturnedsupmod": "\u02B5",
+    "/rhostrokesymbol": "\u03FC",
+    "/rhosymbol": "\u03F1",
+    "/rhosymbolgreek": "\u03F1",
+    "/rhotichookmod": "\u02DE",
+    "/rial": "\uFDFC",
+    "/ribbon": "\u1F380",
+    "/riceBall": "\u1F359",
+    "/riceCracker": "\u1F358",
+    "/ricirclekatakana": "\u32F7",
+    "/rieulacirclekorean": "\u3271",
+    "/rieulaparenkorean": "\u3211",
+    "/rieulcirclekorean": "\u3263",
+    "/rieulhieuhkorean": "\u3140",
+    "/rieulkiyeokkorean": "\u313A",
+    "/rieulkiyeoksioskorean": "\u3169",
+    "/rieulkorean": "\u3139",
+    "/rieulmieumkorean": "\u313B",
+    "/rieulpansioskorean": "\u316C",
+    "/rieulparenkorean": "\u3203",
+    "/rieulphieuphkorean": "\u313F",
+    "/rieulpieupkorean": "\u313C",
+    "/rieulpieupsioskorean": "\u316B",
+    "/rieulsioskorean": "\u313D",
+    "/rieulthieuthkorean": "\u313E",
+    "/rieultikeutkorean": "\u316A",
+    "/rieulyeorinhieuhkorean": "\u316D",
+    "/right-pointingMagnifyingGlass": "\u1F50E",
+    "/rightAngerBubble": "\u1F5EF",
+    "/rightHalfBlock": "\u2590",
+    "/rightHandTelephoneReceiver": "\u1F57D",
+    "/rightOneEighthBlock": "\u2595",
+    "/rightSpeaker": "\u1F568",
+    "/rightSpeakerOneSoundWave": "\u1F569",
+    "/rightSpeakerThreeSoundWaves": "\u1F56A",
+    "/rightSpeechBubble": "\u1F5E9",
+    "/rightThoughtBubble": "\u1F5ED",
+    "/rightangle": "\u221F",
+    "/rightarrowoverleftarrow": "\u21C4",
+    "/rightdnheavyleftuplight": "\u2546",
+    "/rightharpoonoverleftharpoon": "\u21CC",
+    "/rightheavyleftdnlight": "\u252E",
+    "/rightheavyleftuplight": "\u2536",
+    "/rightheavyleftvertlight": "\u253E",
+    "/rightideographiccircled": "\u32A8",
+    "/rightlightleftdnheavy": "\u2531",
+    "/rightlightleftupheavy": "\u2539",
+    "/rightlightleftvertheavy": "\u2549",
+    "/righttackbelowcmb": "\u0319",
+    "/righttoleftembed": "\u202B",
+    "/righttoleftisolate": "\u2067",
+    "/righttoleftmark": "\u200F",
+    "/righttoleftoverride": "\u202E",
+    "/righttriangle": "\u22BF",
+    "/rightupheavyleftdnlight": "\u2544",
+    "/rihiragana": "\u308A",
+    "/rikatakana": "\u30EA",
+    "/rikatakanahalfwidth": "\uFF98",
+    "/ring": "\u02DA",
+    "/ringbelowcmb": "\u0325",
+    "/ringcmb": "\u030A",
+    "/ringequal": "\u2257",
+    "/ringhalfleft": "\u02BF",
+    "/ringhalfleftarmenian": "\u0559",
+    "/ringhalfleftbelowcmb": "\u031C",
+    "/ringhalfleftcentered": "\u02D3",
+    "/ringhalfleftcentredmod": "\u02D3",
+    "/ringhalfleftmod": "\u02BF",
+    "/ringhalfright": "\u02BE",
+    "/ringhalfrightbelowcmb": "\u0339",
+    "/ringhalfrightcentered": "\u02D2",
+    "/ringhalfrightcentredmod": "\u02D2",
+    "/ringhalfrightmod": "\u02BE",
+    "/ringinequal": "\u2256",
+    "/ringingBell": "\u1F56D",
+    "/ringlowmod": "\u02F3",
+    "/ringoperator": "\u2218",
+    "/rinsular": "\uA783",
+    "/rinvertedbreve": "\u0213",
+    "/rirasquare": "\u3352",
+    "/risingdiagonal": "\u27CB",
+    "/rittorusquare": "\u3351",
+    "/rlinebelow": "\u1E5F",
+    "/rlongleg": "\u027C",
+    "/rlonglegturned": "\u027A",
+    "/rmacrondot": "\u1E5D",
+    "/rmonospace": "\uFF52",
+    "/rnoon": "\u06BB",
+    "/rnoon.fina": "\uFBA1",
+    "/rnoon.init": "\uFBA2",
+    "/rnoon.isol": "\uFBA0",
+    "/rnoon.medi": "\uFBA3",
+    "/roastedSweetPotato": "\u1F360",
+    "/robliquestroke": "\uA7A7",
+    "/rocirclekatakana": "\u32FA",
+    "/rocket": "\u1F680",
+    "/rohiragana": "\u308D",
+    "/rokatakana": "\u30ED",
+    "/rokatakanahalfwidth": "\uFF9B",
+    "/rolled-upNewspaper": "\u1F5DE",
+    "/rollerCoaster": "\u1F3A2",
+    "/rookblack": "\u265C",
+    "/rookwhite": "\u2656",
+    "/rooster": "\u1F413",
+    "/roruathai": "\u0E23",
+    "/rose": "\u1F339",
+    "/rosette": "\u1F3F5",
+    "/roundPushpin": "\u1F4CD",
+    "/roundedzeroabove": "\u06DF",
+    "/rowboat": "\u1F6A3",
+    "/rparen": "\u24AD",
+    "/rparenthesized": "\u24AD",
+    "/rrabengali": "\u09DC",
+    "/rradeva": "\u0931",
+    "/rragurmukhi": "\u0A5C",
+    "/rreh": "\u0691",
+    "/rreh.fina": "\uFB8D",
+    "/rreh.isol": "\uFB8C",
+    "/rreharabic": "\u0691",
+    "/rrehfinalarabic": "\uFB8D",
+    "/rrotunda": "\uA75B",
+    "/rrvocalicbengali": "\u09E0",
+    "/rrvocalicdeva": "\u0960",
+    "/rrvocalicgujarati": "\u0AE0",
+    "/rrvocalicvowelsignbengali": "\u09C4",
+    "/rrvocalicvowelsigndeva": "\u0944",
+    "/rrvocalicvowelsigngujarati": "\u0AC4",
+    "/rstroke": "\u024D",
+    "/rsuperior": "\uF6F1",
+    "/rsupmod": "\u02B3",
+    "/rtailturned": "\u2C79",
+    "/rtblock": "\u2590",
+    "/rturned": "\u0279",
+    "/rturnedsuperior": "\u02B4",
+    "/rturnedsupmod": "\u02B4",
+    "/ruble": "\u20BD",
+    "/rucirclekatakana": "\u32F8",
+    "/rugbyFootball": "\u1F3C9",
+    "/ruhiragana": "\u308B",
+    "/rukatakana": "\u30EB",
+    "/rukatakanahalfwidth": "\uFF99",
+    "/rum": "\uA775",
+    "/rumrotunda": "\uA75D",
+    "/runner": "\u1F3C3",
+    "/runningShirtSash": "\u1F3BD",
+    "/rupeemarkbengali": "\u09F2",
+    "/rupeesignbengali": "\u09F3",
+    "/rupiah": "\uF6DD",
+    "/rupiisquare": "\u3353",
+    "/ruthai": "\u0E24",
+    "/ruuburusquare": "\u3354",
+    "/rvocalicbengali": "\u098B",
+    "/rvocalicdeva": "\u090B",
+    "/rvocalicgujarati": "\u0A8B",
+    "/rvocalicvowelsignbengali": "\u09C3",
+    "/rvocalicvowelsigndeva": "\u0943",
+    "/rvocalicvowelsigngujarati": "\u0AC3",
+    "/s": "\u0073",
+    "/s.inferior": "\u209B",
+    "/s_t": "\uFB06",
+    "/sabengali": "\u09B8",
+    "/sacirclekatakana": "\u32DA",
+    "/sacute": "\u015B",
+    "/sacutedotaccent": "\u1E65",
+    "/sad": "\u0635",
+    "/sad.fina": "\uFEBA",
+    "/sad.init": "\uFEBB",
+    "/sad.init_alefmaksura.fina": "\uFD05",
+    "/sad.init_hah.fina": "\uFC20",
+    "/sad.init_hah.medi": "\uFCB1",
+    "/sad.init_hah.medi_hah.medi": "\uFD65",
+    "/sad.init_khah.medi": "\uFCB2",
+    "/sad.init_meem.fina": "\uFC21",
+    "/sad.init_meem.medi": "\uFCB3",
+    "/sad.init_meem.medi_meem.medi": "\uFDC5",
+    "/sad.init_reh.fina": "\uFD0F",
+    "/sad.init_yeh.fina": "\uFD06",
+    "/sad.isol": "\uFEB9",
+    "/sad.medi": "\uFEBC",
+    "/sad.medi_alefmaksura.fina": "\uFD21",
+    "/sad.medi_hah.medi_hah.fina": "\uFD64",
+    "/sad.medi_hah.medi_yeh.fina": "\uFDA9",
+    "/sad.medi_meem.medi_meem.fina": "\uFD66",
+    "/sad.medi_reh.fina": "\uFD2B",
+    "/sad.medi_yeh.fina": "\uFD22",
+    "/sad_lam_alefmaksuraabove": "\u06D6",
+    "/sadarabic": "\u0635",
+    "/sadeva": "\u0938",
+    "/sadfinalarabic": "\uFEBA",
+    "/sadinitialarabic": "\uFEBB",
+    "/sadmedialarabic": "\uFEBC",
+    "/sadthreedotsabove": "\u069E",
+    "/sadtwodotsbelow": "\u069D",
+    "/sagittarius": "\u2650",
+    "/sagujarati": "\u0AB8",
+    "/sagurmukhi": "\u0A38",
+    "/sahiragana": "\u3055",
+    "/saikurusquare": "\u331F",
+    "/sailboat": "\u26F5",
+    "/sakatakana": "\u30B5",
+    "/sakatakanahalfwidth": "\uFF7B",
+    "/sakeBottleAndCup": "\u1F376",
+    "/sallallahoualayhewasallamarabic": "\uFDFA",
+    "/saltillo": "\uA78C",
+    "/saltire": "\u2613",
+    "/samahaprana": "\uA9B0",
+    "/samekh": "\u05E1",
+    "/samekh:hb": "\u05E1",
+    "/samekhdagesh": "\uFB41",
+    "/samekhdageshhebrew": "\uFB41",
+    "/samekhhebrew": "\u05E1",
+    "/samekhwithdagesh:hb": "\uFB41",
+    "/sampi": "\u03E1",
+    "/sampiarchaic": "\u0373",
+    "/samurda": "\uA9AF",
+    "/samvat": "\u0604",
+    "/san": "\u03FB",
+    "/santiimusquare": "\u3320",
+    "/saraaathai": "\u0E32",
+    "/saraaethai": "\u0E41",
+    "/saraaimaimalaithai": "\u0E44",
+    "/saraaimaimuanthai": "\u0E43",
+    "/saraamthai": "\u0E33",
+    "/saraathai": "\u0E30",
+    "/saraethai": "\u0E40",
+    "/saraiileftthai": "\uF886",
+    "/saraiithai": "\u0E35",
+    "/saraileftthai": "\uF885",
+    "/saraithai": "\u0E34",
+    "/saraothai": "\u0E42",
+    "/saraueeleftthai": "\uF888",
+    "/saraueethai": "\u0E37",
+    "/saraueleftthai": "\uF887",
+    "/sarauethai": "\u0E36",
+    "/sarauthai": "\u0E38",
+    "/sarauuthai": "\u0E39",
+    "/satellite": "\u1F6F0",
+    "/satelliteAntenna": "\u1F4E1",
+    "/saturn": "\u2644",
+    "/saxophone": "\u1F3B7",
+    "/sbopomofo": "\u3119",
+    "/scales": "\u2696",
+    "/scanninehorizontal": "\u23BD",
+    "/scanonehorizontal": "\u23BA",
+    "/scansevenhorizontal": "\u23BC",
+    "/scanthreehorizontal": "\u23BB",
+    "/scaron": "\u0161",
+    "/scarondot": "\u1E67",
+    "/scarondotaccent": "\u1E67",
+    "/scedilla": "\u015F",
+    "/school": "\u1F3EB",
+    "/schoolSatchel": "\u1F392",
+    "/schoolideographiccircled": "\u3246",
+    "/schwa": "\u0259",
+    "/schwa.inferior": "\u2094",
+    "/schwacyr": "\u04D9",
+    "/schwacyrillic": "\u04D9",
+    "/schwadieresiscyr": "\u04DB",
+    "/schwadieresiscyrillic": "\u04DB",
+    "/schwahook": "\u025A",
+    "/scircle": "\u24E2",
+    "/scircumflex": "\u015D",
+    "/scommaaccent": "\u0219",
+    "/scooter": "\u1F6F4",
+    "/scorpius": "\u264F",
+    "/screen": "\u1F5B5",
+    "/scroll": "\u1F4DC",
+    "/scruple": "\u2108",
+    "/sdot": "\u1E61",
+    "/sdotaccent": "\u1E61",
+    "/sdotbelow": "\u1E63",
+    "/sdotbelowdotabove": "\u1E69",
+    "/sdotbelowdotaccent": "\u1E69",
+    "/seagullbelowcmb": "\u033C",
+    "/seat": "\u1F4BA",
+    "/secirclekatakana": "\u32DD",
+    "/second": "\u2033",
+    "/secondreversed": "\u2036",
+    "/secondscreensquare": "\u1F19C",
+    "/secondtonechinese": "\u02CA",
+    "/secretideographiccircled": "\u3299",
+    "/section": "\u00A7",
+    "/sectionsignhalftop": "\u2E39",
+    "/sector": "\u2314",
+    "/seeNoEvilMonkey": "\u1F648",
+    "/seedling": "\u1F331",
+    "/seen": "\u0633",
+    "/seen.fina": "\uFEB2",
+    "/seen.init": "\uFEB3",
+    "/seen.init_alefmaksura.fina": "\uFCFB",
+    "/seen.init_hah.fina": "\uFC1D",
+    "/seen.init_hah.medi": "\uFCAE",
+    "/seen.init_hah.medi_jeem.medi": "\uFD5C",
+    "/seen.init_heh.medi": "\uFD31",
+    "/seen.init_jeem.fina": "\uFC1C",
+    "/seen.init_jeem.medi": "\uFCAD",
+    "/seen.init_jeem.medi_hah.medi": "\uFD5D",
+    "/seen.init_khah.fina": "\uFC1E",
+    "/seen.init_khah.medi": "\uFCAF",
+    "/seen.init_meem.fina": "\uFC1F",
+    "/seen.init_meem.medi": "\uFCB0",
+    "/seen.init_meem.medi_hah.medi": "\uFD60",
+    "/seen.init_meem.medi_jeem.medi": "\uFD61",
+    "/seen.init_meem.medi_meem.medi": "\uFD63",
+    "/seen.init_reh.fina": "\uFD0E",
+    "/seen.init_yeh.fina": "\uFCFC",
+    "/seen.isol": "\uFEB1",
+    "/seen.medi": "\uFEB4",
+    "/seen.medi_alefmaksura.fina": "\uFD17",
+    "/seen.medi_hah.medi": "\uFD35",
+    "/seen.medi_heh.medi": "\uFCE8",
+    "/seen.medi_jeem.medi": "\uFD34",
+    "/seen.medi_jeem.medi_alefmaksura.fina": "\uFD5E",
+    "/seen.medi_khah.medi": "\uFD36",
+    "/seen.medi_khah.medi_alefmaksura.fina": "\uFDA8",
+    "/seen.medi_khah.medi_yeh.fina": "\uFDC6",
+    "/seen.medi_meem.medi": "\uFCE7",
+    "/seen.medi_meem.medi_hah.fina": "\uFD5F",
+    "/seen.medi_meem.medi_meem.fina": "\uFD62",
+    "/seen.medi_reh.fina": "\uFD2A",
+    "/seen.medi_yeh.fina": "\uFD18",
+    "/seenDigitFourAbove": "\u077D",
+    "/seenFourDotsAbove": "\u075C",
+    "/seenInvertedV": "\u077E",
+    "/seenSmallTahTwoDots": "\u0770",
+    "/seenTwoDotsVerticallyAbove": "\u076D",
+    "/seenabove": "\u06DC",
+    "/seenarabic": "\u0633",
+    "/seendotbelowdotabove": "\u069A",
+    "/seenfinalarabic": "\uFEB2",
+    "/seeninitialarabic": "\uFEB3",
+    "/seenlow": "\u06E3",
+    "/seenmedialarabic": "\uFEB4",
+    "/seenthreedotsbelow": "\u069B",
+    "/seenthreedotsbelowthreedotsabove": "\u069C",
+    "/segment": "\u2313",
+    "/segol": "\u05B6",
+    "/segol13": "\u05B6",
+    "/segol1f": "\u05B6",
+    "/segol2c": "\u05B6",
+    "/segol:hb": "\u05B6",
+    "/segolhebrew": "\u05B6",
+    "/segolnarrowhebrew": "\u05B6",
+    "/segolquarterhebrew": "\u05B6",
+    "/segolta:hb": "\u0592",
+    "/segoltahebrew": "\u0592",
+    "/segolwidehebrew": "\u05B6",
+    "/seharmenian": "\u057D",
+    "/sehiragana": "\u305B",
+    "/sekatakana": "\u30BB",
+    "/sekatakanahalfwidth": "\uFF7E",
+    "/selfideographicparen": "\u3242",
+    "/semicolon": "\u003B",
+    "/semicolonarabic": "\u061B",
+    "/semicolonmonospace": "\uFF1B",
+    "/semicolonreversed": "\u204F",
+    "/semicolonsmall": "\uFE54",
+    "/semicolonunderlinefunc": "\u236E",
+    "/semidirectproductleft": "\u22CB",
+    "/semidirectproductright": "\u22CC",
+    "/semisextile": "\u26BA",
+    "/semisoftcyr": "\u048D",
+    "/semivoicedmarkkana": "\u309C",
+    "/semivoicedmarkkanahalfwidth": "\uFF9F",
+    "/sentisquare": "\u3322",
+    "/sentosquare": "\u3323",
+    "/septembertelegraph": "\u32C8",
+    "/sersetdblup": "\u22D1",
+    "/sersetnotequalup": "\u228B",
+    "/servicemark": "\u2120",
+    "/sesamedot": "\uFE45",
+    "/sesquiquadrate": "\u26BC",
+    "/setminus": "\u2216",
+    "/seven": "\u0037",
+    "/seven.inferior": "\u2087",
+    "/seven.roman": "\u2166",
+    "/seven.romansmall": "\u2176",
+    "/seven.superior": "\u2077",
+    "/sevenarabic": "\u0667",
+    "/sevenbengali": "\u09ED",
+    "/sevencircle": "\u2466",
+    "/sevencircledbl": "\u24FB",
+    "/sevencircleinversesansserif": "\u2790",
+    "/sevencomma": "\u1F108",
+    "/sevendeva": "\u096D",
+    "/seveneighths": "\u215E",
+    "/sevenfar": "\u06F7",
+    "/sevengujarati": "\u0AED",
+    "/sevengurmukhi": "\u0A6D",
+    "/sevenhackarabic": "\u0667",
+    "/sevenhangzhou": "\u3027",
+    "/sevenideographiccircled": "\u3286",
+    "/sevenideographicparen": "\u3226",
+    "/seveninferior": "\u2087",
+    "/sevenmonospace": "\uFF17",
+    "/sevenoldstyle": "\uF737",
+    "/sevenparen": "\u247A",
+    "/sevenparenthesized": "\u247A",
+    "/sevenperiod": "\u248E",
+    "/sevenpersian": "\u06F7",
+    "/sevenpointonesquare": "\u1F1A1",
+    "/sevenroman": "\u2176",
+    "/sevensuperior": "\u2077",
+    "/seventeencircle": "\u2470",
+    "/seventeencircleblack": "\u24F1",
+    "/seventeenparen": "\u2484",
+    "/seventeenparenthesized": "\u2484",
+    "/seventeenperiod": "\u2498",
+    "/seventhai": "\u0E57",
+    "/seventycirclesquare": "\u324E",
+    "/sextile": "\u26B9",
+    "/sfthyphen": "\u00AD",
+    "/shaarmenian": "\u0577",
+    "/shabengali": "\u09B6",
+    "/shacyr": "\u0448",
+    "/shacyrillic": "\u0448",
+    "/shaddaAlefIsol": "\uFC63",
+    "/shaddaDammaIsol": "\uFC61",
+    "/shaddaDammaMedi": "\uFCF3",
+    "/shaddaDammatanIsol": "\uFC5E",
+    "/shaddaFathaIsol": "\uFC60",
+    "/shaddaFathaMedi": "\uFCF2",
+    "/shaddaIsol": "\uFE7C",
+    "/shaddaKasraIsol": "\uFC62",
+    "/shaddaKasraMedi": "\uFCF4",
+    "/shaddaKasratanIsol": "\uFC5F",
+    "/shaddaMedi": "\uFE7D",
+    "/shaddaarabic": "\u0651",
+    "/shaddadammaarabic": "\uFC61",
+    "/shaddadammatanarabic": "\uFC5E",
+    "/shaddafathaarabic": "\uFC60",
+    "/shaddafathatanarabic": "\u0651",
+    "/shaddakasraarabic": "\uFC62",
+    "/shaddakasratanarabic": "\uFC5F",
+    "/shade": "\u2592",
+    "/shadedark": "\u2593",
+    "/shadelight": "\u2591",
+    "/shademedium": "\u2592",
+    "/shadeva": "\u0936",
+    "/shagujarati": "\u0AB6",
+    "/shagurmukhi": "\u0A36",
+    "/shalshelet:hb": "\u0593",
+    "/shalshelethebrew": "\u0593",
+    "/shamrock": "\u2618",
+    "/shavedIce": "\u1F367",
+    "/shbopomofo": "\u3115",
+    "/shchacyr": "\u0449",
+    "/shchacyrillic": "\u0449",
+    "/sheen": "\u0634",
+    "/sheen.fina": "\uFEB6",
+    "/sheen.init": "\uFEB7",
+    "/sheen.init_alefmaksura.fina": "\uFCFD",
+    "/sheen.init_hah.fina": "\uFD0A",
+    "/sheen.init_hah.medi": "\uFD2E",
+    "/sheen.init_hah.medi_meem.medi": "\uFD68",
+    "/sheen.init_heh.medi": "\uFD32",
+    "/sheen.init_jeem.fina": "\uFD09",
+    "/sheen.init_jeem.medi": "\uFD2D",
+    "/sheen.init_khah.fina": "\uFD0B",
+    "/sheen.init_khah.medi": "\uFD2F",
+    "/sheen.init_meem.fina": "\uFD0C",
+    "/sheen.init_meem.medi": "\uFD30",
+    "/sheen.init_meem.medi_khah.medi": "\uFD6B",
+    "/sheen.init_meem.medi_meem.medi": "\uFD6D",
+    "/sheen.init_reh.fina": "\uFD0D",
+    "/sheen.init_yeh.fina": "\uFCFE",
+    "/sheen.isol": "\uFEB5",
+    "/sheen.medi": "\uFEB8",
+    "/sheen.medi_alefmaksura.fina": "\uFD19",
+    "/sheen.medi_hah.fina": "\uFD26",
+    "/sheen.medi_hah.medi": "\uFD38",
+    "/sheen.medi_hah.medi_meem.fina": "\uFD67",
+    "/sheen.medi_hah.medi_yeh.fina": "\uFDAA",
+    "/sheen.medi_heh.medi": "\uFCEA",
+    "/sheen.medi_jeem.fina": "\uFD25",
+    "/sheen.medi_jeem.medi": "\uFD37",
+    "/sheen.medi_jeem.medi_yeh.fina": "\uFD69",
+    "/sheen.medi_khah.fina": "\uFD27",
+    "/sheen.medi_khah.medi": "\uFD39",
+    "/sheen.medi_meem.fina": "\uFD28",
+    "/sheen.medi_meem.medi": "\uFCE9",
+    "/sheen.medi_meem.medi_khah.fina": "\uFD6A",
+    "/sheen.medi_meem.medi_meem.fina": "\uFD6C",
+    "/sheen.medi_reh.fina": "\uFD29",
+    "/sheen.medi_yeh.fina": "\uFD1A",
+    "/sheenarabic": "\u0634",
+    "/sheendotbelow": "\u06FA",
+    "/sheenfinalarabic": "\uFEB6",
+    "/sheeninitialarabic": "\uFEB7",
+    "/sheenmedialarabic": "\uFEB8",
+    "/sheep": "\u1F411",
+    "/sheicoptic": "\u03E3",
+    "/shelfmod": "\u02FD",
+    "/shelfopenmod": "\u02FE",
+    "/sheqel": "\u20AA",
+    "/sheqelhebrew": "\u20AA",
+    "/sheva": "\u05B0",
+    "/sheva115": "\u05B0",
+    "/sheva15": "\u05B0",
+    "/sheva22": "\u05B0",
+    "/sheva2e": "\u05B0",
+    "/sheva:hb": "\u05B0",
+    "/shevahebrew": "\u05B0",
+    "/shevanarrowhebrew": "\u05B0",
+    "/shevaquarterhebrew": "\u05B0",
+    "/shevawidehebrew": "\u05B0",
+    "/shhacyr": "\u04BB",
+    "/shhacyrillic": "\u04BB",
+    "/shhatailcyr": "\u0527",
+    "/shield": "\u1F6E1",
+    "/shimacoptic": "\u03ED",
+    "/shin": "\u05E9",
+    "/shin:hb": "\u05E9",
+    "/shinDot:hb": "\u05C1",
+    "/shindagesh": "\uFB49",
+    "/shindageshhebrew": "\uFB49",
+    "/shindageshshindot": "\uFB2C",
+    "/shindageshshindothebrew": "\uFB2C",
+    "/shindageshsindot": "\uFB2D",
+    "/shindageshsindothebrew": "\uFB2D",
+    "/shindothebrew": "\u05C1",
+    "/shinhebrew": "\u05E9",
+    "/shinshindot": "\uFB2A",
+    "/shinshindothebrew": "\uFB2A",
+    "/shinsindot": "\uFB2B",
+    "/shinsindothebrew": "\uFB2B",
+    "/shintoshrine": "\u26E9",
+    "/shinwithdagesh:hb": "\uFB49",
+    "/shinwithdageshandshinDot:hb": "\uFB2C",
+    "/shinwithdageshandsinDot:hb": "\uFB2D",
+    "/shinwithshinDot:hb": "\uFB2A",
+    "/shinwithsinDot:hb": "\uFB2B",
+    "/ship": "\u1F6A2",
+    "/sho": "\u03F8",
+    "/shoejotupfunc": "\u235D",
+    "/shoestiledownfunc": "\u2366",
+    "/shoestileleftfunc": "\u2367",
+    "/shogipieceblack": "\u2617",
+    "/shogipiecewhite": "\u2616",
+    "/shook": "\u0282",
+    "/shootingStar": "\u1F320",
+    "/shoppingBags": "\u1F6CD",
+    "/shoppingTrolley": "\u1F6D2",
+    "/shortcake": "\u1F370",
+    "/shortequalsmod": "\uA78A",
+    "/shortoverlongmetrical": "\u23D3",
+    "/shoulderedopenbox": "\u237D",
+    "/shower": "\u1F6BF",
+    "/shvsquare": "\u1F1AA",
+    "/sicirclekatakana": "\u32DB",
+    "/sidewaysBlackDownPointingIndex": "\u1F5A1",
+    "/sidewaysBlackLeftPointingIndex": "\u1F59A",
+    "/sidewaysBlackRightPointingIndex": "\u1F59B",
+    "/sidewaysBlackUpPointingIndex": "\u1F5A0",
+    "/sidewaysWhiteDownPointingIndex": "\u1F59F",
+    "/sidewaysWhiteLeftPointingIndex": "\u1F598",
+    "/sidewaysWhiteRightPointingIndex": "\u1F599",
+    "/sidewaysWhiteUpPointingIndex": "\u1F59E",
+    "/sigma": "\u03C3",
+    "/sigma1": "\u03C2",
+    "/sigmafinal": "\u03C2",
+    "/sigmalunatedottedreversedsymbol": "\u037D",
+    "/sigmalunatedottedsymbol": "\u037C",
+    "/sigmalunatereversedsymbol": "\u037B",
+    "/sigmalunatesymbol": "\u03F2",
+    "/sigmalunatesymbolgreek": "\u03F2",
+    "/sihiragana": "\u3057",
+    "/sikatakana": "\u30B7",
+    "/sikatakanahalfwidth": "\uFF7C",
+    "/silhouetteOfJapan": "\u1F5FE",
+    "/siluqhebrew": "\u05BD",
+    "/siluqlefthebrew": "\u05BD",
+    "/similar": "\u223C",
+    "/sinDot:hb": "\u05C2",
+    "/sindothebrew": "\u05C2",
+    "/sinewave": "\u223F",
+    "/sinh:a": "\u0D85",
+    "/sinh:aa": "\u0D86",
+    "/sinh:aae": "\u0D88",
+    "/sinh:aaesign": "\u0DD1",
+    "/sinh:aasign": "\u0DCF",
+    "/sinh:ae": "\u0D87",
+    "/sinh:aesign": "\u0DD0",
+    "/sinh:ai": "\u0D93",
+    "/sinh:aisign": "\u0DDB",
+    "/sinh:anusvara": "\u0D82",
+    "/sinh:au": "\u0D96",
+    "/sinh:ausign": "\u0DDE",
+    "/sinh:ba": "\u0DB6",
+    "/sinh:bha": "\u0DB7",
+    "/sinh:ca": "\u0DA0",
+    "/sinh:cha": "\u0DA1",
+    "/sinh:da": "\u0DAF",
+    "/sinh:dda": "\u0DA9",
+    "/sinh:ddha": "\u0DAA",
+    "/sinh:dha": "\u0DB0",
+    "/sinh:e": "\u0D91",
+    "/sinh:ee": "\u0D92",
+    "/sinh:eesign": "\u0DDA",
+    "/sinh:esign": "\u0DD9",
+    "/sinh:fa": "\u0DC6",
+    "/sinh:ga": "\u0D9C",
+    "/sinh:gha": "\u0D9D",
+    "/sinh:ha": "\u0DC4",
+    "/sinh:i": "\u0D89",
+    "/sinh:ii": "\u0D8A",
+    "/sinh:iisign": "\u0DD3",
+    "/sinh:isign": "\u0DD2",
+    "/sinh:ja": "\u0DA2",
+    "/sinh:jha": "\u0DA3",
+    "/sinh:jnya": "\u0DA5",
+    "/sinh:ka": "\u0D9A",
+    "/sinh:kha": "\u0D9B",
+    "/sinh:kunddaliya": "\u0DF4",
+    "/sinh:la": "\u0DBD",
+    "/sinh:litheight": "\u0DEE",
+    "/sinh:lithfive": "\u0DEB",
+    "/sinh:lithfour": "\u0DEA",
+    "/sinh:lithnine": "\u0DEF",
+    "/sinh:lithone": "\u0DE7",
+    "/sinh:lithseven": "\u0DED",
+    "/sinh:lithsix": "\u0DEC",
+    "/sinh:liththree": "\u0DE9",
+    "/sinh:lithtwo": "\u0DE8",
+    "/sinh:lithzero": "\u0DE6",
+    "/sinh:lla": "\u0DC5",
+    "/sinh:llvocal": "\u0D90",
+    "/sinh:llvocalsign": "\u0DF3",
+    "/sinh:lvocal": "\u0D8F",
+    "/sinh:lvocalsign": "\u0DDF",
+    "/sinh:ma": "\u0DB8",
+    "/sinh:mba": "\u0DB9",
+    "/sinh:na": "\u0DB1",
+    "/sinh:nda": "\u0DB3",
+    "/sinh:nga": "\u0D9E",
+    "/sinh:nna": "\u0DAB",
+    "/sinh:nndda": "\u0DAC",
+    "/sinh:nnga": "\u0D9F",
+    "/sinh:nya": "\u0DA4",
+    "/sinh:nyja": "\u0DA6",
+    "/sinh:o": "\u0D94",
+    "/sinh:oo": "\u0D95",
+    "/sinh:oosign": "\u0DDD",
+    "/sinh:osign": "\u0DDC",
+    "/sinh:pa": "\u0DB4",
+    "/sinh:pha": "\u0DB5",
+    "/sinh:ra": "\u0DBB",
+    "/sinh:rrvocal": "\u0D8E",
+    "/sinh:rrvocalsign": "\u0DF2",
+    "/sinh:rvocal": "\u0D8D",
+    "/sinh:rvocalsign": "\u0DD8",
+    "/sinh:sa": "\u0DC3",
+    "/sinh:sha": "\u0DC1",
+    "/sinh:ssa": "\u0DC2",
+    "/sinh:ta": "\u0DAD",
+    "/sinh:tha": "\u0DAE",
+    "/sinh:tta": "\u0DA7",
+    "/sinh:ttha": "\u0DA8",
+    "/sinh:u": "\u0D8B",
+    "/sinh:usign": "\u0DD4",
+    "/sinh:uu": "\u0D8C",
+    "/sinh:uusign": "\u0DD6",
+    "/sinh:va": "\u0DC0",
+    "/sinh:virama": "\u0DCA",
+    "/sinh:visarga": "\u0D83",
+    "/sinh:ya": "\u0DBA",
+    "/sinologicaldot": "\uA78F",
+    "/sinsular": "\uA785",
+    "/siosacirclekorean": "\u3274",
+    "/siosaparenkorean": "\u3214",
+    "/sioscieuckorean": "\u317E",
+    "/sioscirclekorean": "\u3266",
+    "/sioskiyeokkorean": "\u317A",
+    "/sioskorean": "\u3145",
+    "/siosnieunkorean": "\u317B",
+    "/siosparenkorean": "\u3206",
+    "/siospieupkorean": "\u317D",
+    "/siostikeutkorean": "\u317C",
+    "/siringusquare": "\u3321",
+    "/six": "\u0036",
+    "/six.inferior": "\u2086",
+    "/six.roman": "\u2165",
+    "/six.romansmall": "\u2175",
+    "/six.superior": "\u2076",
+    "/sixPointedStarMiddleDot": "\u1F52F",
+    "/sixarabic": "\u0666",
+    "/sixbengali": "\u09EC",
+    "/sixcircle": "\u2465",
+    "/sixcircledbl": "\u24FA",
+    "/sixcircleinversesansserif": "\u278F",
+    "/sixcomma": "\u1F107",
+    "/sixdeva": "\u096C",
+    "/sixdotsvertical": "\u2E3D",
+    "/sixfar": "\u06F6",
+    "/sixgujarati": "\u0AEC",
+    "/sixgurmukhi": "\u0A6C",
+    "/sixhackarabic": "\u0666",
+    "/sixhangzhou": "\u3026",
+    "/sixideographiccircled": "\u3285",
+    "/sixideographicparen": "\u3225",
+    "/sixinferior": "\u2086",
+    "/sixlateform.roman": "\u2185",
+    "/sixmonospace": "\uFF16",
+    "/sixoldstyle": "\uF736",
+    "/sixparen": "\u2479",
+    "/sixparenthesized": "\u2479",
+    "/sixperemspace": "\u2006",
+    "/sixperiod": "\u248D",
+    "/sixpersian": "\u06F6",
+    "/sixroman": "\u2175",
+    "/sixsuperior": "\u2076",
+    "/sixteencircle": "\u246F",
+    "/sixteencircleblack": "\u24F0",
+    "/sixteencurrencydenominatorbengali": "\u09F9",
+    "/sixteenparen": "\u2483",
+    "/sixteenparenthesized": "\u2483",
+    "/sixteenperiod": "\u2497",
+    "/sixthai": "\u0E56",
+    "/sixtycirclesquare": "\u324D",
+    "/sixtypsquare": "\u1F1A3",
+    "/sjekomicyr": "\u050D",
+    "/skiAndSkiBoot": "\u1F3BF",
+    "/skier": "\u26F7",
+    "/skull": "\u1F480",
+    "/skullcrossbones": "\u2620",
+    "/slash": "\u002F",
+    "/slashbarfunc": "\u233F",
+    "/slashmonospace": "\uFF0F",
+    "/sled": "\u1F6F7",
+    "/sleeping": "\u1F4A4",
+    "/sleepingAccommodation": "\u1F6CC",
+    "/sleepingFace": "\u1F634",
+    "/sleepyFace": "\u1F62A",
+    "/sleuthOrSpy": "\u1F575",
+    "/sliceOfPizza": "\u1F355",
+    "/slightlyFrowningFace": "\u1F641",
+    "/slightlySmilingFace": "\u1F642",
+    "/slong": "\u017F",
+    "/slongdotaccent": "\u1E9B",
+    "/slope": "\u2333",
+    "/slotMachine": "\u1F3B0",
+    "/smallAirplane": "\u1F6E9",
+    "/smallBlueDiamond": "\u1F539",
+    "/smallOrangeDiamond": "\u1F538",
+    "/smallRedTriangleDOwn": "\u1F53D",
+    "/smallRedTriangleUp": "\u1F53C",
+    "/smile": "\u2323",
+    "/smileface": "\u263A",
+    "/smilingCatFaceWithHeartShapedEyes": "\u1F63B",
+    "/smilingCatFaceWithOpenMouth": "\u1F63A",
+    "/smilingFaceWithHalo": "\u1F607",
+    "/smilingFaceWithHeartShapedEyes": "\u1F60D",
+    "/smilingFaceWithHorns": "\u1F608",
+    "/smilingFaceWithOpenMouth": "\u1F603",
+    "/smilingFaceWithOpenMouthAndColdSweat": "\u1F605",
+    "/smilingFaceWithOpenMouthAndSmilingEyes": "\u1F604",
+    "/smilingFaceWithOpenMouthAndTightlyClosedEyes": "\u1F606",
+    "/smilingFaceWithSmilingEyes": "\u1F60A",
+    "/smilingFaceWithSunglasses": "\u1F60E",
+    "/smilingfaceblack": "\u263B",
+    "/smilingfacewhite": "\u263A",
+    "/smirkingFace": "\u1F60F",
+    "/smll:ampersand": "\uFE60",
+    "/smll:asterisk": "\uFE61",
+    "/smll:backslash": "\uFE68",
+    "/smll:braceleft": "\uFE5B",
+    "/smll:braceright": "\uFE5C",
+    "/smll:colon": "\uFE55",
+    "/smll:comma": "\uFE50",
+    "/smll:dollar": "\uFE69",
+    "/smll:emdash": "\uFE58",
+    "/smll:equal": "\uFE66",
+    "/smll:exclam": "\uFE57",
+    "/smll:greater": "\uFE65",
+    "/smll:hyphen": "\uFE63",
+    "/smll:ideographiccomma": "\uFE51",
+    "/smll:less": "\uFE64",
+    "/smll:numbersign": "\uFE5F",
+    "/smll:parenthesisleft": "\uFE59",
+    "/smll:parenthesisright": "\uFE5A",
+    "/smll:percent": "\uFE6A",
+    "/smll:period": "\uFE52",
+    "/smll:plus": "\uFE62",
+    "/smll:question": "\uFE56",
+    "/smll:semicolon": "\uFE54",
+    "/smll:tortoiseshellbracketleft": "\uFE5D",
+    "/smll:tortoiseshellbracketright": "\uFE5E",
+    "/smoking": "\u1F6AC",
+    "/smonospace": "\uFF53",
+    "/snail": "\u1F40C",
+    "/snake": "\u1F40D",
+    "/snowboarder": "\u1F3C2",
+    "/snowcappedMountain": "\u1F3D4",
+    "/snowman": "\u2603",
+    "/snowmanblack": "\u26C7",
+    "/snowmanoutsnow": "\u26C4",
+    "/sobliquestroke": "\uA7A9",
+    "/soccerball": "\u26BD",
+    "/societyideographiccircled": "\u3293",
+    "/societyideographicparen": "\u3233",
+    "/socirclekatakana": "\u32DE",
+    "/sofPasuq:hb": "\u05C3",
+    "/sofpasuqhebrew": "\u05C3",
+    "/softIceCream": "\u1F366",
+    "/softShellFloppyDisk": "\u1F5AC",
+    "/softcyr": "\u044C",
+    "/softhyphen": "\u00AD",
+    "/softsigncyrillic": "\u044C",
+    "/softwarefunction": "\u2394",
+    "/sohiragana": "\u305D",
+    "/sokatakana": "\u30BD",
+    "/sokatakanahalfwidth": "\uFF7F",
+    "/soliduslongoverlaycmb": "\u0338",
+    "/solidusshortoverlaycmb": "\u0337",
+    "/solidussubsetreversepreceding": "\u27C8",
+    "/solidussupersetpreceding": "\u27C9",
+    "/soonRightwardsArrowAbove": "\u1F51C",
+    "/sorusithai": "\u0E29",
+    "/sosalathai": "\u0E28",
+    "/sosothai": "\u0E0B",
+    "/sossquare": "\u1F198",
+    "/sosuathai": "\u0E2A",
+    "/soundcopyright": "\u2117",
+    "/space": "\u0020",
+    "/spacehackarabic": "\u0020",
+    "/spade": "\u2660",
+    "/spadeblack": "\u2660",
+    "/spadesuitblack": "\u2660",
+    "/spadesuitwhite": "\u2664",
+    "/spadewhite": "\u2664",
+    "/spaghetti": "\u1F35D",
+    "/sparen": "\u24AE",
+    "/sparenthesized": "\u24AE",
+    "/sparklingHeart": "\u1F496",
+    "/speakNoEvilMonkey": "\u1F64A",
+    "/speaker": "\u1F508",
+    "/speakerCancellationStroke": "\u1F507",
+    "/speakerOneSoundWave": "\u1F509",
+    "/speakerThreeSoundWaves": "\u1F50A",
+    "/speakingHeadInSilhouette": "\u1F5E3",
+    "/specialideographiccircled": "\u3295",
+    "/specialideographicparen": "\u3235",
+    "/speechBalloon": "\u1F4AC",
+    "/speedboat": "\u1F6A4",
+    "/spesmilo": "\u20B7",
+    "/sphericalangle": "\u2222",
+    "/spider": "\u1F577",
+    "/spiderWeb": "\u1F578",
+    "/spiralCalendarPad": "\u1F5D3",
+    "/spiralNotePad": "\u1F5D2",
+    "/spiralShell": "\u1F41A",
+    "/splashingSweat": "\u1F4A6",
+    "/sportsMedal": "\u1F3C5",
+    "/spoutingWhale": "\u1F433",
+    "/sppl:tildevertical": "\u2E2F",
+    "/squarebelowcmb": "\u033B",
+    "/squareblack": "\u25A0",
+    "/squarebracketleftvertical": "\uFE47",
+    "/squarebracketrightvertical": "\uFE48",
+    "/squarecap": "\u2293",
+    "/squarecc": "\u33C4",
+    "/squarecm": "\u339D",
+    "/squarecup": "\u2294",
+    "/squareddotoperator": "\u22A1",
+    "/squarediagonalcrosshatchfill": "\u25A9",
+    "/squaredj": "\u1F190",
+    "/squaredkey": "\u26BF",
+    "/squaredminus": "\u229F",
+    "/squaredplus": "\u229E",
+    "/squaredsaltire": "\u26DD",
+    "/squaredtimes": "\u22A0",
+    "/squarefourcorners": "\u26F6",
+    "/squarehalfleftblack": "\u25E7",
+    "/squarehalfrightblack": "\u25E8",
+    "/squarehorizontalfill": "\u25A4",
+    "/squareimage": "\u228F",
+    "/squareimageorequal": "\u2291",
+    "/squareimageornotequal": "\u22E4",
+    "/squarekg": "\u338F",
+    "/squarekm": "\u339E",
+    "/squarekmcapital": "\u33CE",
+    "/squareln": "\u33D1",
+    "/squarelog": "\u33D2",
+    "/squarelowerdiagonalhalfrightblack": "\u25EA",
+    "/squaremediumblack": "\u25FC",
+    "/squaremediumwhite": "\u25FB",
+    "/squaremg": "\u338E",
+    "/squaremil": "\u33D5",
+    "/squaremm": "\u339C",
+    "/squaremsquared": "\u33A1",
+    "/squareoriginal": "\u2290",
+    "/squareoriginalorequal": "\u2292",
+    "/squareoriginalornotequal": "\u22E5",
+    "/squareorthogonalcrosshatchfill": "\u25A6",
+    "/squareraised": "\u2E0B",
+    "/squaresmallblack": "\u25AA",
+    "/squaresmallmediumblack": "\u25FE",
+    "/squaresmallmediumwhite": "\u25FD",
+    "/squaresmallwhite": "\u25AB",
+    "/squareupperdiagonalhalfleftblack": "\u25E9",
+    "/squareupperlefttolowerrightfill": "\u25A7",
+    "/squareupperrighttolowerleftfill": "\u25A8",
+    "/squareverticalfill": "\u25A5",
+    "/squarewhite": "\u25A1",
+    "/squarewhitebisectinglinevertical": "\u25EB",
+    "/squarewhitelowerquadrantleft": "\u25F1",
+    "/squarewhitelowerquadrantright": "\u25F2",
+    "/squarewhiteround": "\u25A2",
+    "/squarewhiteupperquadrantleft": "\u25F0",
+    "/squarewhiteupperquadrantright": "\u25F3",
+    "/squarewhitewithsmallblack": "\u25A3",
+    "/squarewhitewithsquaresmallblack": "\u25A3",
+    "/squishquadfunc": "\u2337",
+    "/srfullwidth": "\u33DB",
+    "/srsquare": "\u33DB",
+    "/ssabengali": "\u09B7",
+    "/ssadeva": "\u0937",
+    "/ssagujarati": "\u0AB7",
+    "/ssangcieuckorean": "\u3149",
+    "/ssanghieuhkorean": "\u3185",
+    "/ssangieungkorean": "\u3180",
+    "/ssangkiyeokkorean": "\u3132",
+    "/ssangnieunkorean": "\u3165",
+    "/ssangpieupkorean": "\u3143",
+    "/ssangsioskorean": "\u3146",
+    "/ssangtikeutkorean": "\u3138",
+    "/ssuperior": "\uF6F2",
+    "/ssupmod": "\u02E2",
+    "/sswashtail": "\u023F",
+    "/stackedcommadbl": "\u2E49",
+    "/stadium": "\u1F3DF",
+    "/staffofaesculapius": "\u2695",
+    "/staffofhermes": "\u269A",
+    "/stampedEnvelope": "\u1F583",
+    "/star": "\u22C6",
+    "/starblack": "\u2605",
+    "/starcrescent": "\u262A",
+    "/stardiaeresisfunc": "\u2363",
+    "/starequals": "\u225B",
+    "/staroperator": "\u22C6",
+    "/staroutlinedwhite": "\u269D",
+    "/starwhite": "\u2606",
+    "/station": "\u1F689",
+    "/statueOfLiberty": "\u1F5FD",
+    "/steamLocomotive": "\u1F682",
+    "/steamingBowl": "\u1F35C",
+    "/stenographicfullstop": "\u2E3C",
+    "/sterling": "\u00A3",
+    "/sterlingmonospace": "\uFFE1",
+    "/stigma": "\u03DB",
+    "/stiletildefunc": "\u236D",
+    "/stockChart": "\u1F5E0",
+    "/stockideographiccircled": "\u3291",
+    "/stockideographicparen": "\u3231",
+    "/stopabove": "\u06EB",
+    "/stopbelow": "\u06EA",
+    "/straightRuler": "\u1F4CF",
+    "/straightness": "\u23E4",
+    "/strawberry": "\u1F353",
+    "/stresslowtonemod": "\uA721",
+    "/stresstonemod": "\uA720",
+    "/strictlyequivalent": "\u2263",
+    "/strokelongoverlaycmb": "\u0336",
+    "/strokeshortoverlaycmb": "\u0335",
+    "/studioMicrophone": "\u1F399",
+    "/studyideographiccircled": "\u32AB",
+    "/studyideographicparen": "\u323B",
+    "/stupa": "\u1F6D3",
+    "/subscriptalef": "\u0656",
+    "/subset": "\u2282",
+    "/subsetdbl": "\u22D0",
+    "/subsetnotequal": "\u228A",
+    "/subsetorequal": "\u2286",
+    "/succeeds": "\u227B",
+    "/succeedsbutnotequivalent": "\u22E9",
+    "/succeedsorequal": "\u227D",
+    "/succeedsorequivalent": "\u227F",
+    "/succeedsunderrelation": "\u22B1",
+    "/suchthat": "\u220B",
+    "/sucirclekatakana": "\u32DC",
+    "/suhiragana": "\u3059",
+    "/suitableideographiccircled": "\u329C",
+    "/sukatakana": "\u30B9",
+    "/sukatakanahalfwidth": "\uFF7D",
+    "/sukumendutvowel": "\uA9B9",
+    "/sukunIsol": "\uFE7E",
+    "/sukunMedi": "\uFE7F",
+    "/sukunarabic": "\u0652",
+    "/sukuvowel": "\uA9B8",
+    "/summation": "\u2211",
+    "/summationbottom": "\u23B3",
+    "/summationdblstruck": "\u2140",
+    "/summationtop": "\u23B2",
+    "/sun": "\u263C",
+    "/sunFace": "\u1F31E",
+    "/sunbehindcloud": "\u26C5",
+    "/sunflower": "\u1F33B",
+    "/sunideographiccircled": "\u3290",
+    "/sunideographicparen": "\u3230",
+    "/sunraysblack": "\u2600",
+    "/sunrayswhite": "\u263C",
+    "/sunrise": "\u1F305",
+    "/sunriseOverMountains": "\u1F304",
+    "/sunsetOverBuildings": "\u1F307",
+    "/superset": "\u2283",
+    "/supersetnotequal": "\u228B",
+    "/supersetorequal": "\u2287",
+    "/superviseideographiccircled": "\u32AC",
+    "/superviseideographicparen": "\u323C",
+    "/surfer": "\u1F3C4",
+    "/sushi": "\u1F363",
+    "/suspensionRailway": "\u1F69F",
+    "/suspensiondbl": "\u2E44",
+    "/svfullwidth": "\u33DC",
+    "/svsquare": "\u33DC",
+    "/swatchtop": "\u23F1",
+    "/swimmer": "\u1F3CA",
+    "/swungdash": "\u2053",
+    "/symbolabovethreedotsabove": "\uFBB6",
+    "/symbolbelowthreedotsabove": "\uFBB7",
+    "/symboldotabove": "\uFBB2",
+    "/symboldotbelow": "\uFBB3",
+    "/symboldoubleverticalbarbelow": "\uFBBC",
+    "/symbolfourdotsabove": "\uFBBA",
+    "/symbolfourdotsbelow": "\uFBBB",
+    "/symbolpointingabovedownthreedotsabove": "\uFBB8",
+    "/symbolpointingbelowdownthreedotsabove": "\uFBB9",
+    "/symbolring": "\uFBBF",
+    "/symboltahabovesmall": "\uFBC0",
+    "/symboltahbelowsmall": "\uFBC1",
+    "/symboltwodotsabove": "\uFBB4",
+    "/symboltwodotsbelow": "\uFBB5",
+    "/symboltwodotsverticallyabove": "\uFBBD",
+    "/symboltwodotsverticallybelow": "\uFBBE",
+    "/symmetry": "\u232F",
+    "/synagogue": "\u1F54D",
+    "/syouwaerasquare": "\u337C",
+    "/syringe": "\u1F489",
+    "/t": "\u0074",
+    "/t-shirt": "\u1F455",
+    "/t.inferior": "\u209C",
+    "/tabengali": "\u09A4",
+    "/tableTennisPaddleAndBall": "\u1F3D3",
+    "/tacirclekatakana": "\u32DF",
+    "/tackcircleaboveup": "\u27DF",
+    "/tackdiaeresisupfunc": "\u2361",
+    "/tackdown": "\u22A4",
+    "/tackdownmod": "\u02D5",
+    "/tackjotdownfunc": "\u234E",
+    "/tackjotupfunc": "\u2355",
+    "/tackleft": "\u22A3",
+    "/tackleftright": "\u27DB",
+    "/tackoverbarupfunc": "\u2351",
+    "/tackright": "\u22A2",
+    "/tackunderlinedownfunc": "\u234A",
+    "/tackup": "\u22A5",
+    "/tackupmod": "\u02D4",
+    "/taco": "\u1F32E",
+    "/tadeva": "\u0924",
+    "/tagujarati": "\u0AA4",
+    "/tagurmukhi": "\u0A24",
+    "/tah": "\u0637",
+    "/tah.fina": "\uFEC2",
+    "/tah.init": "\uFEC3",
+    "/tah.init_alefmaksura.fina": "\uFCF5",
+    "/tah.init_hah.fina": "\uFC26",
+    "/tah.init_hah.medi": "\uFCB8",
+    "/tah.init_meem.fina": "\uFC27",
+    "/tah.init_meem.medi": "\uFD33",
+    "/tah.init_meem.medi_hah.medi": "\uFD72",
+    "/tah.init_meem.medi_meem.medi": "\uFD73",
+    "/tah.init_yeh.fina": "\uFCF6",
+    "/tah.isol": "\uFEC1",
+    "/tah.medi": "\uFEC4",
+    "/tah.medi_alefmaksura.fina": "\uFD11",
+    "/tah.medi_meem.medi": "\uFD3A",
+    "/tah.medi_meem.medi_hah.fina": "\uFD71",
+    "/tah.medi_meem.medi_yeh.fina": "\uFD74",
+    "/tah.medi_yeh.fina": "\uFD12",
+    "/tahabove": "\u0615",
+    "/taharabic": "\u0637",
+    "/tahfinalarabic": "\uFEC2",
+    "/tahinitialarabic": "\uFEC3",
+    "/tahiragana": "\u305F",
+    "/tahmedialarabic": "\uFEC4",
+    "/tahthreedotsabove": "\u069F",
+    "/taisyouerasquare": "\u337D",
+    "/takatakana": "\u30BF",
+    "/takatakanahalfwidth": "\uFF80",
+    "/takhallus": "\u0614",
+    "/talingvowel": "\uA9BA",
+    "/taml:a": "\u0B85",
+    "/taml:aa": "\u0B86",
+    "/taml:aasign": "\u0BBE",
+    "/taml:ai": "\u0B90",
+    "/taml:aisign": "\u0BC8",
+    "/taml:anusvarasign": "\u0B82",
+    "/taml:asabovesign": "\u0BF8",
+    "/taml:au": "\u0B94",
+    "/taml:aulengthmark": "\u0BD7",
+    "/taml:ausign": "\u0BCC",
+    "/taml:ca": "\u0B9A",
+    "/taml:creditsign": "\u0BF7",
+    "/taml:daysign": "\u0BF3",
+    "/taml:debitsign": "\u0BF6",
+    "/taml:e": "\u0B8E",
+    "/taml:ee": "\u0B8F",
+    "/taml:eesign": "\u0BC7",
+    "/taml:eight": "\u0BEE",
+    "/taml:esign": "\u0BC6",
+    "/taml:five": "\u0BEB",
+    "/taml:four": "\u0BEA",
+    "/taml:ha": "\u0BB9",
+    "/taml:i": "\u0B87",
+    "/taml:ii": "\u0B88",
+    "/taml:iisign": "\u0BC0",
+    "/taml:isign": "\u0BBF",
+    "/taml:ja": "\u0B9C",
+    "/taml:ka": "\u0B95",
+    "/taml:la": "\u0BB2",
+    "/taml:lla": "\u0BB3",
+    "/taml:llla": "\u0BB4",
+    "/taml:ma": "\u0BAE",
+    "/taml:monthsign": "\u0BF4",
+    "/taml:na": "\u0BA8",
+    "/taml:nga": "\u0B99",
+    "/taml:nine": "\u0BEF",
+    "/taml:nna": "\u0BA3",
+    "/taml:nnna": "\u0BA9",
+    "/taml:nya": "\u0B9E",
+    "/taml:o": "\u0B92",
+    "/taml:om": "\u0BD0",
+    "/taml:one": "\u0BE7",
+    "/taml:onehundred": "\u0BF1",
+    "/taml:onethousand": "\u0BF2",
+    "/taml:oo": "\u0B93",
+    "/taml:oosign": "\u0BCB",
+    "/taml:osign": "\u0BCA",
+    "/taml:pa": "\u0BAA",
+    "/taml:ra": "\u0BB0",
+    "/taml:rra": "\u0BB1",
+    "/taml:rupeesign": "\u0BF9",
+    "/taml:sa": "\u0BB8",
+    "/taml:seven": "\u0BED",
+    "/taml:sha": "\u0BB6",
+    "/taml:sign": "\u0BFA",
+    "/taml:six": "\u0BEC",
+    "/taml:ssa": "\u0BB7",
+    "/taml:ta": "\u0BA4",
+    "/taml:ten": "\u0BF0",
+    "/taml:three": "\u0BE9",
+    "/taml:tta": "\u0B9F",
+    "/taml:two": "\u0BE8",
+    "/taml:u": "\u0B89",
+    "/taml:usign": "\u0BC1",
+    "/taml:uu": "\u0B8A",
+    "/taml:uusign": "\u0BC2",
+    "/taml:va": "\u0BB5",
+    "/taml:viramasign": "\u0BCD",
+    "/taml:visargasign": "\u0B83",
+    "/taml:ya": "\u0BAF",
+    "/taml:yearsign": "\u0BF5",
+    "/taml:zero": "\u0BE6",
+    "/tamurda": "\uA9A1",
+    "/tanabataTree": "\u1F38B",
+    "/tangerine": "\u1F34A",
+    "/tapeCartridge": "\u1F5AD",
+    "/tarungvowel": "\uA9B4",
+    "/tatweelFathatanAbove": "\uFE71",
+    "/tatweelarabic": "\u0640",
+    "/tau": "\u03C4",
+    "/taurus": "\u2649",
+    "/tav": "\u05EA",
+    "/tav:hb": "\u05EA",
+    "/tavdages": "\uFB4A",
+    "/tavdagesh": "\uFB4A",
+    "/tavdageshhebrew": "\uFB4A",
+    "/tavhebrew": "\u05EA",
+    "/tavwide:hb": "\uFB28",
+    "/tavwithdagesh:hb": "\uFB4A",
+    "/taxi": "\u1F695",
+    "/tbar": "\u0167",
+    "/tbopomofo": "\u310A",
+    "/tcaron": "\u0165",
+    "/tccurl": "\u02A8",
+    "/tcedilla": "\u0163",
+    "/tcheh": "\u0686",
+    "/tcheh.fina": "\uFB7B",
+    "/tcheh.init": "\uFB7C",
+    "/tcheh.isol": "\uFB7A",
+    "/tcheh.medi": "\uFB7D",
+    "/tcheharabic": "\u0686",
+    "/tchehdotabove": "\u06BF",
+    "/tcheheh": "\u0687",
+    "/tcheheh.fina": "\uFB7F",
+    "/tcheheh.init": "\uFB80",
+    "/tcheheh.isol": "\uFB7E",
+    "/tcheheh.medi": "\uFB81",
+    "/tchehfinalarabic": "\uFB7B",
+    "/tchehinitialarabic": "\uFB7C",
+    "/tchehmedialarabic": "\uFB7D",
+    "/tchehmeeminitialarabic": "\uFB7C",
+    "/tcircle": "\u24E3",
+    "/tcircumflexbelow": "\u1E71",
+    "/tcommaaccent": "\u0163",
+    "/tcurl": "\u0236",
+    "/tdieresis": "\u1E97",
+    "/tdot": "\u1E6B",
+    "/tdotaccent": "\u1E6B",
+    "/tdotbelow": "\u1E6D",
+    "/teacupOutHandle": "\u1F375",
+    "/tear-offCalendar": "\u1F4C6",
+    "/tecirclekatakana": "\u32E2",
+    "/tecyr": "\u0442",
+    "/tecyrillic": "\u0442",
+    "/tedescendercyrillic": "\u04AD",
+    "/teh": "\u062A",
+    "/teh.fina": "\uFE96",
+    "/teh.init": "\uFE97",
+    "/teh.init_alefmaksura.fina": "\uFC0F",
+    "/teh.init_hah.fina": "\uFC0C",
+    "/teh.init_hah.medi": "\uFCA2",
+    "/teh.init_hah.medi_jeem.medi": "\uFD52",
+    "/teh.init_hah.medi_meem.medi": "\uFD53",
+    "/teh.init_heh.medi": "\uFCA5",
+    "/teh.init_jeem.fina": "\uFC0B",
+    "/teh.init_jeem.medi": "\uFCA1",
+    "/teh.init_jeem.medi_meem.medi": "\uFD50",
+    "/teh.init_khah.fina": "\uFC0D",
+    "/teh.init_khah.medi": "\uFCA3",
+    "/teh.init_khah.medi_meem.medi": "\uFD54",
+    "/teh.init_meem.fina": "\uFC0E",
+    "/teh.init_meem.medi": "\uFCA4",
+    "/teh.init_meem.medi_hah.medi": "\uFD56",
+    "/teh.init_meem.medi_jeem.medi": "\uFD55",
+    "/teh.init_meem.medi_khah.medi": "\uFD57",
+    "/teh.init_yeh.fina": "\uFC10",
+    "/teh.isol": "\uFE95",
+    "/teh.medi": "\uFE98",
+    "/teh.medi_alefmaksura.fina": "\uFC74",
+    "/teh.medi_hah.medi_jeem.fina": "\uFD51",
+    "/teh.medi_heh.medi": "\uFCE4",
+    "/teh.medi_jeem.medi_alefmaksura.fina": "\uFDA0",
+    "/teh.medi_jeem.medi_yeh.fina": "\uFD9F",
+    "/teh.medi_khah.medi_alefmaksura.fina": "\uFDA2",
+    "/teh.medi_khah.medi_yeh.fina": "\uFDA1",
+    "/teh.medi_meem.fina": "\uFC72",
+    "/teh.medi_meem.medi": "\uFCE3",
+    "/teh.medi_meem.medi_alefmaksura.fina": "\uFDA4",
+    "/teh.medi_meem.medi_yeh.fina": "\uFDA3",
+    "/teh.medi_noon.fina": "\uFC73",
+    "/teh.medi_reh.fina": "\uFC70",
+    "/teh.medi_yeh.fina": "\uFC75",
+    "/teh.medi_zain.fina": "\uFC71",
+    "/teharabic": "\u062A",
+    "/tehdownthreedotsabove": "\u067D",
+    "/teheh": "\u067F",
+    "/teheh.fina": "\uFB63",
+    "/teheh.init": "\uFB64",
+    "/teheh.isol": "\uFB62",
+    "/teheh.medi": "\uFB65",
+    "/tehfinalarabic": "\uFE96",
+    "/tehhahinitialarabic": "\uFCA2",
+    "/tehhahisolatedarabic": "\uFC0C",
+    "/tehinitialarabic": "\uFE97",
+    "/tehiragana": "\u3066",
+    "/tehjeeminitialarabic": "\uFCA1",
+    "/tehjeemisolatedarabic": "\uFC0B",
+    "/tehmarbuta": "\u0629",
+    "/tehmarbuta.fina": "\uFE94",
+    "/tehmarbuta.isol": "\uFE93",
+    "/tehmarbutaarabic": "\u0629",
+    "/tehmarbutafinalarabic": "\uFE94",
+    "/tehmarbutagoal": "\u06C3",
+    "/tehmedialarabic": "\uFE98",
+    "/tehmeeminitialarabic": "\uFCA4",
+    "/tehmeemisolatedarabic": "\uFC0E",
+    "/tehnoonfinalarabic": "\uFC73",
+    "/tehring": "\u067C",
+    "/tekatakana": "\u30C6",
+    "/tekatakanahalfwidth": "\uFF83",
+    "/telephone": "\u2121",
+    "/telephoneOnTopOfModem": "\u1F580",
+    "/telephoneReceiver": "\u1F4DE",
+    "/telephoneReceiverPage": "\u1F57C",
+    "/telephoneblack": "\u260E",
+    "/telephonerecorder": "\u2315",
+    "/telephonewhite": "\u260F",
+    "/telescope": "\u1F52D",
+    "/television": "\u1F4FA",
+    "/telishaGedolah:hb": "\u05A0",
+    "/telishaQetannah:hb": "\u05A9",
+    "/telishagedolahebrew": "\u05A0",
+    "/telishaqetanahebrew": "\u05A9",
+    "/telu:a": "\u0C05",
+    "/telu:aa": "\u0C06",
+    "/telu:aasign": "\u0C3E",
+    "/telu:ai": "\u0C10",
+    "/telu:ailengthmark": "\u0C56",
+    "/telu:aisign": "\u0C48",
+    "/telu:anusvarasign": "\u0C02",
+    "/telu:au": "\u0C14",
+    "/telu:ausign": "\u0C4C",
+    "/telu:avagrahasign": "\u0C3D",
+    "/telu:ba": "\u0C2C",
+    "/telu:bha": "\u0C2D",
+    "/telu:bindusigncandra": "\u0C01",
+    "/telu:ca": "\u0C1A",
+    "/telu:cha": "\u0C1B",
+    "/telu:combiningbinduabovesigncandra": "\u0C00",
+    "/telu:da": "\u0C26",
+    "/telu:dda": "\u0C21",
+    "/telu:ddha": "\u0C22",
+    "/telu:dha": "\u0C27",
+    "/telu:dza": "\u0C59",
+    "/telu:e": "\u0C0E",
+    "/telu:ee": "\u0C0F",
+    "/telu:eesign": "\u0C47",
+    "/telu:eight": "\u0C6E",
+    "/telu:esign": "\u0C46",
+    "/telu:five": "\u0C6B",
+    "/telu:four": "\u0C6A",
+    "/telu:fractiononeforevenpowersoffour": "\u0C7C",
+    "/telu:fractiononeforoddpowersoffour": "\u0C79",
+    "/telu:fractionthreeforevenpowersoffour": "\u0C7E",
+    "/telu:fractionthreeforoddpowersoffour": "\u0C7B",
+    "/telu:fractiontwoforevenpowersoffour": "\u0C7D",
+    "/telu:fractiontwoforoddpowersoffour": "\u0C7A",
+    "/telu:fractionzeroforoddpowersoffour": "\u0C78",
+    "/telu:ga": "\u0C17",
+    "/telu:gha": "\u0C18",
+    "/telu:ha": "\u0C39",
+    "/telu:i": "\u0C07",
+    "/telu:ii": "\u0C08",
+    "/telu:iisign": "\u0C40",
+    "/telu:isign": "\u0C3F",
+    "/telu:ja": "\u0C1C",
+    "/telu:jha": "\u0C1D",
+    "/telu:ka": "\u0C15",
+    "/telu:kha": "\u0C16",
+    "/telu:la": "\u0C32",
+    "/telu:lengthmark": "\u0C55",
+    "/telu:lla": "\u0C33",
+    "/telu:llla": "\u0C34",
+    "/telu:llsignvocal": "\u0C63",
+    "/telu:llvocal": "\u0C61",
+    "/telu:lsignvocal": "\u0C62",
+    "/telu:lvocal": "\u0C0C",
+    "/telu:ma": "\u0C2E",
+    "/telu:na": "\u0C28",
+    "/telu:nga": "\u0C19",
+    "/telu:nine": "\u0C6F",
+    "/telu:nna": "\u0C23",
+    "/telu:nya": "\u0C1E",
+    "/telu:o": "\u0C12",
+    "/telu:one": "\u0C67",
+    "/telu:oo": "\u0C13",
+    "/telu:oosign": "\u0C4B",
+    "/telu:osign": "\u0C4A",
+    "/telu:pa": "\u0C2A",
+    "/telu:pha": "\u0C2B",
+    "/telu:ra": "\u0C30",
+    "/telu:rra": "\u0C31",
+    "/telu:rrra": "\u0C5A",
+    "/telu:rrsignvocal": "\u0C44",
+    "/telu:rrvocal": "\u0C60",
+    "/telu:rsignvocal": "\u0C43",
+    "/telu:rvocal": "\u0C0B",
+    "/telu:sa": "\u0C38",
+    "/telu:seven": "\u0C6D",
+    "/telu:sha": "\u0C36",
+    "/telu:six": "\u0C6C",
+    "/telu:ssa": "\u0C37",
+    "/telu:ta": "\u0C24",
+    "/telu:tha": "\u0C25",
+    "/telu:three": "\u0C69",
+    "/telu:tsa": "\u0C58",
+    "/telu:tta": "\u0C1F",
+    "/telu:ttha": "\u0C20",
+    "/telu:tuumusign": "\u0C7F",
+    "/telu:two": "\u0C68",
+    "/telu:u": "\u0C09",
+    "/telu:usign": "\u0C41",
+    "/telu:uu": "\u0C0A",
+    "/telu:uusign": "\u0C42",
+    "/telu:va": "\u0C35",
+    "/telu:viramasign": "\u0C4D",
+    "/telu:visargasign": "\u0C03",
+    "/telu:ya": "\u0C2F",
+    "/telu:zero": "\u0C66",
+    "/ten.roman": "\u2169",
+    "/ten.romansmall": "\u2179",
+    "/tencircle": "\u2469",
+    "/tencircledbl": "\u24FE",
+    "/tencirclesquare": "\u3248",
+    "/tenge": "\u20B8",
+    "/tenhangzhou": "\u3038",
+    "/tenideographiccircled": "\u3289",
+    "/tenideographicparen": "\u3229",
+    "/tennisRacquetAndBall": "\u1F3BE",
+    "/tenparen": "\u247D",
+    "/tenparenthesized": "\u247D",
+    "/tenperiod": "\u2491",
+    "/tenroman": "\u2179",
+    "/tent": "\u26FA",
+    "/tenthousand.roman": "\u2182",
+    "/tesh": "\u02A7",
+    "/tet": "\u05D8",
+    "/tet:hb": "\u05D8",
+    "/tetailcyr": "\u04AD",
+    "/tetdagesh": "\uFB38",
+    "/tetdageshhebrew": "\uFB38",
+    "/tethebrew": "\u05D8",
+    "/tetrasememetrical": "\u23D8",
+    "/tetsecyr": "\u04B5",
+    "/tetsecyrillic": "\u04B5",
+    "/tetwithdagesh:hb": "\uFB38",
+    "/tevir:hb": "\u059B",
+    "/tevirhebrew": "\u059B",
+    "/tevirlefthebrew": "\u059B",
+    "/thabengali": "\u09A5",
+    "/thadeva": "\u0925",
+    "/thagujarati": "\u0AA5",
+    "/thagurmukhi": "\u0A25",
+    "/thai:angkhankhu": "\u0E5A",
+    "/thai:baht": "\u0E3F",
+    "/thai:bobaimai": "\u0E1A",
+    "/thai:chochan": "\u0E08",
+    "/thai:chochang": "\u0E0A",
+    "/thai:choching": "\u0E09",
+    "/thai:chochoe": "\u0E0C",
+    "/thai:dochada": "\u0E0E",
+    "/thai:dodek": "\u0E14",
+    "/thai:eight": "\u0E58",
+    "/thai:five": "\u0E55",
+    "/thai:fofa": "\u0E1D",
+    "/thai:fofan": "\u0E1F",
+    "/thai:fongman": "\u0E4F",
+    "/thai:four": "\u0E54",
+    "/thai:hohip": "\u0E2B",
+    "/thai:honokhuk": "\u0E2E",
+    "/thai:khokhai": "\u0E02",
+    "/thai:khokhon": "\u0E05",
+    "/thai:khokhuat": "\u0E03",
+    "/thai:khokhwai": "\u0E04",
+    "/thai:khomut": "\u0E5B",
+    "/thai:khorakhang": "\u0E06",
+    "/thai:kokai": "\u0E01",
+    "/thai:lakkhangyao": "\u0E45",
+    "/thai:lochula": "\u0E2C",
+    "/thai:loling": "\u0E25",
+    "/thai:lu": "\u0E26",
+    "/thai:maichattawa": "\u0E4B",
+    "/thai:maiek": "\u0E48",
+    "/thai:maihan-akat": "\u0E31",
+    "/thai:maitaikhu": "\u0E47",
+    "/thai:maitho": "\u0E49",
+    "/thai:maitri": "\u0E4A",
+    "/thai:maiyamok": "\u0E46",
+    "/thai:moma": "\u0E21",
+    "/thai:ngongu": "\u0E07",
+    "/thai:nikhahit": "\u0E4D",
+    "/thai:nine": "\u0E59",
+    "/thai:nonen": "\u0E13",
+    "/thai:nonu": "\u0E19",
+    "/thai:oang": "\u0E2D",
+    "/thai:one": "\u0E51",
+    "/thai:paiyannoi": "\u0E2F",
+    "/thai:phinthu": "\u0E3A",
+    "/thai:phophan": "\u0E1E",
+    "/thai:phophung": "\u0E1C",
+    "/thai:phosamphao": "\u0E20",
+    "/thai:popla": "\u0E1B",
+    "/thai:rorua": "\u0E23",
+    "/thai:ru": "\u0E24",
+    "/thai:saraa": "\u0E30",
+    "/thai:saraaa": "\u0E32",
+    "/thai:saraae": "\u0E41",
+    "/thai:saraaimaimalai": "\u0E44",
+    "/thai:saraaimaimuan": "\u0E43",
+    "/thai:saraam": "\u0E33",
+    "/thai:sarae": "\u0E40",
+    "/thai:sarai": "\u0E34",
+    "/thai:saraii": "\u0E35",
+    "/thai:sarao": "\u0E42",
+    "/thai:sarau": "\u0E38",
+    "/thai:saraue": "\u0E36",
+    "/thai:sarauee": "\u0E37",
+    "/thai:sarauu": "\u0E39",
+    "/thai:seven": "\u0E57",
+    "/thai:six": "\u0E56",
+    "/thai:sorusi": "\u0E29",
+    "/thai:sosala": "\u0E28",
+    "/thai:soso": "\u0E0B",
+    "/thai:sosua": "\u0E2A",
+    "/thai:thanthakhat": "\u0E4C",
+    "/thai:thonangmontho": "\u0E11",
+    "/thai:thophuthao": "\u0E12",
+    "/thai:thothahan": "\u0E17",
+    "/thai:thothan": "\u0E10",
+    "/thai:thothong": "\u0E18",
+    "/thai:thothung": "\u0E16",
+    "/thai:three": "\u0E53",
+    "/thai:topatak": "\u0E0F",
+    "/thai:totao": "\u0E15",
+    "/thai:two": "\u0E52",
+    "/thai:wowaen": "\u0E27",
+    "/thai:yamakkan": "\u0E4E",
+    "/thai:yoyak": "\u0E22",
+    "/thai:yoying": "\u0E0D",
+    "/thai:zero": "\u0E50",
+    "/thal": "\u0630",
+    "/thal.fina": "\uFEAC",
+    "/thal.init_superscriptalef.fina": "\uFC5B",
+    "/thal.isol": "\uFEAB",
+    "/thalarabic": "\u0630",
+    "/thalfinalarabic": "\uFEAC",
+    "/thanthakhatlowleftthai": "\uF898",
+    "/thanthakhatlowrightthai": "\uF897",
+    "/thanthakhatthai": "\u0E4C",
+    "/thanthakhatupperleftthai": "\uF896",
+    "/theh": "\u062B",
+    "/theh.fina": "\uFE9A",
+    "/theh.init": "\uFE9B",
+    "/theh.init_alefmaksura.fina": "\uFC13",
+    "/theh.init_jeem.fina": "\uFC11",
+    "/theh.init_meem.fina": "\uFC12",
+    "/theh.init_meem.medi": "\uFCA6",
+    "/theh.init_yeh.fina": "\uFC14",
+    "/theh.isol": "\uFE99",
+    "/theh.medi": "\uFE9C",
+    "/theh.medi_alefmaksura.fina": "\uFC7A",
+    "/theh.medi_heh.medi": "\uFCE6",
+    "/theh.medi_meem.fina": "\uFC78",
+    "/theh.medi_meem.medi": "\uFCE5",
+    "/theh.medi_noon.fina": "\uFC79",
+    "/theh.medi_reh.fina": "\uFC76",
+    "/theh.medi_yeh.fina": "\uFC7B",
+    "/theh.medi_zain.fina": "\uFC77",
+    "/theharabic": "\u062B",
+    "/thehfinalarabic": "\uFE9A",
+    "/thehinitialarabic": "\uFE9B",
+    "/thehmedialarabic": "\uFE9C",
+    "/thereexists": "\u2203",
+    "/therefore": "\u2234",
+    "/thermometer": "\u1F321",
+    "/theta": "\u03B8",
+    "/theta.math": "\u03D1",
+    "/theta1": "\u03D1",
+    "/thetasymbolgreek": "\u03D1",
+    "/thieuthacirclekorean": "\u3279",
+    "/thieuthaparenkorean": "\u3219",
+    "/thieuthcirclekorean": "\u326B",
+    "/thieuthkorean": "\u314C",
+    "/thieuthparenkorean": "\u320B",
+    "/thinspace": "\u2009",
+    "/thirteencircle": "\u246C",
+    "/thirteencircleblack": "\u24ED",
+    "/thirteenparen": "\u2480",
+    "/thirteenparenthesized": "\u2480",
+    "/thirteenperiod": "\u2494",
+    "/thirtycircle": "\u325A",
+    "/thirtycirclesquare": "\u324A",
+    "/thirtyeightcircle": "\u32B3",
+    "/thirtyfivecircle": "\u325F",
+    "/thirtyfourcircle": "\u325E",
+    "/thirtyhangzhou": "\u303A",
+    "/thirtyninecircle": "\u32B4",
+    "/thirtyonecircle": "\u325B",
+    "/thirtysevencircle": "\u32B2",
+    "/thirtysixcircle": "\u32B1",
+    "/thirtythreecircle": "\u325D",
+    "/thirtytwocircle": "\u325C",
+    "/thonangmonthothai": "\u0E11",
+    "/thook": "\u01AD",
+    "/thophuthaothai": "\u0E12",
+    "/thorn": "\u00FE",
+    "/thornstroke": "\uA765",
+    "/thornstrokedescender": "\uA767",
+    "/thothahanthai": "\u0E17",
+    "/thothanthai": "\u0E10",
+    "/thothongthai": "\u0E18",
+    "/thothungthai": "\u0E16",
+    "/thoughtBalloon": "\u1F4AD",
+    "/thousandcyrillic": "\u0482",
+    "/thousandscyr": "\u0482",
+    "/thousandsseparator": "\u066C",
+    "/thousandsseparatorarabic": "\u066C",
+    "/thousandsseparatorpersian": "\u066C",
+    "/three": "\u0033",
+    "/three.inferior": "\u2083",
+    "/three.roman": "\u2162",
+    "/three.romansmall": "\u2172",
+    "/threeButtonMouse": "\u1F5B1",
+    "/threeNetworkedComputers": "\u1F5A7",
+    "/threeRaysAbove": "\u1F5E4",
+    "/threeRaysBelow": "\u1F5E5",
+    "/threeRaysLeft": "\u1F5E6",
+    "/threeRaysRight": "\u1F5E7",
+    "/threeSpeechBubbles": "\u1F5EB",
+    "/threearabic": "\u0663",
+    "/threebengali": "\u09E9",
+    "/threecircle": "\u2462",
+    "/threecircledbl": "\u24F7",
+    "/threecircleinversesansserif": "\u278C",
+    "/threecomma": "\u1F104",
+    "/threedeva": "\u0969",
+    "/threedimensionalangle": "\u27C0",
+    "/threedotpunctuation": "\u2056",
+    "/threedotsaboveabove": "\u06DB",
+    "/threedsquare": "\u1F19B",
+    "/threeeighths": "\u215C",
+    "/threefar": "\u06F3",
+    "/threefifths": "\u2157",
+    "/threegujarati": "\u0AE9",
+    "/threegurmukhi": "\u0A69",
+    "/threehackarabic": "\u0663",
+    "/threehangzhou": "\u3023",
+    "/threeideographiccircled": "\u3282",
+    "/threeideographicparen": "\u3222",
+    "/threeinferior": "\u2083",
+    "/threelinesconvergingleft": "\u269F",
+    "/threelinesconvergingright": "\u269E",
+    "/threemonospace": "\uFF13",
+    "/threenumeratorbengali": "\u09F6",
+    "/threeoldstyle": "\uF733",
+    "/threeparen": "\u2476",
+    "/threeparenthesized": "\u2476",
+    "/threeperemspace": "\u2004",
+    "/threeperiod": "\u248A",
+    "/threepersian": "\u06F3",
+    "/threequarters": "\u00BE",
+    "/threequartersemdash": "\uF6DE",
+    "/threerightarrows": "\u21F6",
+    "/threeroman": "\u2172",
+    "/threesuperior": "\u00B3",
+    "/threethai": "\u0E53",
+    "/thumbsDownSign": "\u1F44E",
+    "/thumbsUpSign": "\u1F44D",
+    "/thundercloudrain": "\u26C8",
+    "/thunderstorm": "\u2608",
+    "/thzfullwidth": "\u3394",
+    "/thzsquare": "\u3394",
+    "/tibt:AA": "\u0F60",
+    "/tibt:a": "\u0F68",
+    "/tibt:aavowelsign": "\u0F71",
+    "/tibt:angkhanggyasmark": "\u0F3D",
+    "/tibt:angkhanggyonmark": "\u0F3C",
+    "/tibt:astrologicalkhyudpasign": "\u0F18",
+    "/tibt:astrologicalsdongtshugssign": "\u0F19",
+    "/tibt:astrologicalsgragcancharrtagssign": "\u0F17",
+    "/tibt:asubjoined": "\u0FB8",
+    "/tibt:ba": "\u0F56",
+    "/tibt:basubjoined": "\u0FA6",
+    "/tibt:bha": "\u0F57",
+    "/tibt:bhasubjoined": "\u0FA7",
+    "/tibt:bkashogyigmgomark": "\u0F0A",
+    "/tibt:brdarnyingyigmgomdunmainitialmark": "\u0FD3",
+    "/tibt:brdarnyingyigmgosgabmaclosingmark": "\u0FD4",
+    "/tibt:bsdusrtagsmark": "\u0F34",
+    "/tibt:bskashoggimgorgyanmark": "\u0FD0",
+    "/tibt:bskuryigmgomark": "\u0F09",
+    "/tibt:ca": "\u0F45",
+    "/tibt:cangteucantillationsign": "\u0FC2",
+    "/tibt:caretdzudrtagsbzhimigcanmark": "\u0F36",
+    "/tibt:caretdzudrtagsmelongcanmark": "\u0F13",
+    "/tibt:caretyigmgophurshadmamark": "\u0F06",
+    "/tibt:casubjoined": "\u0F95",
+    "/tibt:cha": "\u0F46",
+    "/tibt:chadrtagslogotypesign": "\u0F15",
+    "/tibt:chasubjoined": "\u0F96",
+    "/tibt:chemgomark": "\u0F38",
+    "/tibt:da": "\u0F51",
+    "/tibt:dasubjoined": "\u0FA1",
+    "/tibt:dda": "\u0F4C",
+    "/tibt:ddasubjoined": "\u0F9C",
+    "/tibt:ddha": "\u0F4D",
+    "/tibt:ddhasubjoined": "\u0F9D",
+    "/tibt:delimitertshegbstarmark": "\u0F0C",
+    "/tibt:dha": "\u0F52",
+    "/tibt:dhasubjoined": "\u0FA2",
+    "/tibt:drilbusymbol": "\u0FC4",
+    "/tibt:dza": "\u0F5B",
+    "/tibt:dzasubjoined": "\u0FAB",
+    "/tibt:dzha": "\u0F5C",
+    "/tibt:dzhasubjoined": "\u0FAC",
+    "/tibt:eevowelsign": "\u0F7B",
+    "/tibt:eight": "\u0F28",
+    "/tibt:evowelsign": "\u0F7A",
+    "/tibt:five": "\u0F25",
+    "/tibt:four": "\u0F24",
+    "/tibt:ga": "\u0F42",
+    "/tibt:gasubjoined": "\u0F92",
+    "/tibt:gha": "\u0F43",
+    "/tibt:ghasubjoined": "\u0F93",
+    "/tibt:grucanrgyingssign": "\u0F8A",
+    "/tibt:grumedrgyingssign": "\u0F8B",
+    "/tibt:gtertshegmark": "\u0F14",
+    "/tibt:gteryigmgotruncatedamark": "\u0F01",
+    "/tibt:gteryigmgoumgtertshegmamark": "\u0F03",
+    "/tibt:gteryigmgoumrnambcadmamark": "\u0F02",
+    "/tibt:gugrtagsgyasmark": "\u0F3B",
+    "/tibt:gugrtagsgyonmark": "\u0F3A",
+    "/tibt:ha": "\u0F67",
+    "/tibt:halantamark": "\u0F84",
+    "/tibt:halfeight": "\u0F31",
+    "/tibt:halffive": "\u0F2E",
+    "/tibt:halffour": "\u0F2D",
+    "/tibt:halfnine": "\u0F32",
+    "/tibt:halfone": "\u0F2A",
+    "/tibt:halfseven": "\u0F30",
+    "/tibt:halfsix": "\u0F2F",
+    "/tibt:halfthree": "\u0F2C",
+    "/tibt:halftwo": "\u0F2B",
+    "/tibt:halfzero": "\u0F33",
+    "/tibt:hasubjoined": "\u0FB7",
+    "/tibt:heavybeatcantillationsign": "\u0FC0",
+    "/tibt:iivowelsign": "\u0F73",
+    "/tibt:intersyllabictshegmark": "\u0F0B",
+    "/tibt:invertedmchucansign": "\u0F8C",
+    "/tibt:invertedmchucansubjoinedsign": "\u0F8F",
+    "/tibt:ivowelsign": "\u0F72",
+    "/tibt:ja": "\u0F47",
+    "/tibt:jasubjoined": "\u0F97",
+    "/tibt:ka": "\u0F40",
+    "/tibt:kasubjoined": "\u0F90",
+    "/tibt:kha": "\u0F41",
+    "/tibt:khasubjoined": "\u0F91",
+    "/tibt:kka": "\u0F6B",
+    "/tibt:kssa": "\u0F69",
+    "/tibt:kssasubjoined": "\u0FB9",
+    "/tibt:kurukha": "\u0FBE",
+    "/tibt:kurukhabzhimigcan": "\u0FBF",
+    "/tibt:la": "\u0F63",
+    "/tibt:lasubjoined": "\u0FB3",
+    "/tibt:lcetsacansign": "\u0F88",
+    "/tibt:lcetsacansubjoinedsign": "\u0F8D",
+    "/tibt:lcirtagssign": "\u0F86",
+    "/tibt:leadingmchanrtagsmark": "\u0FD9",
+    "/tibt:lhagrtagslogotypesign": "\u0F16",
+    "/tibt:lightbeatcantillationsign": "\u0FC1",
+    "/tibt:llvocalicvowelsign": "\u0F79",
+    "/tibt:lvocalicvowelsign": "\u0F78",
+    "/tibt:ma": "\u0F58",
+    "/tibt:martshessign": "\u0F3F",
+    "/tibt:masubjoined": "\u0FA8",
+    "/tibt:mchucansign": "\u0F89",
+    "/tibt:mchucansubjoinedsign": "\u0F8E",
+    "/tibt:mnyamyiggimgorgyanmark": "\u0FD1",
+    "/tibt:na": "\u0F53",
+    "/tibt:nasubjoined": "\u0FA3",
+    "/tibt:nga": "\u0F44",
+    "/tibt:ngasbzungnyizlamark": "\u0F35",
+    "/tibt:ngasbzungsgorrtagsmark": "\u0F37",
+    "/tibt:ngasubjoined": "\u0F94",
+    "/tibt:nine": "\u0F29",
+    "/tibt:nna": "\u0F4E",
+    "/tibt:nnasubjoined": "\u0F9E",
+    "/tibt:norbubzhikhyilsymbol": "\u0FCC",
+    "/tibt:norbugsumkhyilsymbol": "\u0FCB",
+    "/tibt:norbunyiskhyilsymbol": "\u0FCA",
+    "/tibt:norbusymbol": "\u0FC9",
+    "/tibt:nya": "\u0F49",
+    "/tibt:nyasubjoined": "\u0F99",
+    "/tibt:nyisshadmark": "\u0F0E",
+    "/tibt:nyistshegmark": "\u0FD2",
+    "/tibt:nyistshegshadmark": "\u0F10",
+    "/tibt:nyizlanaadasign": "\u0F82",
+    "/tibt:omsyllable": "\u0F00",
+    "/tibt:one": "\u0F21",
+    "/tibt:oovowelsign": "\u0F7D",
+    "/tibt:ovowelsign": "\u0F7C",
+    "/tibt:pa": "\u0F54",
+    "/tibt:padmagdansymbol": "\u0FC6",
+    "/tibt:palutamark": "\u0F85",
+    "/tibt:pasubjoined": "\u0FA4",
+    "/tibt:pha": "\u0F55",
+    "/tibt:phasubjoined": "\u0FA5",
+    "/tibt:phurpasymbol": "\u0FC8",
+    "/tibt:ra": "\u0F62",
+    "/tibt:rafixed": "\u0F6A",
+    "/tibt:rasubjoined": "\u0FB2",
+    "/tibt:rasubjoinedfixed": "\u0FBC",
+    "/tibt:rdeldkargcigsign": "\u0F1A",
+    "/tibt:rdeldkargnyissign": "\u0F1B",
+    "/tibt:rdeldkargsumsign": "\u0F1C",
+    "/tibt:rdeldkarrdelnagsign": "\u0F1F",
+    "/tibt:rdelnaggcigsign": "\u0F1D",
+    "/tibt:rdelnaggnyissign": "\u0F1E",
+    "/tibt:rdelnaggsumsign": "\u0FCF",
+    "/tibt:rdelnagrdeldkarsign": "\u0FCE",
+    "/tibt:rdorjergyagramsymbol": "\u0FC7",
+    "/tibt:rdorjesymbol": "\u0FC5",
+    "/tibt:reversediivowelsign": "\u0F81",
+    "/tibt:reversedivowelsign": "\u0F80",
+    "/tibt:rgyagramshadmark": "\u0F12",
+    "/tibt:rinchenspungsshadmark": "\u0F11",
+    "/tibt:rjessungarosign": "\u0F7E",
+    "/tibt:rnambcadsign": "\u0F7F",
+    "/tibt:rra": "\u0F6C",
+    "/tibt:rrvocalicvowelsign": "\u0F77",
+    "/tibt:rvocalicvowelsign": "\u0F76",
+    "/tibt:sa": "\u0F66",
+    "/tibt:sasubjoined": "\u0FB6",
+    "/tibt:sbrulshadmark": "\u0F08",
+    "/tibt:sbubchalcantillationsign": "\u0FC3",
+    "/tibt:seven": "\u0F27",
+    "/tibt:sha": "\u0F64",
+    "/tibt:shadmark": "\u0F0D",
+    "/tibt:shasubjoined": "\u0FB4",
+    "/tibt:six": "\u0F26",
+    "/tibt:snaldansign": "\u0F83",
+    "/tibt:ssa": "\u0F65",
+    "/tibt:ssasubjoined": "\u0FB5",
+    "/tibt:subjoinedAA": "\u0FB0",
+    "/tibt:svastileft": "\u0FD6",
+    "/tibt:svastileftdot": "\u0FD8",
+    "/tibt:svastiright": "\u0FD5",
+    "/tibt:svastirightdot": "\u0FD7",
+    "/tibt:ta": "\u0F4F",
+    "/tibt:tasubjoined": "\u0F9F",
+    "/tibt:tha": "\u0F50",
+    "/tibt:thasubjoined": "\u0FA0",
+    "/tibt:three": "\u0F23",
+    "/tibt:trailingmchanrtagsmark": "\u0FDA",
+    "/tibt:tsa": "\u0F59",
+    "/tibt:tsaphrumark": "\u0F39",
+    "/tibt:tsasubjoined": "\u0FA9",
+    "/tibt:tsha": "\u0F5A",
+    "/tibt:tshasubjoined": "\u0FAA",
+    "/tibt:tshegshadmark": "\u0F0F",
+    "/tibt:tta": "\u0F4A",
+    "/tibt:ttasubjoined": "\u0F9A",
+    "/tibt:ttha": "\u0F4B",
+    "/tibt:tthasubjoined": "\u0F9B",
+    "/tibt:two": "\u0F22",
+    "/tibt:uuvowelsign": "\u0F75",
+    "/tibt:uvowelsign": "\u0F74",
+    "/tibt:wa": "\u0F5D",
+    "/tibt:wasubjoined": "\u0FAD",
+    "/tibt:wasubjoinedfixed": "\u0FBA",
+    "/tibt:ya": "\u0F61",
+    "/tibt:yangrtagssign": "\u0F87",
+    "/tibt:yartshessign": "\u0F3E",
+    "/tibt:yasubjoined": "\u0FB1",
+    "/tibt:yasubjoinedfixed": "\u0FBB",
+    "/tibt:yigmgomdunmainitialmark": "\u0F04",
+    "/tibt:yigmgosgabmaclosingmark": "\u0F05",
+    "/tibt:yigmgotshegshadmamark": "\u0F07",
+    "/tibt:za": "\u0F5F",
+    "/tibt:zasubjoined": "\u0FAF",
+    "/tibt:zero": "\u0F20",
+    "/tibt:zha": "\u0F5E",
+    "/tibt:zhasubjoined": "\u0FAE",
+    "/ticirclekatakana": "\u32E0",
+    "/tickconvavediamondleftwhite": "\u27E2",
+    "/tickconvavediamondrightwhite": "\u27E3",
+    "/ticket": "\u1F3AB",
+    "/tickleftwhitesquare": "\u27E4",
+    "/tickrightwhitesquare": "\u27E5",
+    "/tifcha:hb": "\u0596",
+    "/tiger": "\u1F405",
+    "/tigerFace": "\u1F42F",
+    "/tihiragana": "\u3061",
+    "/tikatakana": "\u30C1",
+    "/tikatakanahalfwidth": "\uFF81",
+    "/tikeutacirclekorean": "\u3270",
+    "/tikeutaparenkorean": "\u3210",
+    "/tikeutcirclekorean": "\u3262",
+    "/tikeutkorean": "\u3137",
+    "/tikeutparenkorean": "\u3202",
+    "/tilde": "\u02DC",
+    "/tildebelowcmb": "\u0330",
+    "/tildecmb": "\u0303",
+    "/tildecomb": "\u0303",
+    "/tildediaeresisfunc": "\u2368",
+    "/tildedotaccent": "\u2E1E",
+    "/tildedotbelow": "\u2E1F",
+    "/tildedoublecmb": "\u0360",
+    "/tildeequalsreversed": "\u22CD",
+    "/tildelowmod": "\u02F7",
+    "/tildeoperator": "\u223C",
+    "/tildeoverlaycmb": "\u0334",
+    "/tildereversed": "\u223D",
+    "/tildering": "\u2E1B",
+    "/tildetpl": "\u224B",
+    "/tildeverticalcmb": "\u033E",
+    "/timerclock": "\u23F2",
+    "/timescircle": "\u2297",
+    "/tinsular": "\uA787",
+    "/tipehahebrew": "\u0596",
+    "/tipehalefthebrew": "\u0596",
+    "/tippigurmukhi": "\u0A70",
+    "/tiredFace": "\u1F62B",
+    "/tironiansignet": "\u204A",
+    "/tirtatumetespada": "\uA9DE",
+    "/titlocmbcyr": "\u0483",
+    "/titlocyrilliccmb": "\u0483",
+    "/tiwnarmenian": "\u057F",
+    "/tjekomicyr": "\u050F",
+    "/tlinebelow": "\u1E6F",
+    "/tmonospace": "\uFF54",
+    "/toarmenian": "\u0569",
+    "/tocirclekatakana": "\u32E3",
+    "/tocornerarrowNW": "\u21F1",
+    "/tocornerarrowSE": "\u21F2",
+    "/tohiragana": "\u3068",
+    "/toilet": "\u1F6BD",
+    "/tokatakana": "\u30C8",
+    "/tokatakanahalfwidth": "\uFF84",
+    "/tokyoTower": "\u1F5FC",
+    "/tolongvowel": "\uA9B5",
+    "/tomato": "\u1F345",
+    "/tonebarextrahighmod": "\u02E5",
+    "/tonebarextralowmod": "\u02E9",
+    "/tonebarhighmod": "\u02E6",
+    "/tonebarlowmod": "\u02E8",
+    "/tonebarmidmod": "\u02E7",
+    "/tonefive": "\u01BD",
+    "/tonehighbeginmod": "\u02F9",
+    "/tonehighendmod": "\u02FA",
+    "/tonelowbeginmod": "\u02FB",
+    "/tonelowendmod": "\u02FC",
+    "/tonesix": "\u0185",
+    "/tonetwo": "\u01A8",
+    "/tongue": "\u1F445",
+    "/tonos": "\u0384",
+    "/tonsquare": "\u3327",
+    "/topHat": "\u1F3A9",
+    "/topUpwardsArrowAbove": "\u1F51D",
+    "/topatakthai": "\u0E0F",
+    "/tortoiseshellbracketleft": "\u3014",
+    "/tortoiseshellbracketleftsmall": "\uFE5D",
+    "/tortoiseshellbracketleftvertical": "\uFE39",
+    "/tortoiseshellbracketright": "\u3015",
+    "/tortoiseshellbracketrightsmall": "\uFE5E",
+    "/tortoiseshellbracketrightvertical": "\uFE3A",
+    "/totalrunout": "\u2330",
+    "/totaothai": "\u0E15",
+    "/tpalatalhook": "\u01AB",
+    "/tparen": "\u24AF",
+    "/tparenthesized": "\u24AF",
+    "/trackball": "\u1F5B2",
+    "/tractor": "\u1F69C",
+    "/trademark": "\u2122",
+    "/trademarksans": "\uF8EA",
+    "/trademarkserif": "\uF6DB",
+    "/train": "\u1F686",
+    "/tram": "\u1F68A",
+    "/tramCar": "\u1F68B",
+    "/trapeziumwhite": "\u23E2",
+    "/tresillo": "\uA72B",
+    "/tretroflex": "\u0288",
+    "/tretroflexhook": "\u0288",
+    "/triagdn": "\u25BC",
+    "/triaglf": "\u25C4",
+    "/triagrt": "\u25BA",
+    "/triagup": "\u25B2",
+    "/triangleWithRoundedCorners": "\u1F6C6",
+    "/triangledotupwhite": "\u25EC",
+    "/triangledownblack": "\u25BC",
+    "/triangledownsmallblack": "\u25BE",
+    "/triangledownsmallwhite": "\u25BF",
+    "/triangledownwhite": "\u25BD",
+    "/trianglehalfupleftblack": "\u25ED",
+    "/trianglehalfuprightblack": "\u25EE",
+    "/triangleleftblack": "\u25C0",
+    "/triangleleftsmallblack": "\u25C2",
+    "/triangleleftsmallwhite": "\u25C3",
+    "/triangleleftwhite": "\u25C1",
+    "/triangleright": "\u22BF",
+    "/trianglerightblack": "\u25B6",
+    "/trianglerightsmallblack": "\u25B8",
+    "/trianglerightsmallwhite": "\u25B9",
+    "/trianglerightwhite": "\u25B7",
+    "/triangleupblack": "\u25B2",
+    "/triangleupsmallblack": "\u25B4",
+    "/triangleupsmallwhite": "\u25B5",
+    "/triangleupwhite": "\u25B3",
+    "/triangularFlagOnPost": "\u1F6A9",
+    "/triangularRuler": "\u1F4D0",
+    "/triangularbullet": "\u2023",
+    "/tricolon": "\u205D",
+    "/tricontainingtriwhiteanglesmall": "\u27C1",
+    "/tridentEmblem": "\u1F531",
+    "/trigramearth": "\u2637",
+    "/trigramfire": "\u2632",
+    "/trigramheaven": "\u2630",
+    "/trigramlake": "\u2631",
+    "/trigrammountain": "\u2636",
+    "/trigramthunder": "\u2633",
+    "/trigramwater": "\u2635",
+    "/trigramwind": "\u2634",
+    "/triplearrowleft": "\u21DA",
+    "/triplearrowright": "\u21DB",
+    "/tripledot": "\u061E",
+    "/trisememetrical": "\u23D7",
+    "/trns:baby": "\u1F6BC",
+    "/trolleybus": "\u1F68E",
+    "/trophy": "\u1F3C6",
+    "/tropicalDrink": "\u1F379",
+    "/tropicalFish": "\u1F420",
+    "/truckblack": "\u26DF",
+    "/true": "\u22A8",
+    "/trumpet": "\u1F3BA",
+    "/ts": "\u02A6",
+    "/tsadi": "\u05E6",
+    "/tsadi:hb": "\u05E6",
+    "/tsadidagesh": "\uFB46",
+    "/tsadidageshhebrew": "\uFB46",
+    "/tsadihebrew": "\u05E6",
+    "/tsadiwithdagesh:hb": "\uFB46",
+    "/tsecyr": "\u0446",
+    "/tsecyrillic": "\u0446",
+    "/tsere": "\u05B5",
+    "/tsere12": "\u05B5",
+    "/tsere1e": "\u05B5",
+    "/tsere2b": "\u05B5",
+    "/tsere:hb": "\u05B5",
+    "/tserehebrew": "\u05B5",
+    "/tserenarrowhebrew": "\u05B5",
+    "/tserequarterhebrew": "\u05B5",
+    "/tserewidehebrew": "\u05B5",
+    "/tshecyr": "\u045B",
+    "/tshecyrillic": "\u045B",
+    "/tsinnorit:hb": "\u05AE",
+    "/tstroke": "\u2C66",
+    "/tsuperior": "\uF6F3",
+    "/ttabengali": "\u099F",
+    "/ttadeva": "\u091F",
+    "/ttagujarati": "\u0A9F",
+    "/ttagurmukhi": "\u0A1F",
+    "/ttamahaprana": "\uA99C",
+    "/tteh": "\u0679",
+    "/tteh.fina": "\uFB67",
+    "/tteh.init": "\uFB68",
+    "/tteh.isol": "\uFB66",
+    "/tteh.medi": "\uFB69",
+    "/tteharabic": "\u0679",
+    "/tteheh": "\u067A",
+    "/tteheh.fina": "\uFB5F",
+    "/tteheh.init": "\uFB60",
+    "/tteheh.isol": "\uFB5E",
+    "/tteheh.medi": "\uFB61",
+    "/ttehfinalarabic": "\uFB67",
+    "/ttehinitialarabic": "\uFB68",
+    "/ttehmedialarabic": "\uFB69",
+    "/tthabengali": "\u09A0",
+    "/tthadeva": "\u0920",
+    "/tthagujarati": "\u0AA0",
+    "/tthagurmukhi": "\u0A20",
+    "/tturned": "\u0287",
+    "/tucirclekatakana": "\u32E1",
+    "/tugrik": "\u20AE",
+    "/tuhiragana": "\u3064",
+    "/tukatakana": "\u30C4",
+    "/tukatakanahalfwidth": "\uFF82",
+    "/tulip": "\u1F337",
+    "/tum": "\uA777",
+    "/turkishlira": "\u20BA",
+    "/turnedOkHandSign": "\u1F58F",
+    "/turnedcomma": "\u2E32",
+    "/turneddagger": "\u2E38",
+    "/turneddigitthree": "\u218B",
+    "/turneddigittwo": "\u218A",
+    "/turnedpiselehpada": "\uA9CD",
+    "/turnedsemicolon": "\u2E35",
+    "/turnedshogipieceblack": "\u26CA",
+    "/turnedshogipiecewhite": "\u26C9",
+    "/turnstiledblverticalbarright": "\u22AB",
+    "/turnstileleftrightdbl": "\u27DA",
+    "/turnstiletplverticalbarright": "\u22AA",
+    "/turtle": "\u1F422",
+    "/tusmallhiragana": "\u3063",
+    "/tusmallkatakana": "\u30C3",
+    "/tusmallkatakanahalfwidth": "\uFF6F",
+    "/twelve.roman": "\u216B",
+    "/twelve.romansmall": "\u217B",
+    "/twelvecircle": "\u246B",
+    "/twelvecircleblack": "\u24EC",
+    "/twelveparen": "\u247F",
+    "/twelveparenthesized": "\u247F",
+    "/twelveperiod": "\u2493",
+    "/twelveroman": "\u217B",
+    "/twenty-twopointtwosquare": "\u1F1A2",
+    "/twentycircle": "\u2473",
+    "/twentycircleblack": "\u24F4",
+    "/twentycirclesquare": "\u3249",
+    "/twentyeightcircle": "\u3258",
+    "/twentyfivecircle": "\u3255",
+    "/twentyfourcircle": "\u3254",
+    "/twentyhangzhou": "\u5344",
+    "/twentyninecircle": "\u3259",
+    "/twentyonecircle": "\u3251",
+    "/twentyparen": "\u2487",
+    "/twentyparenthesized": "\u2487",
+    "/twentyperiod": "\u249B",
+    "/twentysevencircle": "\u3257",
+    "/twentysixcircle": "\u3256",
+    "/twentythreecircle": "\u3253",
+    "/twentytwocircle": "\u3252",
+    "/twistedRightwardsArrows": "\u1F500",
+    "/two": "\u0032",
+    "/two.inferior": "\u2082",
+    "/two.roman": "\u2161",
+    "/two.romansmall": "\u2171",
+    "/twoButtonMouse": "\u1F5B0",
+    "/twoHearts": "\u1F495",
+    "/twoMenHoldingHands": "\u1F46C",
+    "/twoSpeechBubbles": "\u1F5EA",
+    "/twoWomenHoldingHands": "\u1F46D",
+    "/twoarabic": "\u0662",
+    "/twoasterisksalignedvertically": "\u2051",
+    "/twobengali": "\u09E8",
+    "/twocircle": "\u2461",
+    "/twocircledbl": "\u24F6",
+    "/twocircleinversesansserif": "\u278B",
+    "/twocomma": "\u1F103",
+    "/twodeva": "\u0968",
+    "/twodotenleader": "\u2025",
+    "/twodotleader": "\u2025",
+    "/twodotleadervertical": "\uFE30",
+    "/twodotpunctuation": "\u205A",
+    "/twodotsoveronedot": "\u2E2A",
+    "/twofar": "\u06F2",
+    "/twofifths": "\u2156",
+    "/twogujarati": "\u0AE8",
+    "/twogurmukhi": "\u0A68",
+    "/twohackarabic": "\u0662",
+    "/twohangzhou": "\u3022",
+    "/twoideographiccircled": "\u3281",
+    "/twoideographicparen": "\u3221",
+    "/twoinferior": "\u2082",
+    "/twoksquare": "\u1F19D",
+    "/twomonospace": "\uFF12",
+    "/twonumeratorbengali": "\u09F5",
+    "/twooldstyle": "\uF732",
+    "/twoparen": "\u2475",
+    "/twoparenthesized": "\u2475",
+    "/twoperiod": "\u2489",
+    "/twopersian": "\u06F2",
+    "/tworoman": "\u2171",
+    "/twoshortsjoinedmetrical": "\u23D6",
+    "/twoshortsoverlongmetrical": "\u23D5",
+    "/twostroke": "\u01BB",
+    "/twosuperior": "\u00B2",
+    "/twothai": "\u0E52",
+    "/twothirds": "\u2154",
+    "/twowayleftwaytrafficblack": "\u26D6",
+    "/twowayleftwaytrafficwhite": "\u26D7",
+    "/tz": "\uA729",
+    "/u": "\u0075",
+    "/u.fina": "\uFBD8",
+    "/u.isol": "\uFBD7",
+    "/uacute": "\u00FA",
+    "/uacutedblcyr": "\u04F3",
+    "/ubar": "\u0289",
+    "/ubengali": "\u0989",
+    "/ubopomofo": "\u3128",
+    "/ubracketleft": "\u2E26",
+    "/ubracketright": "\u2E27",
+    "/ubreve": "\u016D",
+    "/ucaron": "\u01D4",
+    "/ucircle": "\u24E4",
+    "/ucirclekatakana": "\u32D2",
+    "/ucircumflex": "\u00FB",
+    "/ucircumflexbelow": "\u1E77",
+    "/ucyr": "\u0443",
+    "/ucyrillic": "\u0443",
+    "/udattadeva": "\u0951",
+    "/udblacute": "\u0171",
+    "/udblgrave": "\u0215",
+    "/udeva": "\u0909",
+    "/udieresis": "\u00FC",
+    "/udieresisacute": "\u01D8",
+    "/udieresisbelow": "\u1E73",
+    "/udieresiscaron": "\u01DA",
+    "/udieresiscyr": "\u04F1",
+    "/udieresiscyrillic": "\u04F1",
+    "/udieresisgrave": "\u01DC",
+    "/udieresismacron": "\u01D6",
+    "/udotbelow": "\u1EE5",
+    "/ugrave": "\u00F9",
+    "/ugravedbl": "\u0215",
+    "/ugujarati": "\u0A89",
+    "/ugurmukhi": "\u0A09",
+    "/uhamza": "\u0677",
+    "/uhamza.isol": "\uFBDD",
+    "/uhdsquare": "\u1F1AB",
+    "/uhiragana": "\u3046",
+    "/uhoi": "\u1EE7",
+    "/uhookabove": "\u1EE7",
+    "/uhorn": "\u01B0",
+    "/uhornacute": "\u1EE9",
+    "/uhorndotbelow": "\u1EF1",
+    "/uhorngrave": "\u1EEB",
+    "/uhornhoi": "\u1EED",
+    "/uhornhookabove": "\u1EED",
+    "/uhorntilde": "\u1EEF",
+    "/uhungarumlaut": "\u0171",
+    "/uhungarumlautcyrillic": "\u04F3",
+    "/uighurkazakhkirghizalefmaksura.init": "\uFBE8",
+    "/uighurkazakhkirghizalefmaksura.medi": "\uFBE9",
+    "/uighurkirghizyeh.init_hamzaabove.medi_alefmaksura.fina": "\uFBF9",
+    "/uighurkirghizyeh.init_hamzaabove.medi_alefmaksura.medi": "\uFBFB",
+    "/uighurkirghizyeh.medi_hamzaabove.medi_alefmaksura.fina": "\uFBFA",
+    "/uinvertedbreve": "\u0217",
+    "/ukatakana": "\u30A6",
+    "/ukatakanahalfwidth": "\uFF73",
+    "/ukcyr": "\u0479",
+    "/ukcyrillic": "\u0479",
+    "/ukorean": "\u315C",
+    "/um": "\uA778",
+    "/umacron": "\u016B",
+    "/umacroncyr": "\u04EF",
+    "/umacroncyrillic": "\u04EF",
+    "/umacrondieresis": "\u1E7B",
+    "/umatragurmukhi": "\u0A41",
+    "/umbrella": "\u2602",
+    "/umbrellaonground": "\u26F1",
+    "/umbrellaraindrops": "\u2614",
+    "/umonospace": "\uFF55",
+    "/unamusedFace": "\u1F612",
+    "/unaspiratedmod": "\u02ED",
+    "/underscore": "\u005F",
+    "/underscorecenterline": "\uFE4E",
+    "/underscoredashed": "\uFE4D",
+    "/underscoredbl": "\u2017",
+    "/underscoremonospace": "\uFF3F",
+    "/underscorevertical": "\uFE33",
+    "/underscorewavy": "\uFE4F",
+    "/underscorewavyvertical": "\uFE34",
+    "/undertie": "\u203F",
+    "/undo": "\u238C",
+    "/union": "\u222A",
+    "/unionarray": "\u22C3",
+    "/uniondbl": "\u22D3",
+    "/universal": "\u2200",
+    "/unmarriedpartnership": "\u26AF",
+    "/uogonek": "\u0173",
+    "/uonsquare": "\u3306",
+    "/upPointingAirplane": "\u1F6E7",
+    "/upPointingMilitaryAirplane": "\u1F6E6",
+    "/upPointingSmallAirplane": "\u1F6E8",
+    "/uparen": "\u24B0",
+    "/uparenthesized": "\u24B0",
+    "/uparrowleftofdownarrow": "\u21C5",
+    "/upblock": "\u2580",
+    "/updblhorzsng": "\u2568",
+    "/updblleftsng": "\u255C",
+    "/updblrightsng": "\u2559",
+    "/upheavydnhorzlight": "\u2540",
+    "/upheavyhorzlight": "\u2538",
+    "/upheavyleftdnlight": "\u2526",
+    "/upheavyleftlight": "\u251A",
+    "/upheavyrightdnlight": "\u251E",
+    "/upheavyrightlight": "\u2516",
+    "/uplightdnhorzheavy": "\u2548",
+    "/uplighthorzheavy": "\u2537",
+    "/uplightleftdnheavy": "\u252A",
+    "/uplightleftheavy": "\u2519",
+    "/uplightrightdnheavy": "\u2522",
+    "/uplightrightheavy": "\u2515",
+    "/upperHalfBlock": "\u2580",
+    "/upperOneEighthBlock": "\u2594",
+    "/upperRightShadowedWhiteCircle": "\u1F53F",
+    "/upperdothebrew": "\u05C4",
+    "/upperhalfcircle": "\u25E0",
+    "/upperhalfcircleinversewhite": "\u25DA",
+    "/upperquadrantcirculararcleft": "\u25DC",
+    "/upperquadrantcirculararcright": "\u25DD",
+    "/uppertriangleleft": "\u25F8",
+    "/uppertriangleleftblack": "\u25E4",
+    "/uppertriangleright": "\u25F9",
+    "/uppertrianglerightblack": "\u25E5",
+    "/upsideDownFace": "\u1F643",
+    "/upsilon": "\u03C5",
+    "/upsilonacute": "\u1F7B",
+    "/upsilonasper": "\u1F51",
+    "/upsilonasperacute": "\u1F55",
+    "/upsilonaspergrave": "\u1F53",
+    "/upsilonaspertilde": "\u1F57",
+    "/upsilonbreve": "\u1FE0",
+    "/upsilondieresis": "\u03CB",
+    "/upsilondieresisacute": "\u1FE3",
+    "/upsilondieresisgrave": "\u1FE2",
+    "/upsilondieresistilde": "\u1FE7",
+    "/upsilondieresistonos": "\u03B0",
+    "/upsilongrave": "\u1F7A",
+    "/upsilonlatin": "\u028A",
+    "/upsilonlenis": "\u1F50",
+    "/upsilonlenisacute": "\u1F54",
+    "/upsilonlenisgrave": "\u1F52",
+    "/upsilonlenistilde": "\u1F56",
+    "/upsilontilde": "\u1FE6",
+    "/upsilontonos": "\u03CD",
+    "/upsilonwithmacron": "\u1FE1",
+    "/upsnghorzdbl": "\u2567",
+    "/upsngleftdbl": "\u255B",
+    "/upsngrightdbl": "\u2558",
+    "/uptackbelowcmb": "\u031D",
+    "/uptackmod": "\u02D4",
+    "/upwithexclamationmarksquare": "\u1F199",
+    "/uragurmukhi": "\u0A73",
+    "/uranus": "\u2645",
+    "/uring": "\u016F",
+    "/ushortcyr": "\u045E",
+    "/ushortcyrillic": "\u045E",
+    "/usmallhiragana": "\u3045",
+    "/usmallkatakana": "\u30A5",
+    "/usmallkatakanahalfwidth": "\uFF69",
+    "/usmod": "\uA770",
+    "/ustraightcyr": "\u04AF",
+    "/ustraightcyrillic": "\u04AF",
+    "/ustraightstrokecyr": "\u04B1",
+    "/ustraightstrokecyrillic": "\u04B1",
+    "/utilde": "\u0169",
+    "/utildeacute": "\u1E79",
+    "/utildebelow": "\u1E75",
+    "/uubengali": "\u098A",
+    "/uudeva": "\u090A",
+    "/uugujarati": "\u0A8A",
+    "/uugurmukhi": "\u0A0A",
+    "/uumatragurmukhi": "\u0A42",
+    "/uuvowelsignbengali": "\u09C2",
+    "/uuvowelsigndeva": "\u0942",
+    "/uuvowelsigngujarati": "\u0AC2",
+    "/uvowelsignbengali": "\u09C1",
+    "/uvowelsigndeva": "\u0941",
+    "/uvowelsigngujarati": "\u0AC1",
+    "/v": "\u0076",
+    "/vadeva": "\u0935",
+    "/vagujarati": "\u0AB5",
+    "/vagurmukhi": "\u0A35",
+    "/vakatakana": "\u30F7",
+    "/vanedownfunc": "\u2356",
+    "/vaneleftfunc": "\u2345",
+    "/vanerightfunc": "\u2346",
+    "/vaneupfunc": "\u234F",
+    "/varikajudeospanish:hb": "\uFB1E",
+    "/vav": "\u05D5",
+    "/vav:hb": "\u05D5",
+    "/vav_vav:hb": "\u05F0",
+    "/vav_yod:hb": "\u05F1",
+    "/vavdagesh": "\uFB35",
+    "/vavdagesh65": "\uFB35",
+    "/vavdageshhebrew": "\uFB35",
+    "/vavhebrew": "\u05D5",
+    "/vavholam": "\uFB4B",
+    "/vavholamhebrew": "\uFB4B",
+    "/vavvavhebrew": "\u05F0",
+    "/vavwithdagesh:hb": "\uFB35",
+    "/vavwithholam:hb": "\uFB4B",
+    "/vavyodhebrew": "\u05F1",
+    "/vcircle": "\u24E5",
+    "/vcurl": "\u2C74",
+    "/vdiagonalstroke": "\uA75F",
+    "/vdotbelow": "\u1E7F",
+    "/ve.fina": "\uFBDF",
+    "/ve.isol": "\uFBDE",
+    "/ve:abovetonecandra": "\u1CF4",
+    "/ve:anusvaraantargomukhasign": "\u1CE9",
+    "/ve:anusvarabahirgomukhasign": "\u1CEA",
+    "/ve:anusvarasignlong": "\u1CEF",
+    "/ve:anusvaraubhayatomukhasign": "\u1CF1",
+    "/ve:anusvaravamagomukhasign": "\u1CEB",
+    "/ve:anusvaravamagomukhawithtailsign": "\u1CEC",
+    "/ve:ardhavisargasign": "\u1CF2",
+    "/ve:atharvaindependentsvaritatone": "\u1CE1",
+    "/ve:atikramasign": "\u1CF7",
+    "/ve:belowtonecandra": "\u1CD8",
+    "/ve:dotbelowtone": "\u1CDD",
+    "/ve:hexiformanusvarasignlong": "\u1CEE",
+    "/ve:jihvamuliyasign": "\u1CF5",
+    "/ve:karshanatone": "\u1CD0",
+    "/ve:kathakaanudattatone": "\u1CDC",
+    "/ve:nihshvasasign": "\u1CD3",
+    "/ve:prenkhatone": "\u1CD2",
+    "/ve:rigkashmiriindependentsvaritatone": "\u1CE0",
+    "/ve:ringabovetone": "\u1CF8",
+    "/ve:ringabovetonedbl": "\u1CF9",
+    "/ve:rotatedardhavisargasign": "\u1CF3",
+    "/ve:rthanganusvarasignlong": "\u1CF0",
+    "/ve:sharatone": "\u1CD1",
+    "/ve:svaritatonedbl": "\u1CDA",
+    "/ve:svaritatonetpl": "\u1CDB",
+    "/ve:threedotsbelowtone": "\u1CDF",
+    "/ve:tiryaksign": "\u1CED",
+    "/ve:twodotsbelowtone": "\u1CDE",
+    "/ve:upadhmaniyasign": "\u1CF6",
+    "/ve:visargaanudattasign": "\u1CE5",
+    "/ve:visargaanudattasignreversed": "\u1CE6",
+    "/ve:visargaanudattawithtailsign": "\u1CE8",
+    "/ve:visargasvaritasign": "\u1CE2",
+    "/ve:visargaudattasign": "\u1CE3",
+    "/ve:visargaudattasignreversed": "\u1CE4",
+    "/ve:visargaudattawithtailsign": "\u1CE7",
+    "/ve:yajuraggravatedindependentsvaritatone": "\u1CD5",
+    "/ve:yajurindependentsvaritatone": "\u1CD6",
+    "/ve:yajurkathakaindependentsvaritaschroedertone": "\u1CD9",
+    "/ve:yajurkathakaindependentsvaritatone": "\u1CD7",
+    "/ve:yajurmidlinesvaritasign": "\u1CD4",
+    "/vecyr": "\u0432",
+    "/vecyrillic": "\u0432",
+    "/veh": "\u06A4",
+    "/veh.fina": "\uFB6B",
+    "/veh.init": "\uFB6C",
+    "/veh.isol": "\uFB6A",
+    "/veh.medi": "\uFB6D",
+    "/veharabic": "\u06A4",
+    "/vehfinalarabic": "\uFB6B",
+    "/vehinitialarabic": "\uFB6C",
+    "/vehmedialarabic": "\uFB6D",
+    "/vekatakana": "\u30F9",
+    "/vend": "\uA769",
+    "/venus": "\u2640",
+    "/versicle": "\u2123",
+    "/vert:bracketwhiteleft": "\uFE17",
+    "/vert:brakcetwhiteright": "\uFE18",
+    "/vert:colon": "\uFE13",
+    "/vert:comma": "\uFE10",
+    "/vert:ellipsishor": "\uFE19",
+    "/vert:exclam": "\uFE15",
+    "/vert:ideographiccomma": "\uFE11",
+    "/vert:ideographicfullstop": "\uFE12",
+    "/vert:question": "\uFE16",
+    "/vert:semicolon": "\uFE14",
+    "/vertdblhorzsng": "\u256B",
+    "/vertdblleftsng": "\u2562",
+    "/vertdblrightsng": "\u255F",
+    "/vertheavyhorzlight": "\u2542",
+    "/vertheavyleftlight": "\u2528",
+    "/vertheavyrightlight": "\u2520",
+    "/verticalTrafficLight": "\u1F6A6",
+    "/verticalbar": "\u007C",
+    "/verticalbardbl": "\u2016",
+    "/verticalbarhorizontalstroke": "\u27CA",
+    "/verticalbarwhitearrowonpedestalup": "\u21ED",
+    "/verticalfourdots": "\u205E",
+    "/verticalideographiciterationmark": "\u303B",
+    "/verticalkanarepeatmark": "\u3031",
+    "/verticalkanarepeatmarklowerhalf": "\u3035",
+    "/verticalkanarepeatmarkupperhalf": "\u3033",
+    "/verticalkanarepeatwithvoicedsoundmark": "\u3032",
+    "/verticalkanarepeatwithvoicedsoundmarkupperhalf": "\u3034",
+    "/verticallineabovecmb": "\u030D",
+    "/verticallinebelowcmb": "\u0329",
+    "/verticallinelowmod": "\u02CC",
+    "/verticallinemod": "\u02C8",
+    "/verticalmalestroke": "\u26A8",
+    "/verticalsdbltrokearrowleft": "\u21FA",
+    "/verticalsdbltrokearrowleftright": "\u21FC",
+    "/verticalsdbltrokearrowright": "\u21FB",
+    "/verticalstrokearrowleft": "\u21F7",
+    "/verticalstrokearrowleftright": "\u21F9",
+    "/verticalstrokearrowright": "\u21F8",
+    "/vertlighthorzheavy": "\u253F",
+    "/vertlightleftheavy": "\u2525",
+    "/vertlightrightheavy": "\u251D",
+    "/vertsnghorzdbl": "\u256A",
+    "/vertsngleftdbl": "\u2561",
+    "/vertsngrightdbl": "\u255E",
+    "/verymuchgreater": "\u22D9",
+    "/verymuchless": "\u22D8",
+    "/vesta": "\u26B6",
+    "/vewarmenian": "\u057E",
+    "/vhook": "\u028B",
+    "/vibrationMode": "\u1F4F3",
+    "/videoCamera": "\u1F4F9",
+    "/videoGame": "\u1F3AE",
+    "/videocassette": "\u1F4FC",
+    "/viewdatasquare": "\u2317",
+    "/vikatakana": "\u30F8",
+    "/violin": "\u1F3BB",
+    "/viramabengali": "\u09CD",
+    "/viramadeva": "\u094D",
+    "/viramagujarati": "\u0ACD",
+    "/virgo": "\u264D",
+    "/visargabengali": "\u0983",
+    "/visargadeva": "\u0903",
+    "/visargagujarati": "\u0A83",
+    "/visigothicz": "\uA763",
+    "/vmonospace": "\uFF56",
+    "/voarmenian": "\u0578",
+    "/vodsquare": "\u1F1AC",
+    "/voicediterationhiragana": "\u309E",
+    "/voicediterationkatakana": "\u30FE",
+    "/voicedmarkkana": "\u309B",
+    "/voicedmarkkanahalfwidth": "\uFF9E",
+    "/voicingmod": "\u02EC",
+    "/vokatakana": "\u30FA",
+    "/volapukae": "\uA79B",
+    "/volapukoe": "\uA79D",
+    "/volapukue": "\uA79F",
+    "/volcano": "\u1F30B",
+    "/volleyball": "\u1F3D0",
+    "/vovermfullwidth": "\u33DE",
+    "/vowelVabove": "\u065A",
+    "/voweldotbelow": "\u065C",
+    "/vowelinvertedVabove": "\u065B",
+    "/vparen": "\u24B1",
+    "/vparenthesized": "\u24B1",
+    "/vrighthook": "\u2C71",
+    "/vssquare": "\u1F19A",
+    "/vtilde": "\u1E7D",
+    "/vturned": "\u028C",
+    "/vuhiragana": "\u3094",
+    "/vukatakana": "\u30F4",
+    "/vwelsh": "\u1EFD",
+    "/vy": "\uA761",
+    "/w": "\u0077",
+    "/wacirclekatakana": "\u32FB",
+    "/wacute": "\u1E83",
+    "/waekorean": "\u3159",
+    "/wahiragana": "\u308F",
+    "/wakatakana": "\u30EF",
+    "/wakatakanahalfwidth": "\uFF9C",
+    "/wakorean": "\u3158",
+    "/waningCrescentMoon": "\u1F318",
+    "/waningGibbousMoon": "\u1F316",
+    "/warning": "\u26A0",
+    "/wasmallhiragana": "\u308E",
+    "/wasmallkatakana": "\u30EE",
+    "/wastebasket": "\u1F5D1",
+    "/watch": "\u231A",
+    "/waterBuffalo": "\u1F403",
+    "/waterCloset": "\u1F6BE",
+    "/waterWave": "\u1F30A",
+    "/waterideographiccircled": "\u328C",
+    "/waterideographicparen": "\u322C",
+    "/watermelon": "\u1F349",
+    "/wattosquare": "\u3357",
+    "/wavedash": "\u301C",
+    "/wavingBlackFlag": "\u1F3F4",
+    "/wavingHandSign": "\u1F44B",
+    "/wavingWhiteFlag": "\u1F3F3",
+    "/wavydash": "\u3030",
+    "/wavyhamzabelow": "\u065F",
+    "/wavyline": "\u2307",
+    "/wavyunderscorevertical": "\uFE34",
+    "/waw": "\u0648",
+    "/waw.fina": "\uFEEE",
+    "/waw.isol": "\uFEED",
+    "/wawDigitThreeAbove": "\u0779",
+    "/wawDigitTwoAbove": "\u0778",
+    "/wawarabic": "\u0648",
+    "/wawdotabove": "\u06CF",
+    "/wawfinalarabic": "\uFEEE",
+    "/wawhamza": "\u0624",
+    "/wawhamza.fina": "\uFE86",
+    "/wawhamza.isol": "\uFE85",
+    "/wawhamzaabovearabic": "\u0624",
+    "/wawhamzaabovefinalarabic": "\uFE86",
+    "/wawhighhamza": "\u0676",
+    "/wawring": "\u06C4",
+    "/wawsmall": "\u06E5",
+    "/wawtwodotsabove": "\u06CA",
+    "/waxingCrescentMoon": "\u1F312",
+    "/waxingGibbousMoon": "\u1F314",
+    "/wbfullwidth": "\u33DD",
+    "/wbsquare": "\u33DD",
+    "/wcircle": "\u24E6",
+    "/wcircumflex": "\u0175",
+    "/wcsquare": "\u1F14F",
+    "/wcsquareblack": "\u1F18F",
+    "/wdieresis": "\u1E85",
+    "/wdot": "\u1E87",
+    "/wdotaccent": "\u1E87",
+    "/wdotbelow": "\u1E89",
+    "/wearyCatFace": "\u1F640",
+    "/wearyFace": "\u1F629",
+    "/wecirclekatakana": "\u32FD",
+    "/wecyr": "\u051D",
+    "/wedding": "\u1F492",
+    "/wehiragana": "\u3091",
+    "/weierstrass": "\u2118",
+    "/weightLifter": "\u1F3CB",
+    "/wekatakana": "\u30F1",
+    "/wekorean": "\u315E",
+    "/weokorean": "\u315D",
+    "/westsyriaccross": "\u2670",
+    "/wgrave": "\u1E81",
+    "/whale": "\u1F40B",
+    "/wheelchair": "\u267F",
+    "/wheelofdharma": "\u2638",
+    "/whiteDownPointingBackhandIndex": "\u1F447",
+    "/whiteDownPointingLeftHandIndex": "\u1F597",
+    "/whiteFlower": "\u1F4AE",
+    "/whiteHardShellFloppyDisk": "\u1F5AB",
+    "/whiteLatinCross": "\u1F546",
+    "/whiteLeftPointingBackhandIndex": "\u1F448",
+    "/whitePennant": "\u1F3F1",
+    "/whiteRightPointingBackhandIndex": "\u1F449",
+    "/whiteSquareButton": "\u1F533",
+    "/whiteSun": "\u1F323",
+    "/whiteSunBehindCloud": "\u1F325",
+    "/whiteSunBehindCloudRain": "\u1F326",
+    "/whiteSunSmallCloud": "\u1F324",
+    "/whiteTouchtoneTelephone": "\u1F57E",
+    "/whiteUpPointingBackhandIndex": "\u1F446",
+    "/whitearrowdown": "\u21E9",
+    "/whitearrowfromwallright": "\u21F0",
+    "/whitearrowleft": "\u21E6",
+    "/whitearrowonpedestalup": "\u21EB",
+    "/whitearrowright": "\u21E8",
+    "/whitearrowup": "\u21E7",
+    "/whitearrowupdown": "\u21F3",
+    "/whitearrowupfrombar": "\u21EA",
+    "/whitebullet": "\u25E6",
+    "/whitecircle": "\u25CB",
+    "/whitecircleinverse": "\u25D9",
+    "/whitecornerbracketleft": "\u300E",
+    "/whitecornerbracketleftvertical": "\uFE43",
+    "/whitecornerbracketright": "\u300F",
+    "/whitecornerbracketrightvertical": "\uFE44",
+    "/whitedblarrowonpedestalup": "\u21EF",
+    "/whitedblarrowup": "\u21EE",
+    "/whitediamond": "\u25C7",
+    "/whitediamondcontainingblacksmalldiamond": "\u25C8",
+    "/whitedownpointingsmalltriangle": "\u25BF",
+    "/whitedownpointingtriangle": "\u25BD",
+    "/whiteleftpointingsmalltriangle": "\u25C3",
+    "/whiteleftpointingtriangle": "\u25C1",
+    "/whitelenticularbracketleft": "\u3016",
+    "/whitelenticularbracketright": "\u3017",
+    "/whiterightpointingsmalltriangle": "\u25B9",
+    "/whiterightpointingtriangle": "\u25B7",
+    "/whitesesamedot": "\uFE46",
+    "/whitesmallsquare": "\u25AB",
+    "/whitesmilingface": "\u263A",
+    "/whitesquare": "\u25A1",
+    "/whitesquarebracketleft": "\u301A",
+    "/whitesquarebracketright": "\u301B",
+    "/whitestar": "\u2606",
+    "/whitetelephone": "\u260F",
+    "/whitetortoiseshellbracketleft": "\u3018",
+    "/whitetortoiseshellbracketright": "\u3019",
+    "/whiteuppointingsmalltriangle": "\u25B5",
+    "/whiteuppointingtriangle": "\u25B3",
+    "/whook": "\u2C73",
+    "/wicirclekatakana": "\u32FC",
+    "/wigglylinevertical": "\u2E3E",
+    "/wignyan": "\uA983",
+    "/wihiragana": "\u3090",
+    "/wikatakana": "\u30F0",
+    "/wikorean": "\u315F",
+    "/windBlowingFace": "\u1F32C",
+    "/windChime": "\u1F390",
+    "/windupada": "\uA9C6",
+    "/wineGlass": "\u1F377",
+    "/winkingFace": "\u1F609",
+    "/wiredKeyboard": "\u1F5AE",
+    "/wmonospace": "\uFF57",
+    "/wocirclekatakana": "\u32FE",
+    "/wohiragana": "\u3092",
+    "/wokatakana": "\u30F2",
+    "/wokatakanahalfwidth": "\uFF66",
+    "/wolfFace": "\u1F43A",
+    "/woman": "\u1F469",
+    "/womanBunnyEars": "\u1F46F",
+    "/womansBoots": "\u1F462",
+    "/womansClothes": "\u1F45A",
+    "/womansHat": "\u1F452",
+    "/womansSandal": "\u1F461",
+    "/womens": "\u1F6BA",
+    "/won": "\u20A9",
+    "/wonmonospace": "\uFFE6",
+    "/woodideographiccircled": "\u328D",
+    "/woodideographicparen": "\u322D",
+    "/wordjoiner": "\u2060",
+    "/wordseparatormiddledot": "\u2E31",
+    "/worldMap": "\u1F5FA",
+    "/worriedFace": "\u1F61F",
+    "/wowaenthai": "\u0E27",
+    "/wparen": "\u24B2",
+    "/wparenthesized": "\u24B2",
+    "/wrappedPresent": "\u1F381",
+    "/wreathproduct": "\u2240",
+    "/wrench": "\u1F527",
+    "/wring": "\u1E98",
+    "/wsuperior": "\u02B7",
+    "/wsupmod": "\u02B7",
+    "/wturned": "\u028D",
+    "/wulumelikvowel": "\uA9B7",
+    "/wuluvowel": "\uA9B6",
+    "/wynn": "\u01BF",
+    "/x": "\u0078",
+    "/x.inferior": "\u2093",
+    "/xabovecmb": "\u033D",
+    "/xatailcyr": "\u04B3",
+    "/xbopomofo": "\u3112",
+    "/xcircle": "\u24E7",
+    "/xdieresis": "\u1E8D",
+    "/xdot": "\u1E8B",
+    "/xdotaccent": "\u1E8B",
+    "/xeharmenian": "\u056D",
+    "/xi": "\u03BE",
+    "/xmonospace": "\uFF58",
+    "/xor": "\u22BB",
+    "/xparen": "\u24B3",
+    "/xparenthesized": "\u24B3",
+    "/xsuperior": "\u02E3",
+    "/xsupmod": "\u02E3",
+    "/y": "\u0079",
+    "/yaadosquare": "\u334E",
+    "/yaarusquare": "\u334F",
+    "/yabengali": "\u09AF",
+    "/yacirclekatakana": "\u32F3",
+    "/yacute": "\u00FD",
+    "/yacyr": "\u044F",
+    "/yadeva": "\u092F",
+    "/yaecyr": "\u0519",
+    "/yaekorean": "\u3152",
+    "/yagujarati": "\u0AAF",
+    "/yagurmukhi": "\u0A2F",
+    "/yahiragana": "\u3084",
+    "/yakatakana": "\u30E4",
+    "/yakatakanahalfwidth": "\uFF94",
+    "/yakorean": "\u3151",
+    "/yamakkanthai": "\u0E4E",
+    "/yangtonemod": "\u02EB",
+    "/yasmallhiragana": "\u3083",
+    "/yasmallkatakana": "\u30E3",
+    "/yasmallkatakanahalfwidth": "\uFF6C",
+    "/yatcyr": "\u0463",
+    "/yatcyrillic": "\u0463",
+    "/ycircle": "\u24E8",
+    "/ycircumflex": "\u0177",
+    "/ydieresis": "\u00FF",
+    "/ydot": "\u1E8F",
+    "/ydotaccent": "\u1E8F",
+    "/ydotbelow": "\u1EF5",
+    "/yeh": "\u064A",
+    "/yeh.fina": "\uFEF2",
+    "/yeh.init": "\uFEF3",
+    "/yeh.init_alefmaksura.fina": "\uFC59",
+    "/yeh.init_hah.fina": "\uFC56",
+    "/yeh.init_hah.medi": "\uFCDB",
+    "/yeh.init_hamzaabove.medi_ae.fina": "\uFBEC",
+    "/yeh.init_hamzaabove.medi_alef.fina": "\uFBEA",
+    "/yeh.init_hamzaabove.medi_alefmaksura.fina": "\uFC03",
+    "/yeh.init_hamzaabove.medi_e.fina": "\uFBF6",
+    "/yeh.init_hamzaabove.medi_e.medi": "\uFBF8",
+    "/yeh.init_hamzaabove.medi_hah.fina": "\uFC01",
+    "/yeh.init_hamzaabove.medi_hah.medi": "\uFC98",
+    "/yeh.init_hamzaabove.medi_heh.medi": "\uFC9B",
+    "/yeh.init_hamzaabove.medi_jeem.fina": "\uFC00",
+    "/yeh.init_hamzaabove.medi_jeem.medi": "\uFC97",
+    "/yeh.init_hamzaabove.medi_khah.medi": "\uFC99",
+    "/yeh.init_hamzaabove.medi_meem.fina": "\uFC02",
+    "/yeh.init_hamzaabove.medi_meem.medi": "\uFC9A",
+    "/yeh.init_hamzaabove.medi_oe.fina": "\uFBF2",
+    "/yeh.init_hamzaabove.medi_u.fina": "\uFBF0",
+    "/yeh.init_hamzaabove.medi_waw.fina": "\uFBEE",
+    "/yeh.init_hamzaabove.medi_yeh.fina": "\uFC04",
+    "/yeh.init_hamzaabove.medi_yu.fina": "\uFBF4",
+    "/yeh.init_heh.medi": "\uFCDE",
+    "/yeh.init_jeem.fina": "\uFC55",
+    "/yeh.init_jeem.medi": "\uFCDA",
+    "/yeh.init_khah.fina": "\uFC57",
+    "/yeh.init_khah.medi": "\uFCDC",
+    "/yeh.init_meem.fina": "\uFC58",
+    "/yeh.init_meem.medi": "\uFCDD",
+    "/yeh.init_meem.medi_meem.medi": "\uFD9D",
+    "/yeh.init_yeh.fina": "\uFC5A",
+    "/yeh.isol": "\uFEF1",
+    "/yeh.medi": "\uFEF4",
+    "/yeh.medi_alefmaksura.fina": "\uFC95",
+    "/yeh.medi_hah.medi_yeh.fina": "\uFDAE",
+    "/yeh.medi_hamzaabove.medi_ae.fina": "\uFBED",
+    "/yeh.medi_hamzaabove.medi_alef.fina": "\uFBEB",
+    "/yeh.medi_hamzaabove.medi_alefmaksura.fina": "\uFC68",
+    "/yeh.medi_hamzaabove.medi_e.fina": "\uFBF7",
+    "/yeh.medi_hamzaabove.medi_heh.medi": "\uFCE0",
+    "/yeh.medi_hamzaabove.medi_meem.fina": "\uFC66",
+    "/yeh.medi_hamzaabove.medi_meem.medi": "\uFCDF",
+    "/yeh.medi_hamzaabove.medi_noon.fina": "\uFC67",
+    "/yeh.medi_hamzaabove.medi_oe.fina": "\uFBF3",
+    "/yeh.medi_hamzaabove.medi_reh.fina": "\uFC64",
+    "/yeh.medi_hamzaabove.medi_u.fina": "\uFBF1",
+    "/yeh.medi_hamzaabove.medi_waw.fina": "\uFBEF",
+    "/yeh.medi_hamzaabove.medi_yeh.fina": "\uFC69",
+    "/yeh.medi_hamzaabove.medi_yu.fina": "\uFBF5",
+    "/yeh.medi_hamzaabove.medi_zain.fina": "\uFC65",
+    "/yeh.medi_heh.medi": "\uFCF1",
+    "/yeh.medi_jeem.medi_yeh.fina": "\uFDAF",
+    "/yeh.medi_meem.fina": "\uFC93",
+    "/yeh.medi_meem.medi": "\uFCF0",
+    "/yeh.medi_meem.medi_meem.fina": "\uFD9C",
+    "/yeh.medi_meem.medi_yeh.fina": "\uFDB0",
+    "/yeh.medi_noon.fina": "\uFC94",
+    "/yeh.medi_reh.fina": "\uFC91",
+    "/yeh.medi_yeh.fina": "\uFC96",
+    "/yeh.medi_zain.fina": "\uFC92",
+    "/yehBarreeDigitThreeAbove": "\u077B",
+    "/yehBarreeDigitTwoAbove": "\u077A",
+    "/yehVabove": "\u06CE",
+    "/yehabove": "\u06E7",
+    "/yeharabic": "\u064A",
+    "/yehbarree": "\u06D2",
+    "/yehbarree.fina": "\uFBAF",
+    "/yehbarree.isol": "\uFBAE",
+    "/yehbarreearabic": "\u06D2",
+    "/yehbarreefinalarabic": "\uFBAF",
+    "/yehbarreehamza": "\u06D3",
+    "/yehbarreehamza.fina": "\uFBB1",
+    "/yehbarreehamza.isol": "\uFBB0",
+    "/yehfarsi": "\u06CC",
+    "/yehfarsi.fina": "\uFBFD",
+    "/yehfarsi.init": "\uFBFE",
+    "/yehfarsi.isol": "\uFBFC",
+    "/yehfarsi.medi": "\uFBFF",
+    "/yehfarsiinvertedV": "\u063D",
+    "/yehfarsithreedotsabove": "\u063F",
+    "/yehfarsitwodotsabove": "\u063E",
+    "/yehfinalarabic": "\uFEF2",
+    "/yehhamza": "\u0626",
+    "/yehhamza.fina": "\uFE8A",
+    "/yehhamza.init": "\uFE8B",
+    "/yehhamza.isol": "\uFE89",
+    "/yehhamza.medi": "\uFE8C",
+    "/yehhamzaabovearabic": "\u0626",
+    "/yehhamzaabovefinalarabic": "\uFE8A",
+    "/yehhamzaaboveinitialarabic": "\uFE8B",
+    "/yehhamzaabovemedialarabic": "\uFE8C",
+    "/yehhighhamza": "\u0678",
+    "/yehinitialarabic": "\uFEF3",
+    "/yehmedialarabic": "\uFEF4",
+    "/yehmeeminitialarabic": "\uFCDD",
+    "/yehmeemisolatedarabic": "\uFC58",
+    "/yehnoonfinalarabic": "\uFC94",
+    "/yehsmall": "\u06E6",
+    "/yehtail": "\u06CD",
+    "/yehthreedotsbelow": "\u06D1",
+    "/yehthreedotsbelowarabic": "\u06D1",
+    "/yekorean": "\u3156",
+    "/yellowHeart": "\u1F49B",
+    "/yen": "\u00A5",
+    "/yenmonospace": "\uFFE5",
+    "/yeokorean": "\u3155",
+    "/yeorinhieuhkorean": "\u3186",
+    "/yerachBenYomo:hb": "\u05AA",
+    "/yerahbenyomohebrew": "\u05AA",
+    "/yerahbenyomolefthebrew": "\u05AA",
+    "/yericyrillic": "\u044B",
+    "/yerudieresiscyrillic": "\u04F9",
+    "/yesieungkorean": "\u3181",
+    "/yesieungpansioskorean": "\u3183",
+    "/yesieungsioskorean": "\u3182",
+    "/yetiv:hb": "\u059A",
+    "/yetivhebrew": "\u059A",
+    "/ygrave": "\u1EF3",
+    "/yhoi": "\u1EF7",
+    "/yhook": "\u01B4",
+    "/yhookabove": "\u1EF7",
+    "/yiarmenian": "\u0575",
+    "/yicyrillic": "\u0457",
+    "/yikorean": "\u3162",
+    "/yintonemod": "\u02EA",
+    "/yinyang": "\u262F",
+    "/yiwnarmenian": "\u0582",
+    "/ylongcyr": "\u044B",
+    "/ylongdieresiscyr": "\u04F9",
+    "/yloop": "\u1EFF",
+    "/ymacron": "\u0233",
+    "/ymonospace": "\uFF59",
+    "/yocirclekatakana": "\u32F5",
+    "/yod": "\u05D9",
+    "/yod:hb": "\u05D9",
+    "/yod_yod:hb": "\u05F2",
+    "/yod_yod_patah:hb": "\uFB1F",
+    "/yoddagesh": "\uFB39",
+    "/yoddageshhebrew": "\uFB39",
+    "/yodhebrew": "\u05D9",
+    "/yodwithdagesh:hb": "\uFB39",
+    "/yodwithhiriq:hb": "\uFB1D",
+    "/yodyodhebrew": "\u05F2",
+    "/yodyodpatahhebrew": "\uFB1F",
+    "/yogh": "\u021D",
+    "/yohiragana": "\u3088",
+    "/yoikorean": "\u3189",
+    "/yokatakana": "\u30E8",
+    "/yokatakanahalfwidth": "\uFF96",
+    "/yokorean": "\u315B",
+    "/yosmallhiragana": "\u3087",
+    "/yosmallkatakana": "\u30E7",
+    "/yosmallkatakanahalfwidth": "\uFF6E",
+    "/yot": "\u03F3",
+    "/yotgreek": "\u03F3",
+    "/yoyaekorean": "\u3188",
+    "/yoyakorean": "\u3187",
+    "/yoyakthai": "\u0E22",
+    "/yoyingthai": "\u0E0D",
+    "/yparen": "\u24B4",
+    "/yparenthesized": "\u24B4",
+    "/ypogegrammeni": "\u037A",
+    "/ypogegrammenigreekcmb": "\u0345",
+    "/yr": "\u01A6",
+    "/yring": "\u1E99",
+    "/ystroke": "\u024F",
+    "/ysuperior": "\u02B8",
+    "/ysupmod": "\u02B8",
+    "/ytilde": "\u1EF9",
+    "/yturned": "\u028E",
+    "/yu.fina": "\uFBDC",
+    "/yu.isol": "\uFBDB",
+    "/yuansquare": "\u3350",
+    "/yucirclekatakana": "\u32F4",
+    "/yucyr": "\u044E",
+    "/yuhiragana": "\u3086",
+    "/yuikorean": "\u318C",
+    "/yukatakana": "\u30E6",
+    "/yukatakanahalfwidth": "\uFF95",
+    "/yukirghiz": "\u06C9",
+    "/yukirghiz.fina": "\uFBE3",
+    "/yukirghiz.isol": "\uFBE2",
+    "/yukorean": "\u3160",
+    "/yukrcyr": "\u0457",
+    "/yusbigcyr": "\u046B",
+    "/yusbigcyrillic": "\u046B",
+    "/yusbigiotifiedcyr": "\u046D",
+    "/yusbigiotifiedcyrillic": "\u046D",
+    "/yuslittlecyr": "\u0467",
+    "/yuslittlecyrillic": "\u0467",
+    "/yuslittleiotifiedcyr": "\u0469",
+    "/yuslittleiotifiedcyrillic": "\u0469",
+    "/yusmallhiragana": "\u3085",
+    "/yusmallkatakana": "\u30E5",
+    "/yusmallkatakanahalfwidth": "\uFF6D",
+    "/yuyekorean": "\u318B",
+    "/yuyeokorean": "\u318A",
+    "/yyabengali": "\u09DF",
+    "/yyadeva": "\u095F",
+    "/z": "\u007A",
+    "/zaarmenian": "\u0566",
+    "/zacute": "\u017A",
+    "/zadeva": "\u095B",
+    "/zagurmukhi": "\u0A5B",
+    "/zah": "\u0638",
+    "/zah.fina": "\uFEC6",
+    "/zah.init": "\uFEC7",
+    "/zah.init_meem.fina": "\uFC28",
+    "/zah.init_meem.medi": "\uFCB9",
+    "/zah.isol": "\uFEC5",
+    "/zah.medi": "\uFEC8",
+    "/zah.medi_meem.medi": "\uFD3B",
+    "/zaharabic": "\u0638",
+    "/zahfinalarabic": "\uFEC6",
+    "/zahinitialarabic": "\uFEC7",
+    "/zahiragana": "\u3056",
+    "/zahmedialarabic": "\uFEC8",
+    "/zain": "\u0632",
+    "/zain.fina": "\uFEB0",
+    "/zain.isol": "\uFEAF",
+    "/zainabove": "\u0617",
+    "/zainarabic": "\u0632",
+    "/zainfinalarabic": "\uFEB0",
+    "/zakatakana": "\u30B6",
+    "/zaqefGadol:hb": "\u0595",
+    "/zaqefQatan:hb": "\u0594",
+    "/zaqefgadolhebrew": "\u0595",
+    "/zaqefqatanhebrew": "\u0594",
+    "/zarqa:hb": "\u0598",
+    "/zarqahebrew": "\u0598",
+    "/zayin": "\u05D6",
+    "/zayin:hb": "\u05D6",
+    "/zayindagesh": "\uFB36",
+    "/zayindageshhebrew": "\uFB36",
+    "/zayinhebrew": "\u05D6",
+    "/zayinwithdagesh:hb": "\uFB36",
+    "/zbopomofo": "\u3117",
+    "/zcaron": "\u017E",
+    "/zcircle": "\u24E9",
+    "/zcircumflex": "\u1E91",
+    "/zcurl": "\u0291",
+    "/zdescender": "\u2C6C",
+    "/zdot": "\u017C",
+    "/zdotaccent": "\u017C",
+    "/zdotbelow": "\u1E93",
+    "/zecyr": "\u0437",
+    "/zecyrillic": "\u0437",
+    "/zedescendercyrillic": "\u0499",
+    "/zedieresiscyr": "\u04DF",
+    "/zedieresiscyrillic": "\u04DF",
+    "/zehiragana": "\u305C",
+    "/zekatakana": "\u30BC",
+    "/zero": "\u0030",
+    "/zero.inferior": "\u2080",
+    "/zero.superior": "\u2070",
+    "/zeroarabic": "\u0660",
+    "/zerobengali": "\u09E6",
+    "/zerocircle": "\u24EA",
+    "/zerocircleblack": "\u24FF",
+    "/zerocomma": "\u1F101",
+    "/zerodeva": "\u0966",
+    "/zerofar": "\u06F0",
+    "/zerofullstop": "\u1F100",
+    "/zerogujarati": "\u0AE6",
+    "/zerogurmukhi": "\u0A66",
+    "/zerohackarabic": "\u0660",
+    "/zeroinferior": "\u2080",
+    "/zeromonospace": "\uFF10",
+    "/zerooldstyle": "\uF730",
+    "/zeropersian": "\u06F0",
+    "/zerosquareabove": "\u06E0",
+    "/zerosuperior": "\u2070",
+    "/zerothai": "\u0E50",
+    "/zerothirds": "\u2189",
+    "/zerowidthjoiner": "\uFEFF",
+    "/zerowidthnobreakspace": "\uFEFF",
+    "/zerowidthnonjoiner": "\u200C",
+    "/zerowidthspace": "\u200B",
+    "/zeta": "\u03B6",
+    "/zetailcyr": "\u0499",
+    "/zhbopomofo": "\u3113",
+    "/zhearmenian": "\u056A",
+    "/zhebrevecyr": "\u04C2",
+    "/zhebrevecyrillic": "\u04C2",
+    "/zhecyr": "\u0436",
+    "/zhecyrillic": "\u0436",
+    "/zhedescendercyrillic": "\u0497",
+    "/zhedieresiscyr": "\u04DD",
+    "/zhedieresiscyrillic": "\u04DD",
+    "/zhetailcyr": "\u0497",
+    "/zhook": "\u0225",
+    "/zihiragana": "\u3058",
+    "/zikatakana": "\u30B8",
+    "/zildefunc": "\u236C",
+    "/zinorhebrew": "\u05AE",
+    "/zjekomicyr": "\u0505",
+    "/zlinebelow": "\u1E95",
+    "/zmonospace": "\uFF5A",
+    "/znotationbagmembership": "\u22FF",
+    "/zohiragana": "\u305E",
+    "/zokatakana": "\u30BE",
+    "/zparen": "\u24B5",
+    "/zparenthesized": "\u24B5",
+    "/zretroflex": "\u0290",
+    "/zretroflexhook": "\u0290",
+    "/zstroke": "\u01B6",
+    "/zswashtail": "\u0240",
+    "/zuhiragana": "\u305A",
+    "/zukatakana": "\u30BA",
+    "/zwarakay": "\u0659",
+    # manually added from
+    # https://github.com/serviceprototypinglab/latex-pdfa/blob/master/glyphtounicode-cmr.tex
+    "/angbracketleftBig": "\u28E8",
+    "/angbracketleftBigg": "\u27E8",
+    "/angbracketleftbig": "\u27E8",
+    "/angbracketleftbigg": "\u27E8",
+    "/angbracketrightBig": "\u27E9",
+    "/angbracketrightBigg": "\u27E9",
+    "/angbracketrightbig": "\u27E9",
+    "/angbracketrightbigg": "\u27E9",
+    "/arrowbt": "\u2193",
+    "/arrowdblbt": "\u21D3",
+    "/arrowdbltp": "\u21D1",
+    "/arrowhookleft": "\u21AA",
+    "/arrowhookright": "\u21A9",
+    "/arrowtp": "\u2191",
+    # diff : "/arrowvertex": "\u23D0",
+    "/arrowvertexdbl": "\uED12",
+    "/backslashBig": "\u005C",
+    "/backslashBigg": "\u005C",
+    "/backslashbig": "\u005C",
+    "/backslashbigg": "\u005C",
+    # diff : "/braceex": "\u23AA",
+    "/bracehtipdownleft": "\uED17",
+    "/bracehtipdownright": "\uED18",
+    "/bracehtipupleft": "\uED19",
+    "/bracehtipupright": "\uED1A",
+    "/braceleftBig": "\u007B",
+    "/braceleftBigg": "\u007B",
+    "/braceleftbig": "\u007B",
+    "/braceleftbigg": "\u007B",
+    # diff : "/braceleftbt": "\u23A9",
+    # diff : "/braceleftmid": "\u23A8",
+    # diff : "/bracelefttp": "\u23A7",
+    "/bracerightBig": "\u007D",
+    "/bracerightBigg": "\u007D",
+    "/bracerightbig": "\u007D",
+    "/bracerightbigg": "\u007D",
+    # diff : "/bracerightbt": "\u23AD",
+    # diff : "/bracerightmid": "\u23AC",
+    # diff : "/bracerighttp": "\u23AB",
+    "/bracketleftBig": "\u005B",
+    "/bracketleftBigg": "\u005B",
+    "/bracketleftbig": "\u005B",
+    "/bracketleftbigg": "\u005B",
+    # diff : "/bracketleftbt": "\u23A3",
+    # diff : "/bracketleftex": "\u23A2",
+    # diff : "/bracketlefttp": "\u23A1",
+    "/bracketrightBig": "\u005D",
+    "/bracketrightBigg": "\u005D",
+    "/bracketrightbig": "\u005D",
+    "/bracketrightbigg": "\u005D",
+    # diff : "/bracketrightbt": "\u23A6",
+    # diff : "/bracketrightex": "\u23A5",
+    # diff : "/bracketrighttp": "\u23A4",
+    "/ceilingleftBig": "\u2308",
+    "/ceilingleftBigg": "\u2308",
+    "/ceilingleftbig": "\u2308",
+    "/ceilingleftbigg": "\u2308",
+    "/ceilingrightBig": "\u2309",
+    "/ceilingrightBigg": "\u2309",
+    "/ceilingrightbig": "\u2309",
+    "/ceilingrightbigg": "\u2309",
+    "/circledotdisplay": "\u2A00",
+    "/circledottext": "\u2A00",
+    "/circlemultiplydisplay": "\u2A02",
+    "/circlemultiplytext": "\u2A02",
+    "/circleplusdisplay": "\u2A01",
+    "/circleplustext": "\u2A01",
+    "/contintegraldisplay": "\u222E",
+    "/contintegraltext": "\u222E",
+    "/coproductdisplay": "\u2210",
+    "/coproducttext": "\u2210",
+    "/floorleftBig": "\u230A",
+    "/floorleftBigg": "\u230A",
+    "/floorleftbig": "\u230A",
+    "/floorleftbigg": "\u230A",
+    "/floorrightBig": "\u230B",
+    "/floorrightBigg": "\u230B",
+    "/floorrightbig": "\u230B",
+    "/floorrightbigg": "\u230B",
+    "/hatwide": "\u02C6",
+    "/hatwider": "\u02C6",
+    "/hatwidest": "\u02C6",
+    "/integraldisplay": "\u222B",
+    "/integraltext": "\u222B",
+    "/intersectiondisplay": "\u22C2",
+    "/intersectiontext": "\u22C2",
+    "/logicalanddisplay": "\u22C0",
+    "/logicalandtext": "\u22C0",
+    "/logicalordisplay": "\u22C1",
+    "/logicalortext": "\u22C1",
+    "/mapsto": "\u21A6",
+    "/parenleftBig": "\u0028",
+    "/parenleftBigg": "\u0028",
+    "/parenleftbig": "\u0028",
+    "/parenleftbigg": "\u0028",
+    # diff : "/parenleftbt": "\u239D",
+    # diff : "/parenleftex": "\u239C",
+    # diff : "/parenlefttp": "\u239B",
+    "/parenrightBig": "\u0029",
+    "/parenrightBigg": "\u0029",
+    "/parenrightbig": "\u0029",
+    "/parenrightbigg": "\u0029",
+    # diff : "/parenrightbt": "\u23A0",
+    # diff : "/parenrightex": "\u239F",
+    # diff : "/parenrighttp": "\u239E",
+    "/productdisplay": "\u220F",
+    "/producttext": "\u220F",
+    "/radicalBig": "\u221A",
+    "/radicalBigg": "\u221A",
+    "/radicalbig": "\u221A",
+    "/radicalbigg": "\u221A",
+    "/radicalbt": "\u221A",
+    "/radicaltp": "\uED6A",
+    "/radicalvertex": "\uED6B",
+    "/slashBig": "\u002F",
+    "/slashBigg": "\u002F",
+    "/slashbig": "\u002F",
+    "/slashbigg": "\u002F",
+    "/summationdisplay": "\u2211",
+    "/summationtext": "\u2211",
+    "/tie": "\u2040",
+    "/tildewide": "\u02DC",
+    "/tildewider": "\u02DC",
+    "/tildewidest": "\u02DC",
+    "/uniondisplay": "\u22C3",
+    "/unionmultidisplay": "\u2A04",
+    "/unionmultitext": "\u2A04",
+    "/unionsqdisplay": "\u2A06",
+    "/unionsqtext": "\u2A06",
+    "/uniontext": "\u22C3",
+    "/vextenddouble": "\uED79",
+    "/vextendsingle": "\u23D0",
+    "/a1": "\u25C1",
+    "/a2": "\u22B4",
+    "/a3": "\u25B7",
+    "/a4": "\u22B5",
+    "/a40": "\u02C2",
+    "/a41": "\u02C3",
+    "/a42": "\u2303",
+    "/a43": "\u2304",
+    "/a48": "\u2127",
+    "/a49": "\u22C8",
+    "/a50": "\u25A1",
+    "/a51": "\u25C7",
+    "/a58": "\u2053",
+    "/a59": "\u219D",
+    "/a60": "\u228F",
+    "/a61": "\u2290",
+    "/d0": "\u2199",
+    "/d1": "\u2199",
+    "/d2": "\u2199",
+    "/d3": "\u2199",
+    "/d4": "\u2199",
+    "/d5": "\u2199",
+    "/d6": "\u2199",
+    "/d7": "\u2193",
+    "/d8": "\u2193",
+    "/d9": "\u2193",
+    "/d10": "\u2193",
+    "/d11": "\u2193",
+    "/d12": "\u2193",
+    "/d13": "\u2193",
+    "/d14": "\u2193",
+    "/d15": "\u2193",
+    "/d16": "\u2193",
+    "/d17": "\u2193",
+    "/d18": "\u2193",
+    "/d19": "\u2193",
+    "/d20": "\u2193",
+    "/d21": "\u2193",
+    "/d22": "\u2193",
+    "/d23": "\u2193",
+    "/d24": "\u2198",
+    "/d25": "\u2198",
+    "/d26": "\u2198",
+    "/d27": "\u2198",
+    "/d28": "\u2198",
+    "/d29": "\u2198",
+    "/d30": "\u2198",
+    "/d31": "\u2198",
+    "/d32": "\u2198",
+    "/d33": "\u2198",
+    "/d34": "\u2198",
+    "/d35": "\u2198",
+    "/d36": "\u2198",
+    "/d37": "\u2198",
+    "/d38": "\u2198",
+    "/d39": "\u2192",
+    "/d40": "\u2192",
+    "/d41": "\u2192",
+    "/d42": "\u2192",
+    "/d43": "\u2192",
+    "/d44": "\u2192",
+    "/d45": "\u2192",
+    "/d46": "\u2192",
+    "/d47": "\u2192",
+    "/d48": "\u2192",
+    "/d49": "\u2192",
+    "/d50": "\u2192",
+    "/d51": "\u2192",
+    "/d52": "\u2192",
+    "/d53": "\u2192",
+    "/d54": "\u2192",
+    "/d55": "\u2192",
+    "/d56": "\u2197",
+    "/d57": "\u2197",
+    "/d58": "\u2197",
+    "/d59": "\u2197",
+    "/d60": "\u2197",
+    "/d61": "\u2197",
+    "/d62": "\u2197",
+    "/d63": "\u2197",
+    "/d64": "\u2197",
+    "/d65": "\u2197",
+    "/d66": "\u2197",
+    "/d67": "\u2197",
+    "/d68": "\u2197",
+    "/d69": "\u2197",
+    "/d70": "\u2197",
+    "/d71": "\u2191",
+    "/d72": "\u2191",
+    "/d73": "\u2191",
+    "/d74": "\u2191",
+    "/d75": "\u2191",
+    "/d76": "\u2191",
+    "/d77": "\u2191",
+    "/d78": "\u2191",
+    "/d79": "\u2191",
+    "/d80": "\u2191",
+    "/d81": "\u2191",
+    "/d82": "\u2191",
+    "/d83": "\u2191",
+    "/d84": "\u2191",
+    "/d85": "\u2191",
+    "/d86": "\u2191",
+    "/d87": "\u2191",
+    "/d88": "\u2196",
+    "/d89": "\u2196",
+    "/d90": "\u2196",
+    "/d91": "\u2196",
+    "/d92": "\u2196",
+    "/d93": "\u2196",
+    "/d94": "\u2196",
+    "/d95": "\u2196",
+    "/d96": "\u2196",
+    "/d97": "\u2196",
+    "/d98": "\u2196",
+    "/d99": "\u2196",
+    "/d100": "\u2196",
+    "/d101": "\u2196",
+    "/d102": "\u2196",
+    "/d103": "\u2190",
+    "/d104": "\u2190",
+    "/d105": "\u2190",
+    "/d106": "\u2190",
+    "/d107": "\u2190",
+    "/d108": "\u2190",
+    "/d109": "\u2190",
+    "/d110": "\u2190",
+    "/d111": "\u2190",
+    "/d112": "\u2190",
+    "/d113": "\u2190",
+    "/d114": "\u2190",
+    "/d115": "\u2190",
+    "/d116": "\u2190",
+    "/d117": "\u2190",
+    "/d118": "\u2190",
+    "/d119": "\u2190",
+    "/d120": "\u2199",
+    "/d121": "\u2199",
+    "/d122": "\u2199",
+    "/d123": "\u2199",
+    "/d124": "\u2199",
+    "/d125": "\u2199",
+    "/d126": "\u2199",
+    "/d127": "\u2199",
+    # manually added from
+    # https://github.com/kohler/lcdf-typetools/blob/master/texglyphlist.txt
+    "/Ifractur": "\u2111",
+    "/FFsmall": "\uF766",
+    "/FFIsmall": "\uF766",
+    "/FFLsmall": "\uF766",
+    "/FIsmall": "\uF766",
+    "/FLsmall": "\uF766",
+    # diff : "/Germandbls": "\u0053",
+    "/Germandblssmall": "\uF773",
+    "/Ng": "\u014A",
+    "/Rfractur": "\u211C",
+    "/SS": "\u0053",
+    "/SSsmall": "\uF773",
+    "/altselector": "\uD802",
+    "/angbracketleft": "\u27E8",
+    "/angbracketright": "\u27E9",
+    "/arrowbothv": "\u2195",
+    "/arrowdblbothv": "\u21D5",
+    "/arrowleftbothalf": "\u21BD",
+    "/arrowlefttophalf": "\u21BC",
+    "/arrownortheast": "\u2197",
+    "/arrownorthwest": "\u2196",
+    "/arrowrightbothalf": "\u21C1",
+    "/arrowrighttophalf": "\u21C0",
+    "/arrowsoutheast": "\u2198",
+    "/arrowsouthwest": "\u2199",
+    "/ascendercompwordmark": "\uD80A",
+    "/asteriskcentered": "\u2217",
+    "/bardbl": "\u2225",
+    "/capitalcompwordmark": "\uD809",
+    "/circlecopyrt": "\u20DD",
+    "/circledivide": "\u2298",
+    "/circleminus": "\u2296",
+    "/coproduct": "\u2A3F",
+    "/ct": "\u0063",
+    "/cwm": "\u200C",
+    "/dblbracketleft": "\u27E6",
+    "/dblbracketright": "\u27E7",
+    # diff : "/diamond": "\u2662",
+    "/diamondmath": "\u22C4",
+    # diff : "/dotlessj": "\u0237",
+    "/emptyslot": "\uD801",
+    "/epsilon1": "\u03F5",
+    "/epsiloninv": "\u03F6",
+    "/equivasymptotic": "\u224D",
+    "/flat": "\u266D",
+    "/follows": "\u227B",
+    "/followsequal": "\u2AB0",
+    "/followsorcurly": "\u227D",
+    "/greatermuch": "\u226B",
+    # diff : "/heart": "\u2661",
+    "/interrobangdown": "\u2E18",
+    "/intersectionsq": "\u2293",
+    "/latticetop": "\u22A4",
+    "/lessmuch": "\u226A",
+    "/longdbls": "\u017F",
+    "/longsh": "\u017F",
+    "/longsi": "\u017F",
+    "/longsl": "\u017F",
+    "/longst": "\uFB05",
+    "/lscript": "\u2113",
+    "/natural": "\u266E",
+    "/negationslash": "\u0338",
+    "/ng": "\u014B",
+    "/owner": "\u220B",
+    "/pertenthousand": "\u2031",
+    # diff : "/phi": "\u03D5",
+    # diff : "/phi1": "\u03C6",
+    "/pi1": "\u03D6",
+    "/precedesequal": "\u2AAF",
+    "/precedesorcurly": "\u227C",
+    "/prime": "\u2032",
+    "/rho1": "\u03F1",
+    "/ringfitted": "\uD80D",
+    "/sharp": "\u266F",
+    "/similarequal": "\u2243",
+    "/slurabove": "\u2322",
+    "/slurbelow": "\u2323",
+    "/st": "\uFB06",
+    "/subsetsqequal": "\u2291",
+    "/supersetsqequal": "\u2292",
+    "/triangle": "\u25B3",
+    "/triangleinv": "\u25BD",
+    "/triangleleft": "\u25C1",
+    # diff : "/triangleright": "\u25B7",
+    "/turnstileleft": "\u22A2",
+    "/turnstileright": "\u22A3",
+    "/twelveudash": "\uD80C",
+    "/unionmulti": "\u228E",
+    "/unionsq": "\u2294",
+    "/vector": "\u20D7",
+    "/visualspace": "\u2423",
+    "/Dbar": "\u0110",
+    "/compwordmark": "\u200C",
+    "/dbar": "\u0111",
+    "/rangedash": "\u2013",
+    "/hyphenchar": "\u002D",
+    "/punctdash": "\u2014",
+    "/visiblespace": "\u2423",
+    "/Yen": "\u00A5",
+    "/anticlockwise": "\u27F2",
+    "/arrowparrleftright": "\u21C6",
+    "/arrowparrrightleft": "\u21C4",
+    "/arrowtailleft": "\u21A2",
+    "/arrowtailright": "\u21A3",
+    "/arrowtripleleft": "\u21DA",
+    "/arrowtripleright": "\u21DB",
+    "/check": "\u2713",
+    "/circleR": "\u00AE",
+    "/circleS": "\u24C8",
+    "/circleasterisk": "\u229B",
+    "/circleequal": "\u229C",
+    "/circlering": "\u229A",
+    "/clockwise": "\u27F3",
+    "/curlyleft": "\u21AB",
+    "/curlyright": "\u21AC",
+    "/dblarrowdwn": "\u21CA",
+    "/dblarrowheadleft": "\u219E",
+    "/dblarrowheadright": "\u21A0",
+    # diff : "/dblarrowup": "\u21C8",
+    "/defines": "\u225C",
+    "/diamondsolid": "\u2666",
+    "/difference": "\u224F",
+    "/downfall": "\u22CE",
+    "/equaldotleftright": "\u2252",
+    "/equaldotrightleft": "\u2253",
+    "/equalorfollows": "\u22DF",
+    # diff : "/equalorgreater": "\u2A96",
+    # diff : "/equalorless": "\u2A95",
+    "/equalsdots": "\u2251",
+    "/followsorequal": "\u227F",
+    "/forcesbar": "\u22AA",
+    # diff : "/fork": "\u22D4",
+    "/geomequivalent": "\u224E",
+    "/greaterdbleqlless": "\u2A8C",
+    "/greaterdblequal": "\u2267",
+    "/greaterlessequal": "\u22DB",
+    "/greaterorapproxeql": "\u2A86",
+    "/greaterorequalslant": "\u2A7E",
+    "/greaterorsimilar": "\u2273",
+    "/harpoondownleft": "\u21C3",
+    "/harpoondownright": "\u21C2",
+    "/harpoonleftright": "\u21CC",
+    "/harpoonrightleft": "\u21CB",
+    "/harpoonupleft": "\u21BF",
+    "/harpoonupright": "\u21BE",
+    "/intercal": "\u22BA",
+    "/lessdbleqlgreater": "\u2A8B",
+    "/lessdblequal": "\u2266",
+    "/lessequalgreater": "\u22DA",
+    "/lessorapproxeql": "\u2A85",
+    "/lessorequalslant": "\u2A7D",
+    "/lessorsimilar": "\u2272",
+    "/maltesecross": "\u2720",
+    "/multiopenleft": "\u22CB",
+    "/multiopenright": "\u22CC",
+    "/orunderscore": "\u22BB",
+    "/perpcorrespond": "\u2A5E",
+    # diff : "/precedesorequal": "\u227E",
+    "/primereverse": "\u2035",
+    "/revasymptequal": "\u22CD",
+    "/revsimilar": "\u223D",
+    "/rightanglene": "\u231D",
+    "/rightanglenw": "\u231C",
+    "/rightanglese": "\u231F",
+    "/rightanglesw": "\u231E",
+    "/satisfies": "\u22A8",
+    "/shiftleft": "\u21B0",
+    "/shiftright": "\u21B1",
+    "/square": "\u25A1",
+    "/squaredot": "\u22A1",
+    "/squareminus": "\u229F",
+    "/squaremultiply": "\u22A0",
+    "/squareplus": "\u229E",
+    "/squaresolid": "\u25A0",
+    "/squiggleleftright": "\u21AD",
+    "/squiggleright": "\u21DD",
+    "/subsetdblequal": "\u2AC5",
+    "/supersetdbl": "\u22D1",
+    "/supersetdblequal": "\u2AC6",
+    "/triangledownsld": "\u25BC",
+    "/triangleleftequal": "\u22B4",
+    "/triangleleftsld": "\u25C0",
+    "/trianglerightequal": "\u22B5",
+    "/trianglerightsld": "\u25B6",
+    "/trianglesolid": "\u25B2",
+    "/uprise": "\u22CF",
+    # diff : "/Digamma": "\u1D7C",
+    "/Finv": "\u2132",
+    "/Gmir": "\u2141",
+    "/Omegainv": "\u2127",
+    "/approxorequal": "\u224A",
+    "/archleftdown": "\u21B6",
+    "/archrightdown": "\u21B7",
+    "/beth": "\u2136",
+    "/daleth": "\u2138",
+    "/dividemultiply": "\u22C7",
+    "/downslope": "\u29F9",
+    "/equalorsimilar": "\u2242",
+    "/follownotdbleqv": "\u2ABA",
+    "/follownotslnteql": "\u2AB6",
+    "/followornoteqvlnt": "\u22E9",
+    "/greaternotdblequal": "\u2A8A",
+    "/greaternotequal": "\u2A88",
+    "/greaterornotdbleql": "\u2269",
+    "/greaterornotequal": "\u2269",
+    "/integerdivide": "\u2216",
+    "/lessnotdblequal": "\u2A89",
+    "/lessnotequal": "\u2A87",
+    "/lessornotdbleql": "\u2268",
+    "/lessornotequal": "\u2268",
+    "/multicloseleft": "\u22C9",
+    "/multicloseright": "\u22CA",
+    "/notapproxequal": "\u2247",
+    "/notarrowboth": "\u21AE",
+    "/notarrowleft": "\u219A",
+    "/notarrowright": "\u219B",
+    "/notbar": "\u2224",
+    "/notdblarrowboth": "\u21CE",
+    "/notdblarrowleft": "\u21CD",
+    "/notdblarrowright": "\u21CF",
+    "/notfollows": "\u2281",
+    "/notfollowsoreql": "\u2AB0",
+    "/notforces": "\u22AE",
+    "/notforcesextra": "\u22AF",
+    "/notgreaterdblequal": "\u2267",
+    "/notgreaterequal": "\u2271",
+    "/notgreaterorslnteql": "\u2A7E",
+    "/notlessdblequal": "\u2266",
+    "/notlessequal": "\u2270",
+    "/notlessorslnteql": "\u2A7D",
+    "/notprecedesoreql": "\u2AAF",
+    "/notsatisfies": "\u22AD",
+    "/notsimilar": "\u2241",
+    "/notsubseteql": "\u2288",
+    "/notsubsetordbleql": "\u2AC5",
+    "/notsubsetoreql": "\u228A",
+    "/notsuperseteql": "\u2289",
+    "/notsupersetordbleql": "\u2AC6",
+    "/notsupersetoreql": "\u228B",
+    "/nottriangeqlleft": "\u22EC",
+    "/nottriangeqlright": "\u22ED",
+    "/nottriangleleft": "\u22EA",
+    "/nottriangleright": "\u22EB",
+    "/notturnstile": "\u22AC",
+    "/planckover2pi": "\u210F",
+    "/planckover2pi1": "\u210F",
+    "/precedenotdbleqv": "\u2AB9",
+    "/precedenotslnteql": "\u2AB5",
+    "/precedeornoteqvlnt": "\u22E8",
+    "/subsetnoteql": "\u228A",
+    "/subsetornotdbleql": "\u2ACB",
+    "/supersetnoteql": "\u228B",
+    "/supersetornotdbleql": "\u2ACC",
+    "/upslope": "\u29F8",
+}
+
+
+def _complete() -> None:
+    global adobe_glyphs
+    for i in range(256):
+        adobe_glyphs[f"/a{i}"] = chr(i)
+    adobe_glyphs["/.notdef"] = "□"
+
+
+_complete()
diff --git a/.venv/lib/python3.12/site-packages/pypdf/_codecs/pdfdoc.py b/.venv/lib/python3.12/site-packages/pypdf/_codecs/pdfdoc.py
new file mode 100644
index 00000000..306357a5
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/_codecs/pdfdoc.py
@@ -0,0 +1,264 @@
+# PDFDocEncoding Character Set: Table D.2 of PDF Reference 1.7
+# C.1 Predefined encodings sorted by character name of another PDF reference
+# Some indices have '\u0000' although they should have something else:
+# 22: should be '\u0017'
+_pdfdoc_encoding = [
+    "\u0000",
+    "\u0001",
+    "\u0002",
+    "\u0003",
+    "\u0004",
+    "\u0005",
+    "\u0006",
+    "\u0007",  # 0 -  7
+    "\u0008",
+    "\u0009",
+    "\u000a",
+    "\u000b",
+    "\u000c",
+    "\u000d",
+    "\u000e",
+    "\u000f",  # 8 - 15
+    "\u0010",
+    "\u0011",
+    "\u0012",
+    "\u0013",
+    "\u0014",
+    "\u0015",
+    "\u0000",
+    "\u0017",  # 16 - 23
+    "\u02d8",
+    "\u02c7",
+    "\u02c6",
+    "\u02d9",
+    "\u02dd",
+    "\u02db",
+    "\u02da",
+    "\u02dc",  # 24 - 31
+    "\u0020",
+    "\u0021",
+    "\u0022",
+    "\u0023",
+    "\u0024",
+    "\u0025",
+    "\u0026",
+    "\u0027",  # 32 - 39
+    "\u0028",
+    "\u0029",
+    "\u002a",
+    "\u002b",
+    "\u002c",
+    "\u002d",
+    "\u002e",
+    "\u002f",  # 40 - 47
+    "\u0030",
+    "\u0031",
+    "\u0032",
+    "\u0033",
+    "\u0034",
+    "\u0035",
+    "\u0036",
+    "\u0037",  # 48 - 55
+    "\u0038",
+    "\u0039",
+    "\u003a",
+    "\u003b",
+    "\u003c",
+    "\u003d",
+    "\u003e",
+    "\u003f",  # 56 - 63
+    "\u0040",
+    "\u0041",
+    "\u0042",
+    "\u0043",
+    "\u0044",
+    "\u0045",
+    "\u0046",
+    "\u0047",  # 64 - 71
+    "\u0048",
+    "\u0049",
+    "\u004a",
+    "\u004b",
+    "\u004c",
+    "\u004d",
+    "\u004e",
+    "\u004f",  # 72 - 79
+    "\u0050",
+    "\u0051",
+    "\u0052",
+    "\u0053",
+    "\u0054",
+    "\u0055",
+    "\u0056",
+    "\u0057",  # 80 - 87
+    "\u0058",
+    "\u0059",
+    "\u005a",
+    "\u005b",
+    "\u005c",
+    "\u005d",
+    "\u005e",
+    "\u005f",  # 88 - 95
+    "\u0060",
+    "\u0061",
+    "\u0062",
+    "\u0063",
+    "\u0064",
+    "\u0065",
+    "\u0066",
+    "\u0067",  # 96 - 103
+    "\u0068",
+    "\u0069",
+    "\u006a",
+    "\u006b",
+    "\u006c",
+    "\u006d",
+    "\u006e",
+    "\u006f",  # 104 - 111
+    "\u0070",
+    "\u0071",
+    "\u0072",
+    "\u0073",
+    "\u0074",
+    "\u0075",
+    "\u0076",
+    "\u0077",  # 112 - 119
+    "\u0078",
+    "\u0079",
+    "\u007a",
+    "\u007b",
+    "\u007c",
+    "\u007d",
+    "\u007e",
+    "\u0000",  # 120 - 127
+    "\u2022",
+    "\u2020",
+    "\u2021",
+    "\u2026",
+    "\u2014",
+    "\u2013",
+    "\u0192",
+    "\u2044",  # 128 - 135
+    "\u2039",
+    "\u203a",
+    "\u2212",
+    "\u2030",
+    "\u201e",
+    "\u201c",
+    "\u201d",
+    "\u2018",  # 136 - 143
+    "\u2019",
+    "\u201a",
+    "\u2122",
+    "\ufb01",
+    "\ufb02",
+    "\u0141",
+    "\u0152",
+    "\u0160",  # 144 - 151
+    "\u0178",
+    "\u017d",
+    "\u0131",
+    "\u0142",
+    "\u0153",
+    "\u0161",
+    "\u017e",
+    "\u0000",  # 152 - 159
+    "\u20ac",
+    "\u00a1",
+    "\u00a2",
+    "\u00a3",
+    "\u00a4",
+    "\u00a5",
+    "\u00a6",
+    "\u00a7",  # 160 - 167
+    "\u00a8",
+    "\u00a9",
+    "\u00aa",
+    "\u00ab",
+    "\u00ac",
+    "\u0000",
+    "\u00ae",
+    "\u00af",  # 168 - 175
+    "\u00b0",
+    "\u00b1",
+    "\u00b2",
+    "\u00b3",
+    "\u00b4",
+    "\u00b5",
+    "\u00b6",
+    "\u00b7",  # 176 - 183
+    "\u00b8",
+    "\u00b9",
+    "\u00ba",
+    "\u00bb",
+    "\u00bc",
+    "\u00bd",
+    "\u00be",
+    "\u00bf",  # 184 - 191
+    "\u00c0",
+    "\u00c1",
+    "\u00c2",
+    "\u00c3",
+    "\u00c4",
+    "\u00c5",
+    "\u00c6",
+    "\u00c7",  # 192 - 199
+    "\u00c8",
+    "\u00c9",
+    "\u00ca",
+    "\u00cb",
+    "\u00cc",
+    "\u00cd",
+    "\u00ce",
+    "\u00cf",  # 200 - 207
+    "\u00d0",
+    "\u00d1",
+    "\u00d2",
+    "\u00d3",
+    "\u00d4",
+    "\u00d5",
+    "\u00d6",
+    "\u00d7",  # 208 - 215
+    "\u00d8",
+    "\u00d9",
+    "\u00da",
+    "\u00db",
+    "\u00dc",
+    "\u00dd",
+    "\u00de",
+    "\u00df",  # 216 - 223
+    "\u00e0",
+    "\u00e1",
+    "\u00e2",
+    "\u00e3",
+    "\u00e4",
+    "\u00e5",
+    "\u00e6",
+    "\u00e7",  # 224 - 231
+    "\u00e8",
+    "\u00e9",
+    "\u00ea",
+    "\u00eb",
+    "\u00ec",
+    "\u00ed",
+    "\u00ee",
+    "\u00ef",  # 232 - 239
+    "\u00f0",
+    "\u00f1",
+    "\u00f2",
+    "\u00f3",
+    "\u00f4",
+    "\u00f5",
+    "\u00f6",
+    "\u00f7",  # 240 - 247
+    "\u00f8",
+    "\u00f9",
+    "\u00fa",
+    "\u00fb",
+    "\u00fc",
+    "\u00fd",
+    "\u00fe",
+    "\u00ff",  # 248 - 255
+]
+
+assert len(_pdfdoc_encoding) == 256
diff --git a/.venv/lib/python3.12/site-packages/pypdf/_codecs/std.py b/.venv/lib/python3.12/site-packages/pypdf/_codecs/std.py
new file mode 100644
index 00000000..a6057ff3
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/_codecs/std.py
@@ -0,0 +1,258 @@
+_std_encoding = [
+    "\x00",
+    "\x01",
+    "\x02",
+    "\x03",
+    "\x04",
+    "\x05",
+    "\x06",
+    "\x07",
+    "\x08",
+    "\t",
+    "\n",
+    "\x0b",
+    "\x0c",
+    "\r",
+    "\x0e",
+    "\x0f",
+    "\x10",
+    "\x11",
+    "\x12",
+    "\x13",
+    "\x14",
+    "\x15",
+    "\x16",
+    "\x17",
+    "\x18",
+    "\x19",
+    "\x1a",
+    "\x1b",
+    "\x1c",
+    "\x1d",
+    "\x1e",
+    "\x1f",
+    " ",
+    "!",
+    '"',
+    "#",
+    "$",
+    "%",
+    "&",
+    "’",
+    "(",
+    ")",
+    "*",
+    "+",
+    ",",
+    "-",
+    ".",
+    "/",
+    "0",
+    "1",
+    "2",
+    "3",
+    "4",
+    "5",
+    "6",
+    "7",
+    "8",
+    "9",
+    ":",
+    ";",
+    "<",
+    "=",
+    ">",
+    "?",
+    "@",
+    "A",
+    "B",
+    "C",
+    "D",
+    "E",
+    "F",
+    "G",
+    "H",
+    "I",
+    "J",
+    "K",
+    "L",
+    "M",
+    "N",
+    "O",
+    "P",
+    "Q",
+    "R",
+    "S",
+    "T",
+    "U",
+    "V",
+    "W",
+    "X",
+    "Y",
+    "Z",
+    "[",
+    "\\",
+    "]",
+    "^",
+    "_",
+    "‘",
+    "a",
+    "b",
+    "c",
+    "d",
+    "e",
+    "f",
+    "g",
+    "h",
+    "i",
+    "j",
+    "k",
+    "l",
+    "m",
+    "n",
+    "o",
+    "p",
+    "q",
+    "r",
+    "s",
+    "t",
+    "u",
+    "v",
+    "w",
+    "x",
+    "y",
+    "z",
+    "{",
+    "|",
+    "}",
+    "~",
+    "\x7f",
+    "\x80",
+    "\x81",
+    "\x82",
+    "\x83",
+    "\x84",
+    "\x85",
+    "\x86",
+    "\x87",
+    "\x88",
+    "\x89",
+    "\x8a",
+    "\x8b",
+    "\x8c",
+    "\x8d",
+    "\x8e",
+    "\x8f",
+    "\x90",
+    "\x91",
+    "\x92",
+    "\x93",
+    "\x94",
+    "\x95",
+    "\x96",
+    "\x97",
+    "\x98",
+    "\x99",
+    "\x9a",
+    "\x9b",
+    "\x9c",
+    "\x9d",
+    "\x9e",
+    "\x9f",
+    "\xa0",
+    "¡",
+    "¢",
+    "£",
+    "⁄",
+    "¥",
+    "ƒ",
+    "§",
+    "¤",
+    "'",
+    "“",
+    "«",
+    "‹",
+    "›",
+    "fi",
+    "fl",
+    "°",
+    "–",
+    "†",
+    "‡",
+    "·",
+    "µ",
+    "¶",
+    "•",
+    "‚",
+    "„",
+    "”",
+    "»",
+    "…",
+    "‰",
+    "¾",
+    "¿",
+    "À",
+    "`",
+    "´",
+    "ˆ",
+    "˜",
+    "¯",
+    "˘",
+    "˙",
+    "¨",
+    "É",
+    "˚",
+    "¸",
+    "Ì",
+    "˝",
+    "˛",
+    "ˇ",
+    "—",
+    "Ñ",
+    "Ò",
+    "Ó",
+    "Ô",
+    "Õ",
+    "Ö",
+    "×",
+    "Ø",
+    "Ù",
+    "Ú",
+    "Û",
+    "Ü",
+    "Ý",
+    "Þ",
+    "ß",
+    "à",
+    "Æ",
+    "â",
+    "ª",
+    "ä",
+    "å",
+    "æ",
+    "ç",
+    "Ł",
+    "Ø",
+    "Œ",
+    "º",
+    "ì",
+    "í",
+    "î",
+    "ï",
+    "ð",
+    "æ",
+    "ò",
+    "ó",
+    "ô",
+    "ı",
+    "ö",
+    "÷",
+    "ł",
+    "ø",
+    "œ",
+    "ß",
+    "ü",
+    "ý",
+    "þ",
+    "ÿ",
+]
diff --git a/.venv/lib/python3.12/site-packages/pypdf/_codecs/symbol.py b/.venv/lib/python3.12/site-packages/pypdf/_codecs/symbol.py
new file mode 100644
index 00000000..4c0d680f
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/_codecs/symbol.py
@@ -0,0 +1,260 @@
+# manually generated from https://www.unicode.org/Public/MAPPINGS/VENDORS/ADOBE/symbol.txt
+_symbol_encoding = [
+    "\u0000",
+    "\u0001",
+    "\u0002",
+    "\u0003",
+    "\u0004",
+    "\u0005",
+    "\u0006",
+    "\u0007",
+    "\u0008",
+    "\u0009",
+    "\u000A",
+    "\u000B",
+    "\u000C",
+    "\u000D",
+    "\u000E",
+    "\u000F",
+    "\u0010",
+    "\u0011",
+    "\u0012",
+    "\u0013",
+    "\u0014",
+    "\u0015",
+    "\u0016",
+    "\u0017",
+    "\u0018",
+    "\u0019",
+    "\u001A",
+    "\u001B",
+    "\u001C",
+    "\u001D",
+    "\u001E",
+    "\u001F",
+    "\u0020",
+    "\u0021",
+    "\u2200",
+    "\u0023",
+    "\u2203",
+    "\u0025",
+    "\u0026",
+    "\u220B",
+    "\u0028",
+    "\u0029",
+    "\u2217",
+    "\u002B",
+    "\u002C",
+    "\u2212",
+    "\u002E",
+    "\u002F",
+    "\u0030",
+    "\u0031",
+    "\u0032",
+    "\u0033",
+    "\u0034",
+    "\u0035",
+    "\u0036",
+    "\u0037",
+    "\u0038",
+    "\u0039",
+    "\u003A",
+    "\u003B",
+    "\u003C",
+    "\u003D",
+    "\u003E",
+    "\u003F",
+    "\u2245",
+    "\u0391",
+    "\u0392",
+    "\u03A7",
+    "\u0394",
+    "\u0395",
+    "\u03A6",
+    "\u0393",
+    "\u0397",
+    "\u0399",
+    "\u03D1",
+    "\u039A",
+    "\u039B",
+    "\u039C",
+    "\u039D",
+    "\u039F",
+    "\u03A0",
+    "\u0398",
+    "\u03A1",
+    "\u03A3",
+    "\u03A4",
+    "\u03A5",
+    "\u03C2",
+    "\u03A9",
+    "\u039E",
+    "\u03A8",
+    "\u0396",
+    "\u005B",
+    "\u2234",
+    "\u005D",
+    "\u22A5",
+    "\u005F",
+    "\uF8E5",
+    "\u03B1",
+    "\u03B2",
+    "\u03C7",
+    "\u03B4",
+    "\u03B5",
+    "\u03C6",
+    "\u03B3",
+    "\u03B7",
+    "\u03B9",
+    "\u03D5",
+    "\u03BA",
+    "\u03BB",
+    "\u00B5",
+    "\u03BD",
+    "\u03BF",
+    "\u03C0",
+    "\u03B8",
+    "\u03C1",
+    "\u03C3",
+    "\u03C4",
+    "\u03C5",
+    "\u03D6",
+    "\u03C9",
+    "\u03BE",
+    "\u03C8",
+    "\u03B6",
+    "\u007B",
+    "\u007C",
+    "\u007D",
+    "\u223C",
+    "\u007F",
+    "\u0080",
+    "\u0081",
+    "\u0082",
+    "\u0083",
+    "\u0084",
+    "\u0085",
+    "\u0086",
+    "\u0087",
+    "\u0088",
+    "\u0089",
+    "\u008A",
+    "\u008B",
+    "\u008C",
+    "\u008D",
+    "\u008E",
+    "\u008F",
+    "\u0090",
+    "\u0091",
+    "\u0092",
+    "\u0093",
+    "\u0094",
+    "\u0095",
+    "\u0096",
+    "\u0097",
+    "\u0098",
+    "\u0099",
+    "\u009A",
+    "\u009B",
+    "\u009C",
+    "\u009D",
+    "\u009E",
+    "\u009F",
+    "\u20AC",
+    "\u03D2",
+    "\u2032",
+    "\u2264",
+    "\u2044",
+    "\u221E",
+    "\u0192",
+    "\u2663",
+    "\u2666",
+    "\u2665",
+    "\u2660",
+    "\u2194",
+    "\u2190",
+    "\u2191",
+    "\u2192",
+    "\u2193",
+    "\u00B0",
+    "\u00B1",
+    "\u2033",
+    "\u2265",
+    "\u00D7",
+    "\u221D",
+    "\u2202",
+    "\u2022",
+    "\u00F7",
+    "\u2260",
+    "\u2261",
+    "\u2248",
+    "\u2026",
+    "\uF8E6",
+    "\uF8E7",
+    "\u21B5",
+    "\u2135",
+    "\u2111",
+    "\u211C",
+    "\u2118",
+    "\u2297",
+    "\u2295",
+    "\u2205",
+    "\u2229",
+    "\u222A",
+    "\u2283",
+    "\u2287",
+    "\u2284",
+    "\u2282",
+    "\u2286",
+    "\u2208",
+    "\u2209",
+    "\u2220",
+    "\u2207",
+    "\uF6DA",
+    "\uF6D9",
+    "\uF6DB",
+    "\u220F",
+    "\u221A",
+    "\u22C5",
+    "\u00AC",
+    "\u2227",
+    "\u2228",
+    "\u21D4",
+    "\u21D0",
+    "\u21D1",
+    "\u21D2",
+    "\u21D3",
+    "\u25CA",
+    "\u2329",
+    "\uF8E8",
+    "\uF8E9",
+    "\uF8EA",
+    "\u2211",
+    "\uF8EB",
+    "\uF8EC",
+    "\uF8ED",
+    "\uF8EE",
+    "\uF8EF",
+    "\uF8F0",
+    "\uF8F1",
+    "\uF8F2",
+    "\uF8F3",
+    "\uF8F4",
+    "\u00F0",
+    "\u232A",
+    "\u222B",
+    "\u2320",
+    "\uF8F5",
+    "\u2321",
+    "\uF8F6",
+    "\uF8F7",
+    "\uF8F8",
+    "\uF8F9",
+    "\uF8FA",
+    "\uF8FB",
+    "\uF8FC",
+    "\uF8FD",
+    "\uF8FE",
+    "\u00FF",
+]
+assert len(_symbol_encoding) == 256
diff --git a/.venv/lib/python3.12/site-packages/pypdf/_codecs/zapfding.py b/.venv/lib/python3.12/site-packages/pypdf/_codecs/zapfding.py
new file mode 100644
index 00000000..9b6cdbcc
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/_codecs/zapfding.py
@@ -0,0 +1,261 @@
+#  manually generated from https://www.unicode.org/Public/MAPPINGS/VENDORS/ADOBE/zdingbat.txt
+
+_zapfding_encoding = [
+    "\u0000",
+    "\u0001",
+    "\u0002",
+    "\u0003",
+    "\u0004",
+    "\u0005",
+    "\u0006",
+    "\u0007",
+    "\u0008",
+    "\u0009",
+    "\u000A",
+    "\u000B",
+    "\u000C",
+    "\u000D",
+    "\u000E",
+    "\u000F",
+    "\u0010",
+    "\u0011",
+    "\u0012",
+    "\u0013",
+    "\u0014",
+    "\u0015",
+    "\u0016",
+    "\u0017",
+    "\u0018",
+    "\u0019",
+    "\u001A",
+    "\u001B",
+    "\u001C",
+    "\u001D",
+    "\u001E",
+    "\u001F",
+    "\u0020",
+    "\u2701",
+    "\u2702",
+    "\u2703",
+    "\u2704",
+    "\u260E",
+    "\u2706",
+    "\u2707",
+    "\u2708",
+    "\u2709",
+    "\u261B",
+    "\u261E",
+    "\u270C",
+    "\u270D",
+    "\u270E",
+    "\u270F",
+    "\u2710",
+    "\u2711",
+    "\u2712",
+    "\u2713",
+    "\u2714",
+    "\u2715",
+    "\u2716",
+    "\u2717",
+    "\u2718",
+    "\u2719",
+    "\u271A",
+    "\u271B",
+    "\u271C",
+    "\u271D",
+    "\u271E",
+    "\u271F",
+    "\u2720",
+    "\u2721",
+    "\u2722",
+    "\u2723",
+    "\u2724",
+    "\u2725",
+    "\u2726",
+    "\u2727",
+    "\u2605",
+    "\u2729",
+    "\u272A",
+    "\u272B",
+    "\u272C",
+    "\u272D",
+    "\u272E",
+    "\u272F",
+    "\u2730",
+    "\u2731",
+    "\u2732",
+    "\u2733",
+    "\u2734",
+    "\u2735",
+    "\u2736",
+    "\u2737",
+    "\u2738",
+    "\u2739",
+    "\u273A",
+    "\u273B",
+    "\u273C",
+    "\u273D",
+    "\u273E",
+    "\u273F",
+    "\u2740",
+    "\u2741",
+    "\u2742",
+    "\u2743",
+    "\u2744",
+    "\u2745",
+    "\u2746",
+    "\u2747",
+    "\u2748",
+    "\u2749",
+    "\u274A",
+    "\u274B",
+    "\u25CF",
+    "\u274D",
+    "\u25A0",
+    "\u274F",
+    "\u2750",
+    "\u2751",
+    "\u2752",
+    "\u25B2",
+    "\u25BC",
+    "\u25C6",
+    "\u2756",
+    "\u25D7",
+    "\u2758",
+    "\u2759",
+    "\u275A",
+    "\u275B",
+    "\u275C",
+    "\u275D",
+    "\u275E",
+    "\u007F",
+    "\uF8D7",
+    "\uF8D8",
+    "\uF8D9",
+    "\uF8DA",
+    "\uF8DB",
+    "\uF8DC",
+    "\uF8DD",
+    "\uF8DE",
+    "\uF8DF",
+    "\uF8E0",
+    "\uF8E1",
+    "\uF8E2",
+    "\uF8E3",
+    "\uF8E4",
+    "\u008E",
+    "\u008F",
+    "\u0090",
+    "\u0091",
+    "\u0092",
+    "\u0093",
+    "\u0094",
+    "\u0095",
+    "\u0096",
+    "\u0097",
+    "\u0098",
+    "\u0099",
+    "\u009A",
+    "\u009B",
+    "\u009C",
+    "\u009D",
+    "\u009E",
+    "\u009F",
+    "\u00A0",
+    "\u2761",
+    "\u2762",
+    "\u2763",
+    "\u2764",
+    "\u2765",
+    "\u2766",
+    "\u2767",
+    "\u2663",
+    "\u2666",
+    "\u2665",
+    "\u2660",
+    "\u2460",
+    "\u2461",
+    "\u2462",
+    "\u2463",
+    "\u2464",
+    "\u2465",
+    "\u2466",
+    "\u2467",
+    "\u2468",
+    "\u2469",
+    "\u2776",
+    "\u2777",
+    "\u2778",
+    "\u2779",
+    "\u277A",
+    "\u277B",
+    "\u277C",
+    "\u277D",
+    "\u277E",
+    "\u277F",
+    "\u2780",
+    "\u2781",
+    "\u2782",
+    "\u2783",
+    "\u2784",
+    "\u2785",
+    "\u2786",
+    "\u2787",
+    "\u2788",
+    "\u2789",
+    "\u278A",
+    "\u278B",
+    "\u278C",
+    "\u278D",
+    "\u278E",
+    "\u278F",
+    "\u2790",
+    "\u2791",
+    "\u2792",
+    "\u2793",
+    "\u2794",
+    "\u2192",
+    "\u2194",
+    "\u2195",
+    "\u2798",
+    "\u2799",
+    "\u279A",
+    "\u279B",
+    "\u279C",
+    "\u279D",
+    "\u279E",
+    "\u279F",
+    "\u27A0",
+    "\u27A1",
+    "\u27A2",
+    "\u27A3",
+    "\u27A4",
+    "\u27A5",
+    "\u27A6",
+    "\u27A7",
+    "\u27A8",
+    "\u27A9",
+    "\u27AA",
+    "\u27AB",
+    "\u27AC",
+    "\u27AD",
+    "\u27AE",
+    "\u27AF",
+    "\u00F0",
+    "\u27B1",
+    "\u27B2",
+    "\u27B3",
+    "\u27B4",
+    "\u27B5",
+    "\u27B6",
+    "\u27B7",
+    "\u27B8",
+    "\u27B9",
+    "\u27BA",
+    "\u27BB",
+    "\u27BC",
+    "\u27BD",
+    "\u27BE",
+    "\u00FF",
+]
+assert len(_zapfding_encoding) == 256
diff --git a/.venv/lib/python3.12/site-packages/pypdf/_crypt_providers/__init__.py b/.venv/lib/python3.12/site-packages/pypdf/_crypt_providers/__init__.py
new file mode 100644
index 00000000..49d41128
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/_crypt_providers/__init__.py
@@ -0,0 +1,86 @@
+# Copyright (c) 2023, exiledkingcc
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# * The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+from pypdf._crypt_providers._base import CryptBase, CryptIdentity
+
+try:
+    from pypdf._crypt_providers._cryptography import (
+        CryptAES,
+        CryptRC4,
+        aes_cbc_decrypt,
+        aes_cbc_encrypt,
+        aes_ecb_decrypt,
+        aes_ecb_encrypt,
+        crypt_provider,
+        rc4_decrypt,
+        rc4_encrypt,
+    )
+    from pypdf._utils import Version
+
+    if Version(crypt_provider[1]) <= Version("3.0"):
+        # This is due to the backend parameter being required back then:
+        # https://cryptography.io/en/latest/changelog/#v3-1
+        raise ImportError("cryptography<=3.0 is not supported")  # pragma: no cover
+except ImportError:
+    try:
+        from pypdf._crypt_providers._pycryptodome import (  # type: ignore
+            CryptAES,
+            CryptRC4,
+            aes_cbc_decrypt,
+            aes_cbc_encrypt,
+            aes_ecb_decrypt,
+            aes_ecb_encrypt,
+            crypt_provider,
+            rc4_decrypt,
+            rc4_encrypt,
+        )
+    except ImportError:
+        from pypdf._crypt_providers._fallback import (  # type: ignore
+            CryptAES,
+            CryptRC4,
+            aes_cbc_decrypt,
+            aes_cbc_encrypt,
+            aes_ecb_decrypt,
+            aes_ecb_encrypt,
+            crypt_provider,
+            rc4_decrypt,
+            rc4_encrypt,
+        )
+
+__all__ = [
+    "crypt_provider",
+    "CryptBase",
+    "CryptIdentity",
+    "CryptRC4",
+    "CryptAES",
+    "rc4_encrypt",
+    "rc4_decrypt",
+    "aes_ecb_encrypt",
+    "aes_ecb_decrypt",
+    "aes_cbc_encrypt",
+    "aes_cbc_decrypt",
+]
diff --git a/.venv/lib/python3.12/site-packages/pypdf/_crypt_providers/_base.py b/.venv/lib/python3.12/site-packages/pypdf/_crypt_providers/_base.py
new file mode 100644
index 00000000..894025f3
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/_crypt_providers/_base.py
@@ -0,0 +1,38 @@
+# Copyright (c) 2023, exiledkingcc
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# * The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+
+class CryptBase:
+    def encrypt(self, data: bytes) -> bytes:  # pragma: no cover
+        return data
+
+    def decrypt(self, data: bytes) -> bytes:  # pragma: no cover
+        return data
+
+
+class CryptIdentity(CryptBase):
+    pass
diff --git a/.venv/lib/python3.12/site-packages/pypdf/_crypt_providers/_cryptography.py b/.venv/lib/python3.12/site-packages/pypdf/_crypt_providers/_cryptography.py
new file mode 100644
index 00000000..f5537612
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/_crypt_providers/_cryptography.py
@@ -0,0 +1,118 @@
+# Copyright (c) 2023, exiledkingcc
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# * The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+import secrets
+
+from cryptography import __version__
+from cryptography.hazmat.primitives import padding
+from cryptography.hazmat.primitives.ciphers.algorithms import AES
+
+try:
+    # 43.0.0 - https://cryptography.io/en/latest/changelog/#v43-0-0
+    from cryptography.hazmat.decrepit.ciphers.algorithms import ARC4
+except ImportError:
+    from cryptography.hazmat.primitives.ciphers.algorithms import ARC4
+from cryptography.hazmat.primitives.ciphers.base import Cipher
+from cryptography.hazmat.primitives.ciphers.modes import CBC, ECB
+
+from pypdf._crypt_providers._base import CryptBase
+
+crypt_provider = ("cryptography", __version__)
+
+
+class CryptRC4(CryptBase):
+    def __init__(self, key: bytes) -> None:
+        self.cipher = Cipher(ARC4(key), mode=None)
+
+    def encrypt(self, data: bytes) -> bytes:
+        encryptor = self.cipher.encryptor()
+        return encryptor.update(data) + encryptor.finalize()
+
+    def decrypt(self, data: bytes) -> bytes:
+        decryptor = self.cipher.decryptor()
+        return decryptor.update(data) + decryptor.finalize()
+
+
+class CryptAES(CryptBase):
+    def __init__(self, key: bytes) -> None:
+        self.alg = AES(key)
+
+    def encrypt(self, data: bytes) -> bytes:
+        iv = secrets.token_bytes(16)
+        pad = padding.PKCS7(128).padder()
+        data = pad.update(data) + pad.finalize()
+
+        cipher = Cipher(self.alg, CBC(iv))
+        encryptor = cipher.encryptor()
+        return iv + encryptor.update(data) + encryptor.finalize()
+
+    def decrypt(self, data: bytes) -> bytes:
+        iv = data[:16]
+        data = data[16:]
+        # for empty encrypted data
+        if not data:
+            return data
+
+        # just for robustness, it does not happen under normal circumstances
+        if len(data) % 16 != 0:
+            pad = padding.PKCS7(128).padder()
+            data = pad.update(data) + pad.finalize()
+
+        cipher = Cipher(self.alg, CBC(iv))
+        decryptor = cipher.decryptor()
+        d = decryptor.update(data) + decryptor.finalize()
+        return d[: -d[-1]]
+
+
+def rc4_encrypt(key: bytes, data: bytes) -> bytes:
+    encryptor = Cipher(ARC4(key), mode=None).encryptor()
+    return encryptor.update(data) + encryptor.finalize()
+
+
+def rc4_decrypt(key: bytes, data: bytes) -> bytes:
+    decryptor = Cipher(ARC4(key), mode=None).decryptor()
+    return decryptor.update(data) + decryptor.finalize()
+
+
+def aes_ecb_encrypt(key: bytes, data: bytes) -> bytes:
+    encryptor = Cipher(AES(key), mode=ECB()).encryptor()
+    return encryptor.update(data) + encryptor.finalize()
+
+
+def aes_ecb_decrypt(key: bytes, data: bytes) -> bytes:
+    decryptor = Cipher(AES(key), mode=ECB()).decryptor()
+    return decryptor.update(data) + decryptor.finalize()
+
+
+def aes_cbc_encrypt(key: bytes, iv: bytes, data: bytes) -> bytes:
+    encryptor = Cipher(AES(key), mode=CBC(iv)).encryptor()
+    return encryptor.update(data) + encryptor.finalize()
+
+
+def aes_cbc_decrypt(key: bytes, iv: bytes, data: bytes) -> bytes:
+    decryptor = Cipher(AES(key), mode=CBC(iv)).decryptor()
+    return decryptor.update(data) + decryptor.finalize()
diff --git a/.venv/lib/python3.12/site-packages/pypdf/_crypt_providers/_fallback.py b/.venv/lib/python3.12/site-packages/pypdf/_crypt_providers/_fallback.py
new file mode 100644
index 00000000..631fec19
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/_crypt_providers/_fallback.py
@@ -0,0 +1,93 @@
+# Copyright (c) 2023, exiledkingcc
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# * The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+from pypdf._crypt_providers._base import CryptBase
+from pypdf.errors import DependencyError
+
+_DEPENDENCY_ERROR_STR = "cryptography>=3.1 is required for AES algorithm"
+
+
+crypt_provider = ("local_crypt_fallback", "0.0.0")
+
+
+class CryptRC4(CryptBase):
+    def __init__(self, key: bytes) -> None:
+        self.s = bytearray(range(256))
+        j = 0
+        for i in range(256):
+            j = (j + self.s[i] + key[i % len(key)]) % 256
+            self.s[i], self.s[j] = self.s[j], self.s[i]
+
+    def encrypt(self, data: bytes) -> bytes:
+        s = bytearray(self.s)
+        out = [0 for _ in range(len(data))]
+        i, j = 0, 0
+        for k in range(len(data)):
+            i = (i + 1) % 256
+            j = (j + s[i]) % 256
+            s[i], s[j] = s[j], s[i]
+            x = s[(s[i] + s[j]) % 256]
+            out[k] = data[k] ^ x
+        return bytes(bytearray(out))
+
+    def decrypt(self, data: bytes) -> bytes:
+        return self.encrypt(data)
+
+
+class CryptAES(CryptBase):
+    def __init__(self, key: bytes) -> None:
+        pass
+
+    def encrypt(self, data: bytes) -> bytes:
+        raise DependencyError(_DEPENDENCY_ERROR_STR)
+
+    def decrypt(self, data: bytes) -> bytes:
+        raise DependencyError(_DEPENDENCY_ERROR_STR)
+
+
+def rc4_encrypt(key: bytes, data: bytes) -> bytes:
+    return CryptRC4(key).encrypt(data)
+
+
+def rc4_decrypt(key: bytes, data: bytes) -> bytes:
+    return CryptRC4(key).decrypt(data)
+
+
+def aes_ecb_encrypt(key: bytes, data: bytes) -> bytes:
+    raise DependencyError(_DEPENDENCY_ERROR_STR)
+
+
+def aes_ecb_decrypt(key: bytes, data: bytes) -> bytes:
+    raise DependencyError(_DEPENDENCY_ERROR_STR)
+
+
+def aes_cbc_encrypt(key: bytes, iv: bytes, data: bytes) -> bytes:
+    raise DependencyError(_DEPENDENCY_ERROR_STR)
+
+
+def aes_cbc_decrypt(key: bytes, iv: bytes, data: bytes) -> bytes:
+    raise DependencyError(_DEPENDENCY_ERROR_STR)
diff --git a/.venv/lib/python3.12/site-packages/pypdf/_crypt_providers/_pycryptodome.py b/.venv/lib/python3.12/site-packages/pypdf/_crypt_providers/_pycryptodome.py
new file mode 100644
index 00000000..30a13e18
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/_crypt_providers/_pycryptodome.py
@@ -0,0 +1,97 @@
+# Copyright (c) 2023, exiledkingcc
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# * The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+import secrets
+
+from Crypto import __version__
+from Crypto.Cipher import AES, ARC4
+from Crypto.Util.Padding import pad
+
+from pypdf._crypt_providers._base import CryptBase
+
+crypt_provider = ("pycryptodome", __version__)
+
+
+class CryptRC4(CryptBase):
+    def __init__(self, key: bytes) -> None:
+        self.key = key
+
+    def encrypt(self, data: bytes) -> bytes:
+        return ARC4.ARC4Cipher(self.key).encrypt(data)
+
+    def decrypt(self, data: bytes) -> bytes:
+        return ARC4.ARC4Cipher(self.key).decrypt(data)
+
+
+class CryptAES(CryptBase):
+    def __init__(self, key: bytes) -> None:
+        self.key = key
+
+    def encrypt(self, data: bytes) -> bytes:
+        iv = secrets.token_bytes(16)
+        data = pad(data, 16)
+        aes = AES.new(self.key, AES.MODE_CBC, iv)
+        return iv + aes.encrypt(data)
+
+    def decrypt(self, data: bytes) -> bytes:
+        iv = data[:16]
+        data = data[16:]
+        # for empty encrypted data
+        if not data:
+            return data
+
+        # just for robustness, it does not happen under normal circumstances
+        if len(data) % 16 != 0:
+            data = pad(data, 16)
+
+        aes = AES.new(self.key, AES.MODE_CBC, iv)
+        d = aes.decrypt(data)
+        return d[: -d[-1]]
+
+
+def rc4_encrypt(key: bytes, data: bytes) -> bytes:
+    return ARC4.ARC4Cipher(key).encrypt(data)
+
+
+def rc4_decrypt(key: bytes, data: bytes) -> bytes:
+    return ARC4.ARC4Cipher(key).decrypt(data)
+
+
+def aes_ecb_encrypt(key: bytes, data: bytes) -> bytes:
+    return AES.new(key, AES.MODE_ECB).encrypt(data)
+
+
+def aes_ecb_decrypt(key: bytes, data: bytes) -> bytes:
+    return AES.new(key, AES.MODE_ECB).decrypt(data)
+
+
+def aes_cbc_encrypt(key: bytes, iv: bytes, data: bytes) -> bytes:
+    return AES.new(key, AES.MODE_CBC, iv).encrypt(data)
+
+
+def aes_cbc_decrypt(key: bytes, iv: bytes, data: bytes) -> bytes:
+    return AES.new(key, AES.MODE_CBC, iv).decrypt(data)
diff --git a/.venv/lib/python3.12/site-packages/pypdf/_doc_common.py b/.venv/lib/python3.12/site-packages/pypdf/_doc_common.py
new file mode 100644
index 00000000..d4c5c43c
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/_doc_common.py
@@ -0,0 +1,1365 @@
+# Copyright (c) 2006, Mathieu Fenniak
+# Copyright (c) 2007, Ashish Kulkarni <kulkarni.ashish@gmail.com>
+# Copyright (c) 2024, Pubpub-ZZ
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# * The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+import struct
+import zlib
+from abc import abstractmethod
+from datetime import datetime
+from typing import (
+    Any,
+    Dict,
+    Iterable,
+    Iterator,
+    List,
+    Mapping,
+    Optional,
+    Tuple,
+    Union,
+    cast,
+)
+
+from ._encryption import Encryption
+from ._page import PageObject, _VirtualList
+from ._page_labels import index2label as page_index2page_label
+from ._utils import (
+    b_,
+    deprecate_with_replacement,
+    logger_warning,
+    parse_iso8824_date,
+)
+from .constants import CatalogAttributes as CA
+from .constants import CatalogDictionary as CD
+from .constants import (
+    CheckboxRadioButtonAttributes,
+    GoToActionArguments,
+    UserAccessPermissions,
+)
+from .constants import Core as CO
+from .constants import DocumentInformationAttributes as DI
+from .constants import FieldDictionaryAttributes as FA
+from .constants import PageAttributes as PG
+from .constants import PagesAttributes as PA
+from .errors import (
+    PdfReadError,
+)
+from .generic import (
+    ArrayObject,
+    BooleanObject,
+    ByteStringObject,
+    Destination,
+    DictionaryObject,
+    EncodedStreamObject,
+    Field,
+    Fit,
+    FloatObject,
+    IndirectObject,
+    NameObject,
+    NullObject,
+    NumberObject,
+    PdfObject,
+    TextStringObject,
+    TreeObject,
+    ViewerPreferences,
+    create_string_object,
+)
+from .types import OutlineType, PagemodeType
+from .xmp import XmpInformation
+
+
+def convert_to_int(d: bytes, size: int) -> Union[int, Tuple[Any, ...]]:
+    if size > 8:
+        raise PdfReadError("invalid size in convert_to_int")
+    d = b"\x00\x00\x00\x00\x00\x00\x00\x00" + d
+    d = d[-8:]
+    return struct.unpack(">q", d)[0]
+
+
+class DocumentInformation(DictionaryObject):
+    """
+    A class representing the basic document metadata provided in a PDF File.
+    This class is accessible through
+    :py:class:`PdfReader.metadata<pypdf.PdfReader.metadata>`.
+
+    All text properties of the document metadata have
+    *two* properties, e.g. author and author_raw. The non-raw property will
+    always return a ``TextStringObject``, making it ideal for a case where the
+    metadata is being displayed. The raw property can sometimes return a
+    ``ByteStringObject``, if pypdf was unable to decode the string's text
+    encoding; this requires additional safety in the caller and therefore is not
+    as commonly accessed.
+    """
+
+    def __init__(self) -> None:
+        DictionaryObject.__init__(self)
+
+    def _get_text(self, key: str) -> Optional[str]:
+        retval = self.get(key, None)
+        if isinstance(retval, TextStringObject):
+            return retval
+        return None
+
+    @property
+    def title(self) -> Optional[str]:
+        """
+        Read-only property accessing the document's title.
+
+        Returns a ``TextStringObject`` or ``None`` if the title is not
+        specified.
+        """
+        return (
+            self._get_text(DI.TITLE) or self.get(DI.TITLE).get_object()  # type: ignore
+            if self.get(DI.TITLE)
+            else None
+        )
+
+    @property
+    def title_raw(self) -> Optional[str]:
+        """The "raw" version of title; can return a ``ByteStringObject``."""
+        return self.get(DI.TITLE)
+
+    @property
+    def author(self) -> Optional[str]:
+        """
+        Read-only property accessing the document's author.
+
+        Returns a ``TextStringObject`` or ``None`` if the author is not
+        specified.
+        """
+        return self._get_text(DI.AUTHOR)
+
+    @property
+    def author_raw(self) -> Optional[str]:
+        """The "raw" version of author; can return a ``ByteStringObject``."""
+        return self.get(DI.AUTHOR)
+
+    @property
+    def subject(self) -> Optional[str]:
+        """
+        Read-only property accessing the document's subject.
+
+        Returns a ``TextStringObject`` or ``None`` if the subject is not
+        specified.
+        """
+        return self._get_text(DI.SUBJECT)
+
+    @property
+    def subject_raw(self) -> Optional[str]:
+        """The "raw" version of subject; can return a ``ByteStringObject``."""
+        return self.get(DI.SUBJECT)
+
+    @property
+    def creator(self) -> Optional[str]:
+        """
+        Read-only property accessing the document's creator.
+
+        If the document was converted to PDF from another format, this is the
+        name of the application (e.g. OpenOffice) that created the original
+        document from which it was converted. Returns a ``TextStringObject`` or
+        ``None`` if the creator is not specified.
+        """
+        return self._get_text(DI.CREATOR)
+
+    @property
+    def creator_raw(self) -> Optional[str]:
+        """The "raw" version of creator; can return a ``ByteStringObject``."""
+        return self.get(DI.CREATOR)
+
+    @property
+    def producer(self) -> Optional[str]:
+        """
+        Read-only property accessing the document's producer.
+
+        If the document was converted to PDF from another format, this is the
+        name of the application (for example, macOS Quartz) that converted it to
+        PDF. Returns a ``TextStringObject`` or ``None`` if the producer is not
+        specified.
+        """
+        return self._get_text(DI.PRODUCER)
+
+    @property
+    def producer_raw(self) -> Optional[str]:
+        """The "raw" version of producer; can return a ``ByteStringObject``."""
+        return self.get(DI.PRODUCER)
+
+    @property
+    def creation_date(self) -> Optional[datetime]:
+        """Read-only property accessing the document's creation date."""
+        return parse_iso8824_date(self._get_text(DI.CREATION_DATE))
+
+    @property
+    def creation_date_raw(self) -> Optional[str]:
+        """
+        The "raw" version of creation date; can return a ``ByteStringObject``.
+
+        Typically in the format ``D:YYYYMMDDhhmmss[+Z-]hh'mm`` where the suffix
+        is the offset from UTC.
+        """
+        return self.get(DI.CREATION_DATE)
+
+    @property
+    def modification_date(self) -> Optional[datetime]:
+        """
+        Read-only property accessing the document's modification date.
+
+        The date and time the document was most recently modified.
+        """
+        return parse_iso8824_date(self._get_text(DI.MOD_DATE))
+
+    @property
+    def modification_date_raw(self) -> Optional[str]:
+        """
+        The "raw" version of modification date; can return a
+        ``ByteStringObject``.
+
+        Typically in the format ``D:YYYYMMDDhhmmss[+Z-]hh'mm`` where the suffix
+        is the offset from UTC.
+        """
+        return self.get(DI.MOD_DATE)
+
+
+class PdfDocCommon:
+    """
+    Common functions from PdfWriter and PdfReader objects.
+
+    This root class is strongly abstracted.
+    """
+
+    strict: bool = False  # default
+
+    _encryption: Optional[Encryption] = None
+
+    @property
+    @abstractmethod
+    def root_object(self) -> DictionaryObject:
+        ...  # pragma: no cover
+
+    @property
+    @abstractmethod
+    def pdf_header(self) -> str:
+        ...  # pragma: no cover
+
+    @abstractmethod
+    def get_object(
+        self, indirect_reference: Union[int, IndirectObject]
+    ) -> Optional[PdfObject]:
+        ...  # pragma: no cover
+
+    @abstractmethod
+    def _replace_object(self, indirect: IndirectObject, obj: PdfObject) -> PdfObject:
+        ...  # pragma: no cover
+
+    @property
+    @abstractmethod
+    def _info(self) -> Optional[DictionaryObject]:
+        ...  # pragma: no cover
+
+    @property
+    def metadata(self) -> Optional[DocumentInformation]:
+        """
+        Retrieve the PDF file's document information dictionary, if it exists.
+
+        Note that some PDF files use metadata streams instead of document
+        information dictionaries, and these metadata streams will not be
+        accessed by this function.
+        """
+        retval = DocumentInformation()
+        if self._info is None:
+            return None
+        retval.update(self._info)
+        return retval
+
+    @property
+    def xmp_metadata(self) -> Optional[XmpInformation]:
+        ...  # pragma: no cover
+
+    @abstractmethod
+    def _repr_mimebundle_(
+        self,
+        include: Union[None, Iterable[str]] = None,
+        exclude: Union[None, Iterable[str]] = None,
+    ) -> Dict[str, Any]:
+        """
+        Integration into Jupyter Notebooks.
+
+        This method returns a dictionary that maps a mime-type to its
+        representation.
+
+        See https://ipython.readthedocs.io/en/stable/config/integrating.html
+        """
+        ...  # pragma: no cover
+
+    @property
+    def viewer_preferences(self) -> Optional[ViewerPreferences]:
+        """Returns the existing ViewerPreferences as an overloaded dictionary."""
+        o = self.root_object.get(CD.VIEWER_PREFERENCES, None)
+        if o is None:
+            return None
+        o = o.get_object()
+        if not isinstance(o, ViewerPreferences):
+            o = ViewerPreferences(o)
+            if hasattr(o, "indirect_reference"):
+                self._replace_object(o.indirect_reference, o)
+            else:
+                self.root_object[NameObject(CD.VIEWER_PREFERENCES)] = o
+        return o
+
+    flattened_pages: Optional[List[PageObject]] = None
+
+    def get_num_pages(self) -> int:
+        """
+        Calculate the number of pages in this PDF file.
+
+        Returns:
+            The number of pages of the parsed PDF file.
+
+        Raises:
+            PdfReadError: if file is encrypted and restrictions prevent
+                this action.
+        """
+        # Flattened pages will not work on an encrypted PDF;
+        # the PDF file's page count is used in this case. Otherwise,
+        # the original method (flattened page count) is used.
+        if self.is_encrypted:
+            return self.root_object["/Pages"]["/Count"]  # type: ignore
+        else:
+            if self.flattened_pages is None:
+                self._flatten()
+            assert self.flattened_pages is not None
+            return len(self.flattened_pages)
+
+    def get_page(self, page_number: int) -> PageObject:
+        """
+        Retrieve a page by number from this PDF file.
+        Most of the time ``.pages[page_number]`` is preferred.
+
+        Args:
+            page_number: The page number to retrieve
+                (pages begin at zero)
+
+        Returns:
+            A :class:`PageObject<pypdf._page.PageObject>` instance.
+        """
+        if self.flattened_pages is None:
+            self._flatten()
+        assert self.flattened_pages is not None, "hint for mypy"
+        return self.flattened_pages[page_number]
+
+    @property
+    def named_destinations(self) -> Dict[str, Any]:
+        """
+        A read-only dictionary which maps names to
+        :class:`Destinations<pypdf.generic.Destination>`
+        """
+        return self._get_named_destinations()
+
+    def get_named_dest_root(self) -> ArrayObject:
+        named_dest = ArrayObject()
+        if CA.NAMES in self.root_object and isinstance(
+            self.root_object[CA.NAMES], DictionaryObject
+        ):
+            names = cast(DictionaryObject, self.root_object[CA.NAMES])
+            names_ref = names.indirect_reference
+            if CA.DESTS in names and isinstance(names[CA.DESTS], DictionaryObject):
+                # 3.6.3 Name Dictionary (PDF spec 1.7)
+                dests = cast(DictionaryObject, names[CA.DESTS])
+                dests_ref = dests.indirect_reference
+                if CA.NAMES in dests:
+                    # §7.9.6, entries in a name tree node dictionary
+                    named_dest = cast(ArrayObject, dests[CA.NAMES])
+                else:
+                    named_dest = ArrayObject()
+                    dests[NameObject(CA.NAMES)] = named_dest
+            elif hasattr(self, "_add_object"):
+                dests = DictionaryObject()
+                dests_ref = self._add_object(dests)
+                names[NameObject(CA.DESTS)] = dests_ref
+                dests[NameObject(CA.NAMES)] = named_dest
+
+        elif hasattr(self, "_add_object"):
+            names = DictionaryObject()
+            names_ref = self._add_object(names)
+            self.root_object[NameObject(CA.NAMES)] = names_ref
+            dests = DictionaryObject()
+            dests_ref = self._add_object(dests)
+            names[NameObject(CA.DESTS)] = dests_ref
+            dests[NameObject(CA.NAMES)] = named_dest
+
+        return named_dest
+
+    ## common
+    def _get_named_destinations(
+        self,
+        tree: Union[TreeObject, None] = None,
+        retval: Optional[Any] = None,
+    ) -> Dict[str, Any]:
+        """
+        Retrieve the named destinations present in the document.
+
+        Args:
+            tree:
+            retval:
+
+        Returns:
+            A dictionary which maps names to
+            :class:`Destinations<pypdf.generic.Destination>`.
+        """
+        if retval is None:
+            retval = {}
+            catalog = self.root_object
+
+            # get the name tree
+            if CA.DESTS in catalog:
+                tree = cast(TreeObject, catalog[CA.DESTS])
+            elif CA.NAMES in catalog:
+                names = cast(DictionaryObject, catalog[CA.NAMES])
+                if CA.DESTS in names:
+                    tree = cast(TreeObject, names[CA.DESTS])
+
+        if tree is None:
+            return retval
+
+        if PA.KIDS in tree:
+            # recurse down the tree
+            for kid in cast(ArrayObject, tree[PA.KIDS]):
+                self._get_named_destinations(kid.get_object(), retval)
+        # §7.9.6, entries in a name tree node dictionary
+        elif CA.NAMES in tree:  # /Kids and /Names are exclusives (§7.9.6)
+            names = cast(DictionaryObject, tree[CA.NAMES])
+            i = 0
+            while i < len(names):
+                key = cast(str, names[i].get_object())
+                i += 1
+                if not isinstance(key, str):
+                    continue
+                try:
+                    value = names[i].get_object()
+                except IndexError:
+                    break
+                i += 1
+                if isinstance(value, DictionaryObject):
+                    if "/D" in value:
+                        value = value["/D"]
+                    else:
+                        continue
+                dest = self._build_destination(key, value)  # type: ignore
+                if dest is not None:
+                    retval[key] = dest
+        else:  # case where Dests is in root catalog (PDF 1.7 specs, §2 about PDF 1.1)
+            for k__, v__ in tree.items():
+                val = v__.get_object()
+                if isinstance(val, DictionaryObject):
+                    if "/D" in val:
+                        val = val["/D"].get_object()
+                    else:
+                        continue
+                dest = self._build_destination(k__, val)
+                if dest is not None:
+                    retval[k__] = dest
+        return retval
+
+    # A select group of relevant field attributes. For the complete list.
+    # See §12.3.2 of the PDF 1.7 or PDF 2.0 specification.
+
+    def get_fields(
+        self,
+        tree: Optional[TreeObject] = None,
+        retval: Optional[Dict[Any, Any]] = None,
+        fileobj: Optional[Any] = None,
+        stack: Optional[List[PdfObject]] = None,
+    ) -> Optional[Dict[str, Any]]:
+        """
+        Extract field data if this PDF contains interactive form fields.
+
+        The *tree*, *retval*, *stack* parameters are for recursive use.
+
+        Args:
+            tree: Current object to parse.
+            retval: In-progress list of fields.
+            fileobj: A file object (usually a text file) to write
+                a report to on all interactive form fields found.
+            stack: List of already parsed objects.
+
+        Returns:
+            A dictionary where each key is a field name, and each
+            value is a :class:`Field<pypdf.generic.Field>` object. By
+            default, the mapping name is used for keys.
+            ``None`` if form data could not be located.
+        """
+        field_attributes = FA.attributes_dict()
+        field_attributes.update(CheckboxRadioButtonAttributes.attributes_dict())
+        if retval is None:
+            retval = {}
+            catalog = self.root_object
+            stack = []
+            # get the AcroForm tree
+            if CD.ACRO_FORM in catalog:
+                tree = cast(Optional[TreeObject], catalog[CD.ACRO_FORM])
+            else:
+                return None
+        if tree is None:
+            return retval
+        assert stack is not None
+        if "/Fields" in tree:
+            fields = cast(ArrayObject, tree["/Fields"])
+            for f in fields:
+                field = f.get_object()
+                self._build_field(field, retval, fileobj, field_attributes, stack)
+        elif any(attr in tree for attr in field_attributes):
+            # Tree is a field
+            self._build_field(tree, retval, fileobj, field_attributes, stack)
+        return retval
+
+    def _get_qualified_field_name(self, parent: DictionaryObject) -> str:
+        if "/TM" in parent:
+            return cast(str, parent["/TM"])
+        elif "/Parent" in parent:
+            return (
+                self._get_qualified_field_name(
+                    cast(DictionaryObject, parent["/Parent"])
+                )
+                + "."
+                + cast(str, parent.get("/T", ""))
+            )
+        else:
+            return cast(str, parent.get("/T", ""))
+
+    def _build_field(
+        self,
+        field: Union[TreeObject, DictionaryObject],
+        retval: Dict[Any, Any],
+        fileobj: Any,
+        field_attributes: Any,
+        stack: List[PdfObject],
+    ) -> None:
+        if all(attr not in field for attr in ("/T", "/TM")):
+            return
+        key = self._get_qualified_field_name(field)
+        if fileobj:
+            self._write_field(fileobj, field, field_attributes)
+            fileobj.write("\n")
+        retval[key] = Field(field)
+        obj = retval[key].indirect_reference.get_object()  # to get the full object
+        if obj.get(FA.FT, "") == "/Ch":
+            retval[key][NameObject("/_States_")] = obj[NameObject(FA.Opt)]
+        if obj.get(FA.FT, "") == "/Btn" and "/AP" in obj:
+            #  Checkbox
+            retval[key][NameObject("/_States_")] = ArrayObject(
+                list(obj["/AP"]["/N"].keys())
+            )
+            if "/Off" not in retval[key]["/_States_"]:
+                retval[key][NameObject("/_States_")].append(NameObject("/Off"))
+        elif obj.get(FA.FT, "") == "/Btn" and obj.get(FA.Ff, 0) & FA.FfBits.Radio != 0:
+            states: List[str] = []
+            retval[key][NameObject("/_States_")] = ArrayObject(states)
+            for k in obj.get(FA.Kids, {}):
+                k = k.get_object()
+                for s in list(k["/AP"]["/N"].keys()):
+                    if s not in states:
+                        states.append(s)
+                retval[key][NameObject("/_States_")] = ArrayObject(states)
+            if (
+                obj.get(FA.Ff, 0) & FA.FfBits.NoToggleToOff != 0
+                and "/Off" in retval[key]["/_States_"]
+            ):
+                del retval[key]["/_States_"][retval[key]["/_States_"].index("/Off")]
+        # at last for order
+        self._check_kids(field, retval, fileobj, stack)
+
+    def _check_kids(
+        self,
+        tree: Union[TreeObject, DictionaryObject],
+        retval: Any,
+        fileobj: Any,
+        stack: List[PdfObject],
+    ) -> None:
+        if tree in stack:
+            logger_warning(
+                f"{self._get_qualified_field_name(tree)} already parsed", __name__
+            )
+            return
+        stack.append(tree)
+        if PA.KIDS in tree:
+            # recurse down the tree
+            for kid in tree[PA.KIDS]:  # type: ignore
+                kid = kid.get_object()
+                self.get_fields(kid, retval, fileobj, stack)
+
+    def _write_field(self, fileobj: Any, field: Any, field_attributes: Any) -> None:
+        field_attributes_tuple = FA.attributes()
+        field_attributes_tuple = (
+            field_attributes_tuple + CheckboxRadioButtonAttributes.attributes()
+        )
+
+        for attr in field_attributes_tuple:
+            if attr in (
+                FA.Kids,
+                FA.AA,
+            ):
+                continue
+            attr_name = field_attributes[attr]
+            try:
+                if attr == FA.FT:
+                    # Make the field type value more clear
+                    types = {
+                        "/Btn": "Button",
+                        "/Tx": "Text",
+                        "/Ch": "Choice",
+                        "/Sig": "Signature",
+                    }
+                    if field[attr] in types:
+                        fileobj.write(f"{attr_name}: {types[field[attr]]}\n")
+                elif attr == FA.Parent:
+                    # Let's just write the name of the parent
+                    try:
+                        name = field[attr][FA.TM]
+                    except KeyError:
+                        name = field[attr][FA.T]
+                    fileobj.write(f"{attr_name}: {name}\n")
+                else:
+                    fileobj.write(f"{attr_name}: {field[attr]}\n")
+            except KeyError:
+                # Field attribute is N/A or unknown, so don't write anything
+                pass
+
+    def get_form_text_fields(self, full_qualified_name: bool = False) -> Dict[str, Any]:
+        """
+        Retrieve form fields from the document with textual data.
+
+        Args:
+            full_qualified_name: to get full name
+
+        Returns:
+            A dictionary. The key is the name of the form field,
+            the value is the content of the field.
+
+            If the document contains multiple form fields with the same name, the
+            second and following will get the suffix .2, .3, ...
+        """
+
+        def indexed_key(k: str, fields: Dict[Any, Any]) -> str:
+            if k not in fields:
+                return k
+            else:
+                return (
+                    k
+                    + "."
+                    + str(sum([1 for kk in fields if kk.startswith(k + ".")]) + 2)
+                )
+
+        # Retrieve document form fields
+        formfields = self.get_fields()
+        if formfields is None:
+            return {}
+        ff = {}
+        for field, value in formfields.items():
+            if value.get("/FT") == "/Tx":
+                if full_qualified_name:
+                    ff[field] = value.get("/V")
+                else:
+                    ff[indexed_key(cast(str, value["/T"]), ff)] = value.get("/V")
+        return ff
+
+    def get_pages_showing_field(
+        self, field: Union[Field, PdfObject, IndirectObject]
+    ) -> List[PageObject]:
+        """
+        Provides list of pages where the field is called.
+
+        Args:
+            field: Field Object, PdfObject or IndirectObject referencing a Field
+
+        Returns:
+            List of pages:
+                - Empty list:
+                    The field has no widgets attached
+                    (either hidden field or ancestor field).
+                - Single page list:
+                    Page where the widget is present
+                    (most common).
+                - Multi-page list:
+                    Field with multiple kids widgets
+                    (example: radio buttons, field repeated on multiple pages).
+        """
+
+        def _get_inherited(obj: DictionaryObject, key: str) -> Any:
+            if key in obj:
+                return obj[key]
+            elif "/Parent" in obj:
+                return _get_inherited(
+                    cast(DictionaryObject, obj["/Parent"].get_object()), key
+                )
+            else:
+                return None
+
+        try:
+            # to cope with all types
+            field = cast(DictionaryObject, field.indirect_reference.get_object())  # type: ignore
+        except Exception as exc:
+            raise ValueError("field type is invalid") from exc
+        if _get_inherited(field, "/FT") is None:
+            raise ValueError("field is not valid")
+        ret = []
+        if field.get("/Subtype", "") == "/Widget":
+            if "/P" in field:
+                ret = [field["/P"].get_object()]
+            else:
+                ret = [
+                    p
+                    for p in self.pages
+                    if field.indirect_reference in p.get("/Annots", "")
+                ]
+        else:
+            kids = field.get("/Kids", ())
+            for k in kids:
+                k = k.get_object()
+                if (k.get("/Subtype", "") == "/Widget") and ("/T" not in k):
+                    # Kid that is just a widget, not a field:
+                    if "/P" in k:
+                        ret += [k["/P"].get_object()]
+                    else:
+                        ret += [
+                            p
+                            for p in self.pages
+                            if k.indirect_reference in p.get("/Annots", "")
+                        ]
+        return [
+            x
+            if isinstance(x, PageObject)
+            else (self.pages[self._get_page_number_by_indirect(x.indirect_reference)])  # type: ignore
+            for x in ret
+        ]
+
+    @property
+    def open_destination(
+        self,
+    ) -> Union[None, Destination, TextStringObject, ByteStringObject]:
+        """
+        Property to access the opening destination (``/OpenAction`` entry in
+        the PDF catalog). It returns ``None`` if the entry does not exist
+        or is not set.
+
+        Raises:
+            Exception: If a destination is invalid.
+        """
+        if "/OpenAction" not in self.root_object:
+            return None
+        oa: Any = self.root_object["/OpenAction"]
+        if isinstance(oa, bytes):  # pragma: no cover
+            oa = oa.decode()
+        if isinstance(oa, str):
+            return create_string_object(oa)
+        elif isinstance(oa, ArrayObject):
+            try:
+                page, typ = oa[0:2]
+                array = oa[2:]
+                fit = Fit(typ, tuple(array))
+                return Destination("OpenAction", page, fit)
+            except Exception as exc:
+                raise Exception(f"Invalid Destination {oa}: {exc}")
+        else:
+            return None
+
+    @open_destination.setter
+    def open_destination(self, dest: Union[None, str, Destination, PageObject]) -> None:
+        raise NotImplementedError("no setter for open_destination")
+
+    @property
+    def outline(self) -> OutlineType:
+        """
+        Read-only property for the outline present in the document
+        (i.e., a collection of 'outline items' which are also known as
+        'bookmarks').
+        """
+        return self._get_outline()
+
+    def _get_outline(
+        self, node: Optional[DictionaryObject] = None, outline: Optional[Any] = None
+    ) -> OutlineType:
+        if outline is None:
+            outline = []
+            catalog = self.root_object
+
+            # get the outline dictionary and named destinations
+            if CO.OUTLINES in catalog:
+                lines = cast(DictionaryObject, catalog[CO.OUTLINES])
+
+                if isinstance(lines, NullObject):
+                    return outline
+
+                # §12.3.3 Document outline, entries in the outline dictionary
+                if lines is not None and "/First" in lines:
+                    node = cast(DictionaryObject, lines["/First"])
+            self._namedDests = self._get_named_destinations()
+
+        if node is None:
+            return outline
+
+        # see if there are any more outline items
+        while True:
+            outline_obj = self._build_outline_item(node)
+            if outline_obj:
+                outline.append(outline_obj)
+
+            # check for sub-outline
+            if "/First" in node:
+                sub_outline: List[Any] = []
+                self._get_outline(cast(DictionaryObject, node["/First"]), sub_outline)
+                if sub_outline:
+                    outline.append(sub_outline)
+
+            if "/Next" not in node:
+                break
+            node = cast(DictionaryObject, node["/Next"])
+
+        return outline
+
+    @property
+    def threads(self) -> Optional[ArrayObject]:
+        """
+        Read-only property for the list of threads.
+
+        See §12.4.3 from the PDF 1.7 or 2.0 specification.
+
+        It is an array of dictionaries with "/F" (the first bead in the thread)
+        and "/I" (a thread information dictionary containing information about
+        the thread, such as its title, author, and creation date) properties or
+        None if there are no articles.
+
+        Since PDF 2.0 it can also contain an indirect reference to a metadata
+        stream containing information about the thread, such as its title,
+        author, and creation date.
+        """
+        catalog = self.root_object
+        if CO.THREADS in catalog:
+            return cast("ArrayObject", catalog[CO.THREADS])
+        else:
+            return None
+
+    @abstractmethod
+    def _get_page_number_by_indirect(
+        self, indirect_reference: Union[None, int, NullObject, IndirectObject]
+    ) -> Optional[int]:
+        ...  # pragma: no cover
+
+    def get_page_number(self, page: PageObject) -> Optional[int]:
+        """
+        Retrieve page number of a given PageObject.
+
+        Args:
+            page: The page to get page number. Should be
+                an instance of :class:`PageObject<pypdf._page.PageObject>`
+
+        Returns:
+            The page number or None if page is not found
+        """
+        return self._get_page_number_by_indirect(page.indirect_reference)
+
+    def get_destination_page_number(self, destination: Destination) -> Optional[int]:
+        """
+        Retrieve page number of a given Destination object.
+
+        Args:
+            destination: The destination to get page number.
+
+        Returns:
+            The page number or None if page is not found
+        """
+        return self._get_page_number_by_indirect(destination.page)
+
+    def _build_destination(
+        self,
+        title: str,
+        array: Optional[
+            List[
+                Union[NumberObject, IndirectObject, None, NullObject, DictionaryObject]
+            ]
+        ],
+    ) -> Destination:
+        page, typ = None, None
+        # handle outline items with missing or invalid destination
+        if (
+            isinstance(array, (NullObject, str))
+            or (isinstance(array, ArrayObject) and len(array) == 0)
+            or array is None
+        ):
+            page = NullObject()
+            return Destination(title, page, Fit.fit())
+        else:
+            page, typ = array[0:2]  # type: ignore
+            array = array[2:]
+            try:
+                return Destination(title, page, Fit(fit_type=typ, fit_args=array))  # type: ignore
+            except PdfReadError:
+                logger_warning(f"Unknown destination: {title} {array}", __name__)
+                if self.strict:
+                    raise
+                # create a link to first Page
+                tmp = self.pages[0].indirect_reference
+                indirect_reference = NullObject() if tmp is None else tmp
+                return Destination(title, indirect_reference, Fit.fit())  # type: ignore
+
+    def _build_outline_item(self, node: DictionaryObject) -> Optional[Destination]:
+        dest, title, outline_item = None, None, None
+
+        # title required for valid outline
+        # § 12.3.3, entries in an outline item dictionary
+        try:
+            title = cast("str", node["/Title"])
+        except KeyError:
+            if self.strict:
+                raise PdfReadError(f"Outline Entry Missing /Title attribute: {node!r}")
+            title = ""
+
+        if "/A" in node:
+            # Action, PDFv1.7 Section 12.6 (only type GoTo supported)
+            action = cast(DictionaryObject, node["/A"])
+            action_type = cast(NameObject, action[GoToActionArguments.S])
+            if action_type == "/GoTo":
+                dest = action[GoToActionArguments.D]
+        elif "/Dest" in node:
+            # Destination, PDFv1.7 Section 12.3.2
+            dest = node["/Dest"]
+            # if array was referenced in another object, will be a dict w/ key "/D"
+            if isinstance(dest, DictionaryObject) and "/D" in dest:
+                dest = dest["/D"]
+
+        if isinstance(dest, ArrayObject):
+            outline_item = self._build_destination(title, dest)
+        elif isinstance(dest, str):
+            # named destination, addresses NameObject Issue #193
+            # TODO : keep named destination instead of replacing it ?
+            try:
+                outline_item = self._build_destination(
+                    title, self._namedDests[dest].dest_array
+                )
+            except KeyError:
+                # named destination not found in Name Dict
+                outline_item = self._build_destination(title, None)
+        elif dest is None:
+            # outline item not required to have destination or action
+            # PDFv1.7 Table 153
+            outline_item = self._build_destination(title, dest)
+        else:
+            if self.strict:
+                raise PdfReadError(f"Unexpected destination {dest!r}")
+            else:
+                logger_warning(
+                    f"Removed unexpected destination {dest!r} from destination",
+                    __name__,
+                )
+            outline_item = self._build_destination(title, None)
+
+        # if outline item created, add color, format, and child count if present
+        if outline_item:
+            if "/C" in node:
+                # Color of outline item font in (R, G, B) with values ranging 0.0-1.0
+                outline_item[NameObject("/C")] = ArrayObject(FloatObject(c) for c in node["/C"])  # type: ignore
+            if "/F" in node:
+                # specifies style characteristics bold and/or italic
+                # with 1=italic, 2=bold, 3=both
+                outline_item[NameObject("/F")] = node["/F"]
+            if "/Count" in node:
+                # absolute value = num. visible children
+                # with positive = open/unfolded, negative = closed/folded
+                outline_item[NameObject("/Count")] = node["/Count"]
+            #  if count is 0 we will consider it as open ( in order to have always an is_open to simplify
+            outline_item[NameObject("/%is_open%")] = BooleanObject(
+                node.get("/Count", 0) >= 0
+            )
+        outline_item.node = node
+        try:
+            outline_item.indirect_reference = node.indirect_reference
+        except AttributeError:
+            pass
+        return outline_item
+
+    @property
+    def pages(self) -> List[PageObject]:
+        """
+        Property that emulates a list of :class:`PageObject<pypdf._page.PageObject>`.
+        This property allows to get a page or a range of pages.
+
+        Note:
+            For PdfWriter only: Provides the capability to remove a page/range of
+            page from the list (using the del operator). Remember: Only the page
+            entry is removed, as the objects beneath can be used elsewhere. A
+            solution to completely remove them - if they are not used anywhere - is
+            to write to a buffer/temporary file and then load it into a new
+            PdfWriter.
+
+        """
+        return _VirtualList(self.get_num_pages, self.get_page)  # type: ignore
+
+    @property
+    def page_labels(self) -> List[str]:
+        """
+        A list of labels for the pages in this document.
+
+        This property is read-only. The labels are in the order that the pages
+        appear in the document.
+        """
+        return [page_index2page_label(self, i) for i in range(len(self.pages))]
+
+    @property
+    def page_layout(self) -> Optional[str]:
+        """
+        Get the page layout currently being used.
+
+        .. list-table:: Valid ``layout`` values
+           :widths: 50 200
+
+           * - /NoLayout
+             - Layout explicitly not specified
+           * - /SinglePage
+             - Show one page at a time
+           * - /OneColumn
+             - Show one column at a time
+           * - /TwoColumnLeft
+             - Show pages in two columns, odd-numbered pages on the left
+           * - /TwoColumnRight
+             - Show pages in two columns, odd-numbered pages on the right
+           * - /TwoPageLeft
+             - Show two pages at a time, odd-numbered pages on the left
+           * - /TwoPageRight
+             - Show two pages at a time, odd-numbered pages on the right
+        """
+        try:
+            return cast(NameObject, self.root_object[CD.PAGE_LAYOUT])
+        except KeyError:
+            return None
+
+    @property
+    def page_mode(self) -> Optional[PagemodeType]:
+        """
+        Get the page mode currently being used.
+
+        .. list-table:: Valid ``mode`` values
+           :widths: 50 200
+
+           * - /UseNone
+             - Do not show outline or thumbnails panels
+           * - /UseOutlines
+             - Show outline (aka bookmarks) panel
+           * - /UseThumbs
+             - Show page thumbnails panel
+           * - /FullScreen
+             - Fullscreen view
+           * - /UseOC
+             - Show Optional Content Group (OCG) panel
+           * - /UseAttachments
+             - Show attachments panel
+        """
+        try:
+            return self.root_object["/PageMode"]  # type: ignore
+        except KeyError:
+            return None
+
+    def _flatten(
+        self,
+        pages: Union[None, DictionaryObject, PageObject] = None,
+        inherit: Optional[Dict[str, Any]] = None,
+        indirect_reference: Optional[IndirectObject] = None,
+    ) -> None:
+        inheritable_page_attributes = (
+            NameObject(PG.RESOURCES),
+            NameObject(PG.MEDIABOX),
+            NameObject(PG.CROPBOX),
+            NameObject(PG.ROTATE),
+        )
+        if inherit is None:
+            inherit = {}
+        if pages is None:
+            # Fix issue 327: set flattened_pages attribute only for
+            # decrypted file
+            catalog = self.root_object
+            pages = catalog["/Pages"].get_object()  # type: ignore
+            assert isinstance(pages, DictionaryObject)
+            self.flattened_pages = []
+
+        if PA.TYPE in pages:
+            t = cast(str, pages[PA.TYPE])
+        # if pdf has no type, considered as a page if /Kids is missing
+        elif PA.KIDS not in pages:
+            t = "/Page"
+        else:
+            t = "/Pages"
+
+        if t == "/Pages":
+            for attr in inheritable_page_attributes:
+                if attr in pages:
+                    inherit[attr] = pages[attr]
+            for page in cast(ArrayObject, pages[PA.KIDS]):
+                addt = {}
+                if isinstance(page, IndirectObject):
+                    addt["indirect_reference"] = page
+                obj = page.get_object()
+                if obj:
+                    # damaged file may have invalid child in /Pages
+                    self._flatten(obj, inherit, **addt)
+        elif t == "/Page":
+            for attr_in, value in list(inherit.items()):
+                # if the page has it's own value, it does not inherit the
+                # parent's value:
+                if attr_in not in pages:
+                    pages[attr_in] = value
+            page_obj = PageObject(self, indirect_reference)
+            page_obj.update(pages)
+
+            # TODO: Could flattened_pages be None at this point?
+            self.flattened_pages.append(page_obj)  # type: ignore
+
+    def remove_page(
+        self,
+        page: Union[int, PageObject, IndirectObject],
+        clean: bool = False,
+    ) -> None:
+        """
+        Remove page from pages list.
+
+        Args:
+            page:
+                * :class:`int`: Page number to be removed.
+                * :class:`~pypdf._page.PageObject`: page to be removed. If the page appears many times
+                  only the first one will be removed.
+                * :class:`~pypdf.generic.IndirectObject`: Reference to page to be removed.
+
+            clean: replace PageObject with NullObject to prevent annotations
+                or destinations to reference a detached page.
+        """
+        if self.flattened_pages is None:
+            self._flatten()
+        assert self.flattened_pages is not None
+        if isinstance(page, IndirectObject):
+            p = page.get_object()
+            if not isinstance(p, PageObject):
+                logger_warning("IndirectObject is not referencing a page", __name__)
+                return
+            page = p
+
+        if not isinstance(page, int):
+            try:
+                page = self.flattened_pages.index(page)
+            except ValueError:
+                logger_warning("Cannot find page in pages", __name__)
+                return
+        if not (0 <= page < len(self.flattened_pages)):
+            logger_warning("Page number is out of range", __name__)
+            return
+
+        ind = self.pages[page].indirect_reference
+        del self.pages[page]
+        if clean and ind is not None:
+            self._replace_object(ind, NullObject())
+
+    def _get_indirect_object(self, num: int, gen: int) -> Optional[PdfObject]:
+        """
+        Used to ease development.
+
+        This is equivalent to generic.IndirectObject(num,gen,self).get_object()
+
+        Args:
+            num: The object number of the indirect object.
+            gen: The generation number of the indirect object.
+
+        Returns:
+            A PdfObject
+        """
+        return IndirectObject(num, gen, self).get_object()
+
+    def decode_permissions(
+        self, permissions_code: int
+    ) -> Dict[str, bool]:  # pragma: no cover
+        """Take the permissions as an integer, return the allowed access."""
+        deprecate_with_replacement(
+            old_name="decode_permissions",
+            new_name="user_access_permissions",
+            removed_in="5.0.0",
+        )
+
+        permissions_mapping = {
+            "print": UserAccessPermissions.PRINT,
+            "modify": UserAccessPermissions.MODIFY,
+            "copy": UserAccessPermissions.EXTRACT,
+            "annotations": UserAccessPermissions.ADD_OR_MODIFY,
+            "forms": UserAccessPermissions.FILL_FORM_FIELDS,
+            # Do not fix typo, as part of official, but deprecated API.
+            "accessability": UserAccessPermissions.EXTRACT_TEXT_AND_GRAPHICS,
+            "assemble": UserAccessPermissions.ASSEMBLE_DOC,
+            "print_high_quality": UserAccessPermissions.PRINT_TO_REPRESENTATION,
+        }
+
+        return {
+            key: permissions_code & flag != 0
+            for key, flag in permissions_mapping.items()
+        }
+
+    @property
+    def user_access_permissions(self) -> Optional[UserAccessPermissions]:
+        """Get the user access permissions for encrypted documents. Returns None if not encrypted."""
+        if self._encryption is None:
+            return None
+        return UserAccessPermissions(self._encryption.P)
+
+    @property
+    @abstractmethod
+    def is_encrypted(self) -> bool:
+        """
+        Read-only boolean property showing whether this PDF file is encrypted.
+
+        Note that this property, if true, will remain true even after the
+        :meth:`decrypt()<pypdf.PdfReader.decrypt>` method is called.
+        """
+        ...  # pragma: no cover
+
+    @property
+    def xfa(self) -> Optional[Dict[str, Any]]:
+        tree: Optional[TreeObject] = None
+        retval: Dict[str, Any] = {}
+        catalog = self.root_object
+
+        if "/AcroForm" not in catalog or not catalog["/AcroForm"]:
+            return None
+
+        tree = cast(TreeObject, catalog["/AcroForm"])
+
+        if "/XFA" in tree:
+            fields = cast(ArrayObject, tree["/XFA"])
+            i = iter(fields)
+            for f in i:
+                tag = f
+                f = next(i)
+                if isinstance(f, IndirectObject):
+                    field = cast(Optional[EncodedStreamObject], f.get_object())
+                    if field:
+                        es = zlib.decompress(b_(field._data))
+                        retval[tag] = es
+        return retval
+
+    @property
+    def attachments(self) -> Mapping[str, List[bytes]]:
+        return LazyDict(
+            {
+                name: (self._get_attachment_list, name)
+                for name in self._list_attachments()
+            }
+        )
+
+    def _list_attachments(self) -> List[str]:
+        """
+        Retrieves the list of filenames of file attachments.
+
+        Returns:
+            list of filenames
+        """
+        catalog = self.root_object
+        # From the catalog get the embedded file names
+        try:
+            filenames = cast(
+                ArrayObject,
+                cast(
+                    DictionaryObject,
+                    cast(DictionaryObject, catalog["/Names"])["/EmbeddedFiles"],
+                )["/Names"],
+            )
+        except KeyError:
+            return []
+        attachments_names = [f for f in filenames if isinstance(f, str)]
+        return attachments_names
+
+    def _get_attachment_list(self, name: str) -> List[bytes]:
+        out = self._get_attachments(name)[name]
+        if isinstance(out, list):
+            return out
+        return [out]
+
+    def _get_attachments(
+        self, filename: Optional[str] = None
+    ) -> Dict[str, Union[bytes, List[bytes]]]:
+        """
+        Retrieves all or selected file attachments of the PDF as a dictionary of file names
+        and the file data as a bytestring.
+
+        Args:
+            filename: If filename is None, then a dictionary of all attachments
+                will be returned, where the key is the filename and the value
+                is the content. Otherwise, a dictionary with just a single key
+                - the filename - and its content will be returned.
+
+        Returns:
+            dictionary of filename -> Union[bytestring or List[ByteString]]
+            If the filename exists multiple times a list of the different versions will be provided.
+        """
+        catalog = self.root_object
+        # From the catalog get the embedded file names
+        try:
+            filenames = cast(
+                ArrayObject,
+                cast(
+                    DictionaryObject,
+                    cast(DictionaryObject, catalog["/Names"])["/EmbeddedFiles"],
+                )["/Names"],
+            )
+        except KeyError:
+            return {}
+        attachments: Dict[str, Union[bytes, List[bytes]]] = {}
+        # Loop through attachments
+        for i in range(len(filenames)):
+            f = filenames[i]
+            if isinstance(f, str):
+                if filename is not None and f != filename:
+                    continue
+                name = f
+                f_dict = filenames[i + 1].get_object()
+                f_data = f_dict["/EF"]["/F"].get_data()
+                if name in attachments:
+                    if not isinstance(attachments[name], list):
+                        attachments[name] = [attachments[name]]  # type:ignore
+                    attachments[name].append(f_data)  # type:ignore
+                else:
+                    attachments[name] = f_data
+        return attachments
+
+
+class LazyDict(Mapping[Any, Any]):
+    def __init__(self, *args: Any, **kw: Any) -> None:
+        self._raw_dict = dict(*args, **kw)
+
+    def __getitem__(self, key: str) -> Any:
+        func, arg = self._raw_dict.__getitem__(key)
+        return func(arg)
+
+    def __iter__(self) -> Iterator[Any]:
+        return iter(self._raw_dict)
+
+    def __len__(self) -> int:
+        return len(self._raw_dict)
+
+    def __str__(self) -> str:
+        return f"LazyDict(keys={list(self.keys())})"
diff --git a/.venv/lib/python3.12/site-packages/pypdf/_encryption.py b/.venv/lib/python3.12/site-packages/pypdf/_encryption.py
new file mode 100644
index 00000000..5ddd8d0e
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/_encryption.py
@@ -0,0 +1,1168 @@
+# Copyright (c) 2022, exiledkingcc
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# * The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+import hashlib
+import secrets
+import struct
+from enum import Enum, IntEnum
+from typing import Any, Dict, Optional, Tuple, Union, cast
+
+from pypdf._crypt_providers import (
+    CryptAES,
+    CryptBase,
+    CryptIdentity,
+    CryptRC4,
+    aes_cbc_decrypt,
+    aes_cbc_encrypt,
+    aes_ecb_decrypt,
+    aes_ecb_encrypt,
+    rc4_decrypt,
+    rc4_encrypt,
+)
+
+from ._utils import b_, logger_warning
+from .generic import (
+    ArrayObject,
+    ByteStringObject,
+    DictionaryObject,
+    NameObject,
+    NumberObject,
+    PdfObject,
+    StreamObject,
+    TextStringObject,
+    create_string_object,
+)
+
+
+class CryptFilter:
+    def __init__(
+        self,
+        stm_crypt: CryptBase,
+        str_crypt: CryptBase,
+        ef_crypt: CryptBase,
+    ) -> None:
+        self.stm_crypt = stm_crypt
+        self.str_crypt = str_crypt
+        self.ef_crypt = ef_crypt
+
+    def encrypt_object(self, obj: PdfObject) -> PdfObject:
+        if isinstance(obj, ByteStringObject):
+            data = self.str_crypt.encrypt(obj.original_bytes)
+            obj = ByteStringObject(data)
+        if isinstance(obj, TextStringObject):
+            data = self.str_crypt.encrypt(obj.get_encoded_bytes())
+            obj = ByteStringObject(data)
+        elif isinstance(obj, StreamObject):
+            obj2 = StreamObject()
+            obj2.update(obj)
+            obj2.set_data(self.stm_crypt.encrypt(b_(obj._data)))
+            for key, value in obj.items():  # Dont forget the Stream dict.
+                obj2[key] = self.encrypt_object(value)
+            obj = obj2
+        elif isinstance(obj, DictionaryObject):
+            obj2 = DictionaryObject()  # type: ignore
+            for key, value in obj.items():
+                obj2[key] = self.encrypt_object(value)
+            obj = obj2
+        elif isinstance(obj, ArrayObject):
+            obj = ArrayObject(self.encrypt_object(x) for x in obj)
+        return obj
+
+    def decrypt_object(self, obj: PdfObject) -> PdfObject:
+        if isinstance(obj, (ByteStringObject, TextStringObject)):
+            data = self.str_crypt.decrypt(obj.original_bytes)
+            obj = create_string_object(data)
+        elif isinstance(obj, StreamObject):
+            obj._data = self.stm_crypt.decrypt(b_(obj._data))
+            for key, value in obj.items():  # Dont forget the Stream dict.
+                obj[key] = self.decrypt_object(value)
+        elif isinstance(obj, DictionaryObject):
+            for key, value in obj.items():
+                obj[key] = self.decrypt_object(value)
+        elif isinstance(obj, ArrayObject):
+            for i in range(len(obj)):
+                obj[i] = self.decrypt_object(obj[i])
+        return obj
+
+
+_PADDING = (
+    b"\x28\xbf\x4e\x5e\x4e\x75\x8a\x41\x64\x00\x4e\x56\xff\xfa\x01\x08"
+    b"\x2e\x2e\x00\xb6\xd0\x68\x3e\x80\x2f\x0c\xa9\xfe\x64\x53\x69\x7a"
+)
+
+
+def _padding(data: bytes) -> bytes:
+    return (data + _PADDING)[:32]
+
+
+class AlgV4:
+    @staticmethod
+    def compute_key(
+        password: bytes,
+        rev: int,
+        key_size: int,
+        o_entry: bytes,
+        P: int,
+        id1_entry: bytes,
+        metadata_encrypted: bool,
+    ) -> bytes:
+        """
+        Algorithm 2: Computing an encryption key.
+
+        a) Pad or truncate the password string to exactly 32 bytes. If the
+           password string is more than 32 bytes long,
+           use only its first 32 bytes; if it is less than 32 bytes long, pad it
+           by appending the required number of
+           additional bytes from the beginning of the following padding string:
+                < 28 BF 4E 5E 4E 75 8A 41 64 00 4E 56 FF FA 01 08
+                2E 2E 00 B6 D0 68 3E 80 2F 0C A9 FE 64 53 69 7A >
+           That is, if the password string is n bytes long, append
+           the first 32 - n bytes of the padding string to the end
+           of the password string. If the password string is empty
+           (zero-length), meaning there is no user password,
+           substitute the entire padding string in its place.
+
+        b) Initialize the MD5 hash function and pass the result of step (a)
+           as input to this function.
+        c) Pass the value of the encryption dictionary’s O entry to the
+           MD5 hash function. ("Algorithm 3: Computing
+           the encryption dictionary’s O (owner password) value" shows how the
+           O value is computed.)
+        d) Convert the integer value of the P entry to a 32-bit unsigned binary
+           number and pass these bytes to the
+           MD5 hash function, low-order byte first.
+        e) Pass the first element of the file’s file identifier array (the value
+           of the ID entry in the document’s trailer
+           dictionary; see Table 15) to the MD5 hash function.
+        f) (Security handlers of revision 4 or greater) If document metadata is
+           not being encrypted, pass 4 bytes with
+           the value 0xFFFFFFFF to the MD5 hash function.
+        g) Finish the hash.
+        h) (Security handlers of revision 3 or greater) Do the following
+           50 times: Take the output from the previous
+           MD5 hash and pass the first n bytes of the output as input into a new
+           MD5 hash, where n is the number of
+           bytes of the encryption key as defined by the value of the encryption
+           dictionary’s Length entry.
+        i) Set the encryption key to the first n bytes of the output from the
+           final MD5 hash, where n shall always be 5
+           for security handlers of revision 2 but, for security handlers of
+           revision 3 or greater, shall depend on the
+           value of the encryption dictionary’s Length entry.
+
+        Args:
+            password: The encryption secret as a bytes-string
+            rev: The encryption revision (see PDF standard)
+            key_size: The size of the key in bytes
+            o_entry: The owner entry
+            P: A set of flags specifying which operations shall be permitted
+                when the document is opened with user access. If bit 2 is set to 1,
+                all other bits are ignored and all operations are permitted.
+                If bit 2 is set to 0, permission for operations are based on the
+                values of the remaining flags defined in Table 24.
+            id1_entry:
+            metadata_encrypted: A boolean indicating if the metadata is encrypted.
+
+        Returns:
+            The u_hash digest of length key_size
+        """
+        a = _padding(password)
+        u_hash = hashlib.md5(a)
+        u_hash.update(o_entry)
+        u_hash.update(struct.pack("<I", P))
+        u_hash.update(id1_entry)
+        if rev >= 4 and not metadata_encrypted:
+            u_hash.update(b"\xff\xff\xff\xff")
+        u_hash_digest = u_hash.digest()
+        length = key_size // 8
+        if rev >= 3:
+            for _ in range(50):
+                u_hash_digest = hashlib.md5(u_hash_digest[:length]).digest()
+        return u_hash_digest[:length]
+
+    @staticmethod
+    def compute_O_value_key(owner_password: bytes, rev: int, key_size: int) -> bytes:
+        """
+        Algorithm 3: Computing the encryption dictionary’s O (owner password) value.
+
+        a) Pad or truncate the owner password string as described in step (a)
+           of "Algorithm 2: Computing an encryption key".
+           If there is no owner password, use the user password instead.
+        b) Initialize the MD5 hash function and pass the result of step (a) as
+           input to this function.
+        c) (Security handlers of revision 3 or greater) Do the following 50 times:
+           Take the output from the previous
+           MD5 hash and pass it as input into a new MD5 hash.
+        d) Create an RC4 encryption key using the first n bytes of the output
+           from the final MD5 hash, where n shall
+           always be 5 for security handlers of revision 2 but, for security
+           handlers of revision 3 or greater, shall
+           depend on the value of the encryption dictionary’s Length entry.
+        e) Pad or truncate the user password string as described in step (a) of
+           "Algorithm 2: Computing an encryption key".
+        f) Encrypt the result of step (e), using an RC4 encryption function with
+           the encryption key obtained in step (d).
+        g) (Security handlers of revision 3 or greater) Do the following 19 times:
+           Take the output from the previous
+           invocation of the RC4 function and pass it as input to a new
+           invocation of the function; use an encryption
+           key generated by taking each byte of the encryption key obtained in
+           step (d) and performing an XOR
+           (exclusive or) operation between that byte and the single-byte value
+           of the iteration counter (from 1 to 19).
+        h) Store the output from the final invocation of the RC4 function as
+           the value of the O entry in the encryption dictionary.
+
+        Args:
+            owner_password:
+            rev: The encryption revision (see PDF standard)
+            key_size: The size of the key in bytes
+
+        Returns:
+            The RC4 key
+        """
+        a = _padding(owner_password)
+        o_hash_digest = hashlib.md5(a).digest()
+
+        if rev >= 3:
+            for _ in range(50):
+                o_hash_digest = hashlib.md5(o_hash_digest).digest()
+
+        rc4_key = o_hash_digest[: key_size // 8]
+        return rc4_key
+
+    @staticmethod
+    def compute_O_value(rc4_key: bytes, user_password: bytes, rev: int) -> bytes:
+        """
+        See :func:`compute_O_value_key`.
+
+        Args:
+            rc4_key:
+            user_password:
+            rev: The encryption revision (see PDF standard)
+
+        Returns:
+            The RC4 encrypted
+        """
+        a = _padding(user_password)
+        rc4_enc = rc4_encrypt(rc4_key, a)
+        if rev >= 3:
+            for i in range(1, 20):
+                key = bytes(bytearray(x ^ i for x in rc4_key))
+                rc4_enc = rc4_encrypt(key, rc4_enc)
+        return rc4_enc
+
+    @staticmethod
+    def compute_U_value(key: bytes, rev: int, id1_entry: bytes) -> bytes:
+        """
+        Algorithm 4: Computing the encryption dictionary’s U (user password) value.
+
+        (Security handlers of revision 2)
+
+        a) Create an encryption key based on the user password string, as
+           described in "Algorithm 2: Computing an encryption key".
+        b) Encrypt the 32-byte padding string shown in step (a) of
+           "Algorithm 2: Computing an encryption key", using an RC4 encryption
+           function with the encryption key from the preceding step.
+        c) Store the result of step (b) as the value of the U entry in the
+           encryption dictionary.
+
+        Args:
+            key:
+            rev: The encryption revision (see PDF standard)
+            id1_entry:
+
+        Returns:
+            The value
+        """
+        if rev <= 2:
+            value = rc4_encrypt(key, _PADDING)
+            return value
+
+        """
+        Algorithm 5: Computing the encryption dictionary’s U (user password) value.
+
+        (Security handlers of revision 3 or greater)
+
+        a) Create an encryption key based on the user password string, as
+           described in "Algorithm 2: Computing an encryption key".
+        b) Initialize the MD5 hash function and pass the 32-byte padding string
+           shown in step (a) of "Algorithm 2:
+           Computing an encryption key" as input to this function.
+        c) Pass the first element of the file’s file identifier array (the value
+           of the ID entry in the document’s trailer
+           dictionary; see Table 15) to the hash function and finish the hash.
+        d) Encrypt the 16-byte result of the hash, using an RC4 encryption
+           function with the encryption key from step (a).
+        e) Do the following 19 times: Take the output from the previous
+           invocation of the RC4 function and pass it as input to a new
+           invocation of the function; use an encryption key generated by
+           taking each byte of the original encryption key obtained in
+           step (a) and performing an XOR (exclusive or) operation between that
+           byte and the single-byte value of the iteration counter (from 1 to 19).
+        f) Append 16 bytes of arbitrary padding to the output from the final
+           invocation of the RC4 function and store the 32-byte result as the
+           value of the U entry in the encryption dictionary.
+        """
+        u_hash = hashlib.md5(_PADDING)
+        u_hash.update(id1_entry)
+        rc4_enc = rc4_encrypt(key, u_hash.digest())
+        for i in range(1, 20):
+            rc4_key = bytes(bytearray(x ^ i for x in key))
+            rc4_enc = rc4_encrypt(rc4_key, rc4_enc)
+        return _padding(rc4_enc)
+
+    @staticmethod
+    def verify_user_password(
+        user_password: bytes,
+        rev: int,
+        key_size: int,
+        o_entry: bytes,
+        u_entry: bytes,
+        P: int,
+        id1_entry: bytes,
+        metadata_encrypted: bool,
+    ) -> bytes:
+        """
+        Algorithm 6: Authenticating the user password.
+
+        a) Perform all but the last step of "Algorithm 4: Computing the
+           encryption dictionary’s U (user password) value (Security handlers of
+           revision 2)" or "Algorithm 5: Computing the encryption dictionary’s U
+           (user password) value (Security handlers of revision 3 or greater)"
+           using the supplied password string.
+        b) If the result of step (a) is equal to the value of the encryption
+           dictionary’s U entry (comparing on the first 16 bytes in the case of
+           security handlers of revision 3 or greater), the password supplied is
+           the correct user password. The key obtained in step (a) (that is, in
+           the first step of "Algorithm 4: Computing the encryption
+           dictionary’s U (user password) value
+           (Security handlers of revision 2)" or
+           "Algorithm 5: Computing the encryption dictionary’s U (user password)
+           value (Security handlers of revision 3 or greater)") shall be used
+           to decrypt the document.
+
+        Args:
+            user_password: The user password as a bytes stream
+            rev: The encryption revision (see PDF standard)
+            key_size: The size of the key in bytes
+            o_entry: The owner entry
+            u_entry: The user entry
+            P: A set of flags specifying which operations shall be permitted
+                when the document is opened with user access. If bit 2 is set to 1,
+                all other bits are ignored and all operations are permitted.
+                If bit 2 is set to 0, permission for operations are based on the
+                values of the remaining flags defined in Table 24.
+            id1_entry:
+            metadata_encrypted: A boolean indicating if the metadata is encrypted.
+
+        Returns:
+            The key
+        """
+        key = AlgV4.compute_key(
+            user_password, rev, key_size, o_entry, P, id1_entry, metadata_encrypted
+        )
+        u_value = AlgV4.compute_U_value(key, rev, id1_entry)
+        if rev >= 3:
+            u_value = u_value[:16]
+            u_entry = u_entry[:16]
+        if u_value != u_entry:
+            key = b""
+        return key
+
+    @staticmethod
+    def verify_owner_password(
+        owner_password: bytes,
+        rev: int,
+        key_size: int,
+        o_entry: bytes,
+        u_entry: bytes,
+        P: int,
+        id1_entry: bytes,
+        metadata_encrypted: bool,
+    ) -> bytes:
+        """
+        Algorithm 7: Authenticating the owner password.
+
+        a) Compute an encryption key from the supplied password string, as
+           described in steps (a) to (d) of
+           "Algorithm 3: Computing the encryption dictionary’s O (owner password)
+           value".
+        b) (Security handlers of revision 2 only) Decrypt the value of the
+           encryption dictionary’s O entry, using an RC4
+           encryption function with the encryption key computed in step (a).
+           (Security handlers of revision 3 or greater) Do the following 20 times:
+           Decrypt the value of the encryption dictionary’s O entry (first iteration)
+           or the output from the previous iteration (all subsequent iterations),
+           using an RC4 encryption function with a different encryption key at
+           each iteration. The key shall be generated by taking the original key
+           (obtained in step (a)) and performing an XOR (exclusive or) operation
+           between each byte of the key and the single-byte value of the
+           iteration counter (from 19 to 0).
+        c) The result of step (b) purports to be the user password.
+           Authenticate this user password using
+           "Algorithm 6: Authenticating the user password".
+           If it is correct, the password supplied is the correct owner password.
+
+        Args:
+            owner_password:
+            rev: The encryption revision (see PDF standard)
+            key_size: The size of the key in bytes
+            o_entry: The owner entry
+            u_entry: The user entry
+            P: A set of flags specifying which operations shall be permitted
+                when the document is opened with user access. If bit 2 is set to 1,
+                all other bits are ignored and all operations are permitted.
+                If bit 2 is set to 0, permission for operations are based on the
+                values of the remaining flags defined in Table 24.
+            id1_entry:
+            metadata_encrypted: A boolean indicating if the metadata is encrypted.
+
+        Returns:
+            bytes
+        """
+        rc4_key = AlgV4.compute_O_value_key(owner_password, rev, key_size)
+
+        if rev <= 2:
+            user_password = rc4_decrypt(rc4_key, o_entry)
+        else:
+            user_password = o_entry
+            for i in range(19, -1, -1):
+                key = bytes(bytearray(x ^ i for x in rc4_key))
+                user_password = rc4_decrypt(key, user_password)
+        return AlgV4.verify_user_password(
+            user_password,
+            rev,
+            key_size,
+            o_entry,
+            u_entry,
+            P,
+            id1_entry,
+            metadata_encrypted,
+        )
+
+
+class AlgV5:
+    @staticmethod
+    def verify_owner_password(
+        R: int, password: bytes, o_value: bytes, oe_value: bytes, u_value: bytes
+    ) -> bytes:
+        """
+        Algorithm 3.2a Computing an encryption key.
+
+        To understand the algorithm below, it is necessary to treat the O and U
+        strings in the Encrypt dictionary as made up of three sections.
+        The first 32 bytes are a hash value (explained below). The next 8 bytes
+        are called the Validation Salt. The final 8 bytes are called the Key Salt.
+
+        1. The password string is generated from Unicode input by processing the
+           input string with the SASLprep (IETF RFC 4013) profile of
+           stringprep (IETF RFC 3454), and then converting to a UTF-8
+           representation.
+        2. Truncate the UTF-8 representation to 127 bytes if it is longer than
+           127 bytes.
+        3. Test the password against the owner key by computing the SHA-256 hash
+           of the UTF-8 password concatenated with the 8 bytes of owner
+           Validation Salt, concatenated with the 48-byte U string. If the
+           32-byte result matches the first 32 bytes of the O string, this is
+           the owner password.
+           Compute an intermediate owner key by computing the SHA-256 hash of
+           the UTF-8 password concatenated with the 8 bytes of owner Key Salt,
+           concatenated with the 48-byte U string. The 32-byte result is the
+           key used to decrypt the 32-byte OE string using AES-256 in CBC mode
+           with no padding and an initialization vector of zero.
+           The 32-byte result is the file encryption key.
+        4. Test the password against the user key by computing the SHA-256 hash
+           of the UTF-8 password concatenated with the 8 bytes of user
+           Validation Salt. If the 32 byte result matches the first 32 bytes of
+           the U string, this is the user password.
+           Compute an intermediate user key by computing the SHA-256 hash of the
+           UTF-8 password concatenated with the 8 bytes of user Key Salt.
+           The 32-byte result is the key used to decrypt the 32-byte
+           UE string using AES-256 in CBC mode with no padding and an
+           initialization vector of zero. The 32-byte result is the file
+           encryption key.
+        5. Decrypt the 16-byte Perms string using AES-256 in ECB mode with an
+           initialization vector of zero and the file encryption key as the key.
+           Verify that bytes 9-11 of the result are the characters ‘a’, ‘d’, ‘b’.
+           Bytes 0-3 of the decrypted Perms entry, treated as a little-endian
+           integer, are the user permissions.
+           They should match the value in the P key.
+
+        Args:
+            R: A number specifying which revision of the standard security
+                handler shall be used to interpret this dictionary
+            password: The owner password
+            o_value: A 32-byte string, based on both the owner and user passwords,
+                that shall be used in computing the encryption key and in
+                determining whether a valid owner password was entered
+            oe_value:
+            u_value: A 32-byte string, based on the user password, that shall be
+                used in determining whether to prompt the user for a password and,
+                if so, whether a valid user or owner password was entered.
+
+        Returns:
+            The key
+        """
+        password = password[:127]
+        if (
+            AlgV5.calculate_hash(R, password, o_value[32:40], u_value[:48])
+            != o_value[:32]
+        ):
+            return b""
+        iv = bytes(0 for _ in range(16))
+        tmp_key = AlgV5.calculate_hash(R, password, o_value[40:48], u_value[:48])
+        key = aes_cbc_decrypt(tmp_key, iv, oe_value)
+        return key
+
+    @staticmethod
+    def verify_user_password(
+        R: int, password: bytes, u_value: bytes, ue_value: bytes
+    ) -> bytes:
+        """
+        See :func:`verify_owner_password`.
+
+        Args:
+            R: A number specifying which revision of the standard security
+                handler shall be used to interpret this dictionary
+            password: The user password
+            u_value: A 32-byte string, based on the user password, that shall be
+                used in determining whether to prompt the user for a password
+                and, if so, whether a valid user or owner password was entered.
+            ue_value:
+
+        Returns:
+            bytes
+        """
+        password = password[:127]
+        if AlgV5.calculate_hash(R, password, u_value[32:40], b"") != u_value[:32]:
+            return b""
+        iv = bytes(0 for _ in range(16))
+        tmp_key = AlgV5.calculate_hash(R, password, u_value[40:48], b"")
+        return aes_cbc_decrypt(tmp_key, iv, ue_value)
+
+    @staticmethod
+    def calculate_hash(R: int, password: bytes, salt: bytes, udata: bytes) -> bytes:
+        # from https://github.com/qpdf/qpdf/blob/main/libqpdf/QPDF_encryption.cc
+        k = hashlib.sha256(password + salt + udata).digest()
+        if R < 6:
+            return k
+        count = 0
+        while True:
+            count += 1
+            k1 = password + k + udata
+            e = aes_cbc_encrypt(k[:16], k[16:32], k1 * 64)
+            hash_fn = (
+                hashlib.sha256,
+                hashlib.sha384,
+                hashlib.sha512,
+            )[sum(e[:16]) % 3]
+            k = hash_fn(e).digest()
+            if count >= 64 and e[-1] <= count - 32:
+                break
+        return k[:32]
+
+    @staticmethod
+    def verify_perms(
+        key: bytes, perms: bytes, p: int, metadata_encrypted: bool
+    ) -> bool:
+        """
+        See :func:`verify_owner_password` and :func:`compute_perms_value`.
+
+        Args:
+            key: The owner password
+            perms:
+            p: A set of flags specifying which operations shall be permitted
+                when the document is opened with user access.
+                If bit 2 is set to 1, all other bits are ignored and all
+                operations are permitted.
+                If bit 2 is set to 0, permission for operations are based on
+                the values of the remaining flags defined in Table 24.
+            metadata_encrypted:
+
+        Returns:
+            A boolean
+        """
+        b8 = b"T" if metadata_encrypted else b"F"
+        p1 = struct.pack("<I", p) + b"\xff\xff\xff\xff" + b8 + b"adb"
+        p2 = aes_ecb_decrypt(key, perms)
+        return p1 == p2[:12]
+
+    @staticmethod
+    def generate_values(
+        R: int,
+        user_password: bytes,
+        owner_password: bytes,
+        key: bytes,
+        p: int,
+        metadata_encrypted: bool,
+    ) -> Dict[Any, Any]:
+        user_password = user_password[:127]
+        owner_password = owner_password[:127]
+        u_value, ue_value = AlgV5.compute_U_value(R, user_password, key)
+        o_value, oe_value = AlgV5.compute_O_value(R, owner_password, key, u_value)
+        perms = AlgV5.compute_Perms_value(key, p, metadata_encrypted)
+        return {
+            "/U": u_value,
+            "/UE": ue_value,
+            "/O": o_value,
+            "/OE": oe_value,
+            "/Perms": perms,
+        }
+
+    @staticmethod
+    def compute_U_value(R: int, password: bytes, key: bytes) -> Tuple[bytes, bytes]:
+        """
+        Algorithm 3.8 Computing the encryption dictionary’s U (user password)
+        and UE (user encryption key) values.
+
+        1. Generate 16 random bytes of data using a strong random number generator.
+           The first 8 bytes are the User Validation Salt. The second 8 bytes
+           are the User Key Salt. Compute the 32-byte SHA-256 hash of the
+           password concatenated with the User Validation Salt. The 48-byte
+           string consisting of the 32-byte hash followed by the User
+           Validation Salt followed by the User Key Salt is stored as the U key.
+        2. Compute the 32-byte SHA-256 hash of the password concatenated with
+           the User Key Salt. Using this hash as the key, encrypt the file
+           encryption key using AES-256 in CBC mode with no padding and an
+           initialization vector of zero. The resulting 32-byte string is stored
+           as the UE key.
+
+        Args:
+            R:
+            password:
+            key:
+
+        Returns:
+            A tuple (u-value, ue value)
+        """
+        random_bytes = secrets.token_bytes(16)
+        val_salt = random_bytes[:8]
+        key_salt = random_bytes[8:]
+        u_value = AlgV5.calculate_hash(R, password, val_salt, b"") + val_salt + key_salt
+
+        tmp_key = AlgV5.calculate_hash(R, password, key_salt, b"")
+        iv = bytes(0 for _ in range(16))
+        ue_value = aes_cbc_encrypt(tmp_key, iv, key)
+        return u_value, ue_value
+
+    @staticmethod
+    def compute_O_value(
+        R: int, password: bytes, key: bytes, u_value: bytes
+    ) -> Tuple[bytes, bytes]:
+        """
+        Algorithm 3.9 Computing the encryption dictionary’s O (owner password)
+        and OE (owner encryption key) values.
+
+        1. Generate 16 random bytes of data using a strong random number
+           generator. The first 8 bytes are the Owner Validation Salt. The
+           second 8 bytes are the Owner Key Salt. Compute the 32-byte SHA-256
+           hash of the password concatenated with the Owner Validation Salt and
+           then concatenated with the 48-byte U string as generated in
+           Algorithm 3.8. The 48-byte string consisting of the 32-byte hash
+           followed by the Owner Validation Salt followed by the Owner Key Salt
+           is stored as the O key.
+        2. Compute the 32-byte SHA-256 hash of the password concatenated with
+           the Owner Key Salt and then concatenated with the 48-byte U string as
+           generated in Algorithm 3.8. Using this hash as the key,
+           encrypt the file encryption key using AES-256 in CBC mode with
+           no padding and an initialization vector of zero.
+           The resulting 32-byte string is stored as the OE key.
+
+        Args:
+            R:
+            password:
+            key:
+            u_value: A 32-byte string, based on the user password, that shall be
+                used in determining whether to prompt the user for a password
+                and, if so, whether a valid user or owner password was entered.
+
+        Returns:
+            A tuple (O value, OE value)
+        """
+        random_bytes = secrets.token_bytes(16)
+        val_salt = random_bytes[:8]
+        key_salt = random_bytes[8:]
+        o_value = (
+            AlgV5.calculate_hash(R, password, val_salt, u_value) + val_salt + key_salt
+        )
+        tmp_key = AlgV5.calculate_hash(R, password, key_salt, u_value[:48])
+        iv = bytes(0 for _ in range(16))
+        oe_value = aes_cbc_encrypt(tmp_key, iv, key)
+        return o_value, oe_value
+
+    @staticmethod
+    def compute_Perms_value(key: bytes, p: int, metadata_encrypted: bool) -> bytes:
+        """
+        Algorithm 3.10 Computing the encryption dictionary’s Perms
+        (permissions) value.
+
+        1. Extend the permissions (contents of the P integer) to 64 bits by
+           setting the upper 32 bits to all 1’s.
+           (This allows for future extension without changing the format.)
+        2. Record the 8 bytes of permission in the bytes 0-7 of the block,
+           low order byte first.
+        3. Set byte 8 to the ASCII value ' T ' or ' F ' according to the
+           EncryptMetadata Boolean.
+        4. Set bytes 9-11 to the ASCII characters ' a ', ' d ', ' b '.
+        5. Set bytes 12-15 to 4 bytes of random data, which will be ignored.
+        6. Encrypt the 16-byte block using AES-256 in ECB mode with an
+           initialization vector of zero, using the file encryption key as the
+           key. The result (16 bytes) is stored as the Perms string, and checked
+           for validity when the file is opened.
+
+        Args:
+            key:
+            p: A set of flags specifying which operations shall be permitted
+                when the document is opened with user access. If bit 2 is set to 1,
+                all other bits are ignored and all operations are permitted.
+                If bit 2 is set to 0, permission for operations are based on the
+                values of the remaining flags defined in Table 24.
+            metadata_encrypted: A boolean indicating if the metadata is encrypted.
+
+        Returns:
+            The perms value
+        """
+        b8 = b"T" if metadata_encrypted else b"F"
+        rr = secrets.token_bytes(4)
+        data = struct.pack("<I", p) + b"\xff\xff\xff\xff" + b8 + b"adb" + rr
+        perms = aes_ecb_encrypt(key, data)
+        return perms
+
+
+class PasswordType(IntEnum):
+    NOT_DECRYPTED = 0
+    USER_PASSWORD = 1
+    OWNER_PASSWORD = 2
+
+
+class EncryptAlgorithm(tuple, Enum):  # type: ignore # noqa: SLOT001
+    # V, R, Length
+    RC4_40 = (1, 2, 40)
+    RC4_128 = (2, 3, 128)
+    AES_128 = (4, 4, 128)
+    AES_256_R5 = (5, 5, 256)
+    AES_256 = (5, 6, 256)
+
+
+class EncryptionValues:
+    O: bytes  # noqa
+    U: bytes
+    OE: bytes
+    UE: bytes
+    Perms: bytes
+
+
+class Encryption:
+    """
+    Collects and manages parameters for PDF document encryption and decryption.
+
+    Args:
+        V: A code specifying the algorithm to be used in encrypting and
+           decrypting the document.
+        R: The revision of the standard security handler.
+        Length: The length of the encryption key in bits.
+        P: A set of flags specifying which operations shall be permitted
+           when the document is opened with user access
+        entry: The encryption dictionary object.
+        EncryptMetadata: Whether to encrypt metadata in the document.
+        first_id_entry: The first 16 bytes of the file's original ID.
+        StmF: The name of the crypt filter that shall be used by default
+              when decrypting streams.
+        StrF: The name of the crypt filter that shall be used when decrypting
+              all strings in the document.
+        EFF: The name of the crypt filter that shall be used when
+             encrypting embedded file streams that do not have their own
+             crypt filter specifier.
+        values: Additional encryption parameters.
+    """
+
+    def __init__(
+        self,
+        V: int,
+        R: int,
+        Length: int,
+        P: int,
+        entry: DictionaryObject,
+        EncryptMetadata: bool,
+        first_id_entry: bytes,
+        StmF: str,
+        StrF: str,
+        EFF: str,
+        values: Optional[EncryptionValues],
+    ) -> None:
+        # §7.6.2, entries common to all encryption dictionaries
+        # use same name as keys of encryption dictionaries entries
+        self.V = V
+        self.R = R
+        self.Length = Length  # key_size
+        self.P = (P + 0x100000000) % 0x100000000  # maybe P < 0
+        self.EncryptMetadata = EncryptMetadata
+        self.id1_entry = first_id_entry
+        self.StmF = StmF
+        self.StrF = StrF
+        self.EFF = EFF
+        self.values: EncryptionValues = values if values else EncryptionValues()
+
+        self._password_type = PasswordType.NOT_DECRYPTED
+        self._key: Optional[bytes] = None
+
+    def is_decrypted(self) -> bool:
+        return self._password_type != PasswordType.NOT_DECRYPTED
+
+    def encrypt_object(self, obj: PdfObject, idnum: int, generation: int) -> PdfObject:
+        # skip calculate key
+        if not self._is_encryption_object(obj):
+            return obj
+
+        cf = self._make_crypt_filter(idnum, generation)
+        return cf.encrypt_object(obj)
+
+    def decrypt_object(self, obj: PdfObject, idnum: int, generation: int) -> PdfObject:
+        # skip calculate key
+        if not self._is_encryption_object(obj):
+            return obj
+
+        cf = self._make_crypt_filter(idnum, generation)
+        return cf.decrypt_object(obj)
+
+    @staticmethod
+    def _is_encryption_object(obj: PdfObject) -> bool:
+        return isinstance(
+            obj,
+            (
+                ByteStringObject,
+                TextStringObject,
+                StreamObject,
+                ArrayObject,
+                DictionaryObject,
+            ),
+        )
+
+    def _make_crypt_filter(self, idnum: int, generation: int) -> CryptFilter:
+        """
+        Algorithm 1: Encryption of data using the RC4 or AES algorithms.
+
+        a) Obtain the object number and generation number from the object
+           identifier of the string or stream to be encrypted
+           (see 7.3.10, "Indirect Objects"). If the string is a direct object,
+           use the identifier of the indirect object containing it.
+        b) For all strings and streams without crypt filter specifier; treating
+           the object number and generation number as binary integers, extend
+           the original n-byte encryption key to n + 5 bytes by appending the
+           low-order 3 bytes of the object number and the low-order 2 bytes of
+           the generation number in that order, low-order byte first.
+           (n is 5 unless the value of V in the encryption dictionary is greater
+           than 1, in which case n is the value of Length divided by 8.)
+           If using the AES algorithm, extend the encryption key an additional
+           4 bytes by adding the value “sAlT”, which corresponds to the
+           hexadecimal values 0x73, 0x41, 0x6C, 0x54. (This addition is done for
+           backward compatibility and is not intended to provide additional
+           security.)
+        c) Initialize the MD5 hash function and pass the result of step (b) as
+           input to this function.
+        d) Use the first (n + 5) bytes, up to a maximum of 16, of the output
+           from the MD5 hash as the key for the RC4 or AES symmetric key
+           algorithms, along with the string or stream data to be encrypted.
+           If using the AES algorithm, the Cipher Block Chaining (CBC) mode,
+           which requires an initialization vector, is used. The block size
+           parameter is set to 16 bytes, and the initialization vector is a
+           16-byte random number that is stored as the first 16 bytes of the
+           encrypted stream or string.
+
+        Algorithm 3.1a Encryption of data using the AES algorithm
+        1. Use the 32-byte file encryption key for the AES-256 symmetric key
+           algorithm, along with the string or stream data to be encrypted.
+           Use the AES algorithm in Cipher Block Chaining (CBC) mode, which
+           requires an initialization vector. The block size parameter is set to
+           16 bytes, and the initialization vector is a 16-byte random number
+           that is stored as the first 16 bytes of the encrypted stream or string.
+           The output is the encrypted data to be stored in the PDF file.
+        """
+        pack1 = struct.pack("<i", idnum)[:3]
+        pack2 = struct.pack("<i", generation)[:2]
+
+        assert self._key
+        key = self._key
+        n = 5 if self.V == 1 else self.Length // 8
+        key_data = key[:n] + pack1 + pack2
+        key_hash = hashlib.md5(key_data)
+        rc4_key = key_hash.digest()[: min(n + 5, 16)]
+        # for AES-128
+        key_hash.update(b"sAlT")
+        aes128_key = key_hash.digest()[: min(n + 5, 16)]
+
+        # for AES-256
+        aes256_key = key
+
+        stm_crypt = self._get_crypt(self.StmF, rc4_key, aes128_key, aes256_key)
+        str_crypt = self._get_crypt(self.StrF, rc4_key, aes128_key, aes256_key)
+        ef_crypt = self._get_crypt(self.EFF, rc4_key, aes128_key, aes256_key)
+
+        return CryptFilter(stm_crypt, str_crypt, ef_crypt)
+
+    @staticmethod
+    def _get_crypt(
+        method: str, rc4_key: bytes, aes128_key: bytes, aes256_key: bytes
+    ) -> CryptBase:
+        if method == "/AESV3":
+            return CryptAES(aes256_key)
+        if method == "/AESV2":
+            return CryptAES(aes128_key)
+        elif method == "/Identity":
+            return CryptIdentity()
+        else:
+            return CryptRC4(rc4_key)
+
+    @staticmethod
+    def _encode_password(password: Union[bytes, str]) -> bytes:
+        if isinstance(password, str):
+            try:
+                pwd = password.encode("latin-1")
+            except Exception:
+                pwd = password.encode("utf-8")
+        else:
+            pwd = password
+        return pwd
+
+    def verify(self, password: Union[bytes, str]) -> PasswordType:
+        pwd = self._encode_password(password)
+        key, rc = self.verify_v4(pwd) if self.V <= 4 else self.verify_v5(pwd)
+        if rc != PasswordType.NOT_DECRYPTED:
+            self._password_type = rc
+            self._key = key
+        return rc
+
+    def verify_v4(self, password: bytes) -> Tuple[bytes, PasswordType]:
+        # verify owner password first
+        key = AlgV4.verify_owner_password(
+            password,
+            self.R,
+            self.Length,
+            self.values.O,
+            self.values.U,
+            self.P,
+            self.id1_entry,
+            self.EncryptMetadata,
+        )
+        if key:
+            return key, PasswordType.OWNER_PASSWORD
+        key = AlgV4.verify_user_password(
+            password,
+            self.R,
+            self.Length,
+            self.values.O,
+            self.values.U,
+            self.P,
+            self.id1_entry,
+            self.EncryptMetadata,
+        )
+        if key:
+            return key, PasswordType.USER_PASSWORD
+        return b"", PasswordType.NOT_DECRYPTED
+
+    def verify_v5(self, password: bytes) -> Tuple[bytes, PasswordType]:
+        # TODO: use SASLprep process
+        # verify owner password first
+        key = AlgV5.verify_owner_password(
+            self.R, password, self.values.O, self.values.OE, self.values.U
+        )
+        rc = PasswordType.OWNER_PASSWORD
+        if not key:
+            key = AlgV5.verify_user_password(
+                self.R, password, self.values.U, self.values.UE
+            )
+            rc = PasswordType.USER_PASSWORD
+        if not key:
+            return b"", PasswordType.NOT_DECRYPTED
+
+        # verify Perms
+        if not AlgV5.verify_perms(key, self.values.Perms, self.P, self.EncryptMetadata):
+            logger_warning("ignore '/Perms' verify failed", __name__)
+        return key, rc
+
+    def write_entry(
+        self, user_password: str, owner_password: Optional[str]
+    ) -> DictionaryObject:
+        user_pwd = self._encode_password(user_password)
+        owner_pwd = self._encode_password(owner_password) if owner_password else None
+        if owner_pwd is None:
+            owner_pwd = user_pwd
+
+        if self.V <= 4:
+            self.compute_values_v4(user_pwd, owner_pwd)
+        else:
+            self._key = secrets.token_bytes(self.Length // 8)
+            values = AlgV5.generate_values(
+                self.R, user_pwd, owner_pwd, self._key, self.P, self.EncryptMetadata
+            )
+            self.values.O = values["/O"]
+            self.values.U = values["/U"]
+            self.values.OE = values["/OE"]
+            self.values.UE = values["/UE"]
+            self.values.Perms = values["/Perms"]
+
+        dict_obj = DictionaryObject()
+        dict_obj[NameObject("/V")] = NumberObject(self.V)
+        dict_obj[NameObject("/R")] = NumberObject(self.R)
+        dict_obj[NameObject("/Length")] = NumberObject(self.Length)
+        dict_obj[NameObject("/P")] = NumberObject(self.P)
+        dict_obj[NameObject("/Filter")] = NameObject("/Standard")
+        # ignore /EncryptMetadata
+
+        dict_obj[NameObject("/O")] = ByteStringObject(self.values.O)
+        dict_obj[NameObject("/U")] = ByteStringObject(self.values.U)
+
+        if self.V >= 4:
+            # TODO: allow different method
+            std_cf = DictionaryObject()
+            std_cf[NameObject("/AuthEvent")] = NameObject("/DocOpen")
+            std_cf[NameObject("/CFM")] = NameObject(self.StmF)
+            std_cf[NameObject("/Length")] = NumberObject(self.Length // 8)
+            cf = DictionaryObject()
+            cf[NameObject("/StdCF")] = std_cf
+            dict_obj[NameObject("/CF")] = cf
+            dict_obj[NameObject("/StmF")] = NameObject("/StdCF")
+            dict_obj[NameObject("/StrF")] = NameObject("/StdCF")
+            # ignore EFF
+            # dict_obj[NameObject("/EFF")] = NameObject("/StdCF")
+
+        if self.V >= 5:
+            dict_obj[NameObject("/OE")] = ByteStringObject(self.values.OE)
+            dict_obj[NameObject("/UE")] = ByteStringObject(self.values.UE)
+            dict_obj[NameObject("/Perms")] = ByteStringObject(self.values.Perms)
+        return dict_obj
+
+    def compute_values_v4(self, user_password: bytes, owner_password: bytes) -> None:
+        rc4_key = AlgV4.compute_O_value_key(owner_password, self.R, self.Length)
+        o_value = AlgV4.compute_O_value(rc4_key, user_password, self.R)
+
+        key = AlgV4.compute_key(
+            user_password,
+            self.R,
+            self.Length,
+            o_value,
+            self.P,
+            self.id1_entry,
+            self.EncryptMetadata,
+        )
+        u_value = AlgV4.compute_U_value(key, self.R, self.id1_entry)
+
+        self._key = key
+        self.values.O = o_value
+        self.values.U = u_value
+
+    @staticmethod
+    def read(encryption_entry: DictionaryObject, first_id_entry: bytes) -> "Encryption":
+        if encryption_entry.get("/Filter") != "/Standard":
+            raise NotImplementedError(
+                "only Standard PDF encryption handler is available"
+            )
+        if "/SubFilter" in encryption_entry:
+            raise NotImplementedError("/SubFilter NOT supported")
+
+        stm_filter = "/V2"
+        str_filter = "/V2"
+        ef_filter = "/V2"
+
+        alg_ver = encryption_entry.get("/V", 0)
+        if alg_ver not in (1, 2, 3, 4, 5):
+            raise NotImplementedError(f"Encryption V={alg_ver} NOT supported")
+        if alg_ver >= 4:
+            filters = encryption_entry["/CF"]
+
+            stm_filter = encryption_entry.get("/StmF", "/Identity")
+            str_filter = encryption_entry.get("/StrF", "/Identity")
+            ef_filter = encryption_entry.get("/EFF", stm_filter)
+
+            if stm_filter != "/Identity":
+                stm_filter = filters[stm_filter]["/CFM"]  # type: ignore
+            if str_filter != "/Identity":
+                str_filter = filters[str_filter]["/CFM"]  # type: ignore
+            if ef_filter != "/Identity":
+                ef_filter = filters[ef_filter]["/CFM"]  # type: ignore
+
+            allowed_methods = ("/Identity", "/V2", "/AESV2", "/AESV3")
+            if stm_filter not in allowed_methods:
+                raise NotImplementedError(f"StmF Method {stm_filter} NOT supported!")
+            if str_filter not in allowed_methods:
+                raise NotImplementedError(f"StrF Method {str_filter} NOT supported!")
+            if ef_filter not in allowed_methods:
+                raise NotImplementedError(f"EFF Method {ef_filter} NOT supported!")
+
+        alg_rev = cast(int, encryption_entry["/R"])
+        perm_flags = cast(int, encryption_entry["/P"])
+        key_bits = encryption_entry.get("/Length", 40)
+        encrypt_metadata = encryption_entry.get("/EncryptMetadata")
+        encrypt_metadata = (
+            encrypt_metadata.value if encrypt_metadata is not None else True
+        )
+        values = EncryptionValues()
+        values.O = cast(ByteStringObject, encryption_entry["/O"]).original_bytes
+        values.U = cast(ByteStringObject, encryption_entry["/U"]).original_bytes
+        values.OE = encryption_entry.get("/OE", ByteStringObject()).original_bytes
+        values.UE = encryption_entry.get("/UE", ByteStringObject()).original_bytes
+        values.Perms = encryption_entry.get("/Perms", ByteStringObject()).original_bytes
+        return Encryption(
+            V=alg_ver,
+            R=alg_rev,
+            Length=key_bits,
+            P=perm_flags,
+            EncryptMetadata=encrypt_metadata,
+            first_id_entry=first_id_entry,
+            values=values,
+            StrF=str_filter,
+            StmF=stm_filter,
+            EFF=ef_filter,
+            entry=encryption_entry,  # Dummy entry for the moment; will get removed
+        )
+
+    @staticmethod
+    def make(
+        alg: EncryptAlgorithm, permissions: int, first_id_entry: bytes
+    ) -> "Encryption":
+        alg_ver, alg_rev, key_bits = alg
+
+        stm_filter, str_filter, ef_filter = "/V2", "/V2", "/V2"
+
+        if alg == EncryptAlgorithm.AES_128:
+            stm_filter, str_filter, ef_filter = "/AESV2", "/AESV2", "/AESV2"
+        elif alg in (EncryptAlgorithm.AES_256_R5, EncryptAlgorithm.AES_256):
+            stm_filter, str_filter, ef_filter = "/AESV3", "/AESV3", "/AESV3"
+
+        return Encryption(
+            V=alg_ver,
+            R=alg_rev,
+            Length=key_bits,
+            P=permissions,
+            EncryptMetadata=True,
+            first_id_entry=first_id_entry,
+            values=None,
+            StrF=str_filter,
+            StmF=stm_filter,
+            EFF=ef_filter,
+            entry=DictionaryObject(),  # Dummy entry for the moment; will get removed
+        )
diff --git a/.venv/lib/python3.12/site-packages/pypdf/_merger.py b/.venv/lib/python3.12/site-packages/pypdf/_merger.py
new file mode 100644
index 00000000..7176a1ad
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/_merger.py
@@ -0,0 +1,678 @@
+# Copyright (c) 2006, Mathieu Fenniak
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# * The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+from io import BytesIO, FileIO, IOBase
+from pathlib import Path
+from types import TracebackType
+from typing import (
+    Any,
+    Dict,
+    Iterable,
+    List,
+    Optional,
+    Tuple,
+    Type,
+    Union,
+    cast,
+)
+
+from ._encryption import Encryption
+from ._page import PageObject
+from ._reader import PdfReader
+from ._utils import (
+    StrByteType,
+    deprecate_with_replacement,
+    str_,
+)
+from ._writer import PdfWriter
+from .constants import GoToActionArguments, TypArguments, TypFitArguments
+from .constants import PagesAttributes as PA
+from .generic import (
+    PAGE_FIT,
+    ArrayObject,
+    Destination,
+    DictionaryObject,
+    Fit,
+    FloatObject,
+    IndirectObject,
+    NameObject,
+    NullObject,
+    NumberObject,
+    OutlineItem,
+    TextStringObject,
+    TreeObject,
+)
+from .pagerange import PageRange, PageRangeSpec
+from .types import LayoutType, OutlineType, PagemodeType
+
+ERR_CLOSED_WRITER = "close() was called and thus the writer cannot be used anymore"
+
+
+class _MergedPage:
+    """Collect necessary information on each page that is being merged."""
+
+    def __init__(self, pagedata: PageObject, src: PdfReader, id: int) -> None:
+        self.src = src
+        self.pagedata = pagedata
+        self.out_pagedata = None
+        self.id = id
+
+
+class PdfMerger:
+    """
+    Use :class:`PdfWriter` instead.
+
+    .. deprecated:: 5.0.0
+    """
+
+    def __init__(
+        self, strict: bool = False, fileobj: Union[Path, StrByteType] = ""
+    ) -> None:
+        deprecate_with_replacement("PdfMerger", "PdfWriter", "5.0.0")
+        self.inputs: List[Tuple[Any, PdfReader]] = []
+        self.pages: List[Any] = []
+        self.output: Optional[PdfWriter] = PdfWriter()
+        self.outline: OutlineType = []
+        self.named_dests: List[Any] = []
+        self.id_count = 0
+        self.fileobj = fileobj
+        self.strict = strict
+
+    def __enter__(self) -> "PdfMerger":
+        # There is nothing to do.
+        deprecate_with_replacement("PdfMerger", "PdfWriter", "5.0.0")
+        return self
+
+    def __exit__(
+        self,
+        exc_type: Optional[Type[BaseException]],
+        exc: Optional[BaseException],
+        traceback: Optional[TracebackType],
+    ) -> None:
+        """Write to the fileobj and close the merger."""
+        if self.fileobj:
+            self.write(self.fileobj)
+        self.close()
+
+    def merge(
+        self,
+        page_number: int,
+        fileobj: Union[Path, StrByteType, PdfReader],
+        outline_item: Optional[str] = None,
+        pages: Optional[PageRangeSpec] = None,
+        import_outline: bool = True,
+    ) -> None:
+        """
+        Merge the pages from the given file into the output file at the
+        specified page number.
+
+        Args:
+            page_number: The *page number* to insert this file. File will
+                be inserted after the given number.
+            fileobj: A File Object or an object that supports the standard
+                read and seek methods similar to a File Object. Could also be a
+                string representing a path to a PDF file.
+            outline_item: Optionally, you may specify an outline item
+                (previously referred to as a 'bookmark') to be applied at the
+                beginning of the included file by supplying the text of the outline item.
+            pages: can be a :class:`PageRange<pypdf.pagerange.PageRange>`
+                or a ``(start, stop[, step])`` tuple
+                to merge only the specified range of pages from the source
+                document into the output document.
+                Can also be a list of pages to merge.
+           import_outline: You may prevent the source document's
+                outline (collection of outline items, previously referred to as
+                'bookmarks') from being imported by specifying this as ``False``.
+        """
+        stream, encryption_obj = self._create_stream(fileobj)
+
+        # Create a new PdfReader instance using the stream
+        # (either file or BytesIO or StringIO) created above
+        reader = PdfReader(stream, strict=self.strict)  # type: ignore[arg-type]
+        self.inputs.append((stream, reader))
+        if encryption_obj is not None:
+            reader._encryption = encryption_obj
+
+        # Find the range of pages to merge.
+        if pages is None:
+            pages = (0, len(reader.pages))
+        elif isinstance(pages, PageRange):
+            pages = pages.indices(len(reader.pages))
+        elif isinstance(pages, list):
+            pass
+        elif not isinstance(pages, tuple):
+            raise TypeError('"pages" must be a tuple of (start, stop[, step])')
+
+        srcpages = []
+
+        outline = []
+        if import_outline:
+            outline = reader.outline
+            outline = self._trim_outline(reader, outline, pages)
+
+        if outline_item:
+            outline_item_typ = OutlineItem(
+                TextStringObject(outline_item),
+                NumberObject(self.id_count),
+                Fit.fit(),
+            )
+            self.outline += [outline_item_typ, outline]  # type: ignore
+        else:
+            self.outline += outline
+
+        dests = reader.named_destinations
+        trimmed_dests = self._trim_dests(reader, dests, pages)
+        self.named_dests += trimmed_dests
+
+        # Gather all the pages that are going to be merged
+        for i in range(*pages):
+            page = reader.pages[i]
+
+            id = self.id_count
+            self.id_count += 1
+
+            mp = _MergedPage(page, reader, id)
+
+            srcpages.append(mp)
+
+        self._associate_dests_to_pages(srcpages)
+        self._associate_outline_items_to_pages(srcpages)
+
+        # Slice to insert the pages at the specified page_number
+        self.pages[page_number:page_number] = srcpages
+
+    def _create_stream(
+        self, fileobj: Union[Path, StrByteType, PdfReader]
+    ) -> Tuple[IOBase, Optional[Encryption]]:
+        # If the fileobj parameter is a string, assume it is a path
+        # and create a file object at that location. If it is a file,
+        # copy the file's contents into a BytesIO stream object; if
+        # it is a PdfReader, copy that reader's stream into a
+        # BytesIO stream.
+        # If fileobj is none of the above types, it is not modified
+        encryption_obj = None
+        stream: IOBase
+        if isinstance(fileobj, (str, Path)):
+            stream = FileIO(fileobj, "rb")
+        elif isinstance(fileobj, PdfReader):
+            if fileobj._encryption:
+                encryption_obj = fileobj._encryption
+            orig_tell = fileobj.stream.tell()
+            fileobj.stream.seek(0)
+            stream = BytesIO(fileobj.stream.read())
+
+            # reset the stream to its original location
+            fileobj.stream.seek(orig_tell)
+        elif hasattr(fileobj, "seek") and hasattr(fileobj, "read"):
+            fileobj.seek(0)
+            file_content = fileobj.read()
+            stream = BytesIO(file_content)
+        else:
+            raise NotImplementedError(
+                "PdfMerger.merge requires an object that PdfReader can parse. "
+                "Typically, that is a Path or a string representing a Path, "
+                "a file object, or an object implementing .seek and .read. "
+                "Passing a PdfReader directly works as well."
+            )
+        return stream, encryption_obj
+
+    def append(
+        self,
+        fileobj: Union[StrByteType, PdfReader, Path],
+        outline_item: Optional[str] = None,
+        pages: Union[
+            None, PageRange, Tuple[int, int], Tuple[int, int, int], List[int]
+        ] = None,
+        import_outline: bool = True,
+    ) -> None:
+        """
+        Identical to the :meth:`merge()<merge>` method, but assumes you want to
+        concatenate all pages onto the end of the file instead of specifying a
+        position.
+
+        Args:
+            fileobj: A File Object or an object that supports the standard
+                read and seek methods similar to a File Object. Could also be a
+                string representing a path to a PDF file.
+            outline_item: Optionally, you may specify an outline item
+                (previously referred to as a 'bookmark') to be applied at the
+                beginning of the included file by supplying the text of the outline item.
+            pages: can be a :class:`PageRange<pypdf.pagerange.PageRange>`
+                or a ``(start, stop[, step])`` tuple
+                to merge only the specified range of pages from the source
+                document into the output document.
+                Can also be a list of pages to append.
+            import_outline: You may prevent the source document's
+                outline (collection of outline items, previously referred to as
+                'bookmarks') from being imported by specifying this as ``False``.
+        """
+        self.merge(len(self.pages), fileobj, outline_item, pages, import_outline)
+
+    def write(self, fileobj: Union[Path, StrByteType]) -> None:
+        """
+        Write all data that has been merged to the given output file.
+
+        Args:
+            fileobj: Output file. Can be a filename or any kind of
+                file-like object.
+        """
+        if self.output is None:
+            raise RuntimeError(ERR_CLOSED_WRITER)
+
+        # Add pages to the PdfWriter
+        # The commented out line below was replaced with the two lines below it
+        # to allow PdfMerger to work with PyPdf 1.13
+        for page in self.pages:
+            self.output.add_page(page.pagedata)
+            pages_obj = cast(Dict[str, Any], self.output._pages.get_object())
+            page.out_pagedata = self.output.get_reference(
+                pages_obj[PA.KIDS][-1].get_object()
+            )
+
+        # Once all pages are added, create outline items to point at those pages
+        self._write_dests()
+        self._write_outline()
+
+        # Write the output to the file
+        my_file, ret_fileobj = self.output.write(fileobj)
+
+        if my_file:
+            ret_fileobj.close()
+
+    def close(self) -> None:
+        """Shut all file descriptors (input and output) and clear all memory usage."""
+        self.pages = []
+        for file_descriptor, _reader in self.inputs:
+            file_descriptor.close()
+
+        self.inputs = []
+        self.output = None
+
+    def add_metadata(self, infos: Dict[str, Any]) -> None:
+        """
+        Add custom metadata to the output.
+
+        Args:
+            infos: a Python dictionary where each key is a field
+                and each value is your new metadata.
+                An example is ``{'/Title': 'My title'}``
+        """
+        if self.output is None:
+            raise RuntimeError(ERR_CLOSED_WRITER)
+        self.output.add_metadata(infos)
+
+    def set_page_layout(self, layout: LayoutType) -> None:
+        """
+        Set the page layout.
+
+        Args:
+            layout: The page layout to be used
+
+        .. list-table:: Valid ``layout`` arguments
+           :widths: 50 200
+
+           * - /NoLayout
+             - Layout explicitly not specified
+           * - /SinglePage
+             - Show one page at a time
+           * - /OneColumn
+             - Show one column at a time
+           * - /TwoColumnLeft
+             - Show pages in two columns, odd-numbered pages on the left
+           * - /TwoColumnRight
+             - Show pages in two columns, odd-numbered pages on the right
+           * - /TwoPageLeft
+             - Show two pages at a time, odd-numbered pages on the left
+           * - /TwoPageRight
+             - Show two pages at a time, odd-numbered pages on the right
+        """
+        if self.output is None:
+            raise RuntimeError(ERR_CLOSED_WRITER)
+        self.output._set_page_layout(layout)
+
+    def set_page_mode(self, mode: PagemodeType) -> None:
+        """
+        Set the page mode.
+
+        Args:
+            mode: The page mode to use.
+
+        .. list-table:: Valid ``mode`` arguments
+           :widths: 50 200
+
+           * - /UseNone
+             - Do not show outline or thumbnails panels
+           * - /UseOutlines
+             - Show outline (aka bookmarks) panel
+           * - /UseThumbs
+             - Show page thumbnails panel
+           * - /FullScreen
+             - Fullscreen view
+           * - /UseOC
+             - Show Optional Content Group (OCG) panel
+           * - /UseAttachments
+             - Show attachments panel
+        """
+        self.page_mode = mode
+
+    @property
+    def page_mode(self) -> Optional[PagemodeType]:
+        """
+        Set the page mode.
+
+        Args:
+            mode: The page mode to use.
+
+        .. list-table:: Valid ``mode`` arguments
+           :widths: 50 200
+
+           * - /UseNone
+             - Do not show outline or thumbnails panels
+           * - /UseOutlines
+             - Show outline (aka bookmarks) panel
+           * - /UseThumbs
+             - Show page thumbnails panel
+           * - /FullScreen
+             - Fullscreen view
+           * - /UseOC
+             - Show Optional Content Group (OCG) panel
+           * - /UseAttachments
+             - Show attachments panel
+        """
+        if self.output is None:
+            raise RuntimeError(ERR_CLOSED_WRITER)
+        return self.output.page_mode
+
+    @page_mode.setter
+    def page_mode(self, mode: PagemodeType) -> None:
+        if self.output is None:
+            raise RuntimeError(ERR_CLOSED_WRITER)
+        self.output.page_mode = mode
+
+    def _trim_dests(
+        self,
+        pdf: PdfReader,
+        dests: Dict[str, Dict[str, Any]],
+        pages: Union[Tuple[int, int], Tuple[int, int, int], List[int]],
+    ) -> List[Dict[str, Any]]:
+        """
+        Remove named destinations that are not a part of the specified page set.
+
+        Args:
+            pdf:
+            dests:
+            pages:
+        """
+        new_dests = []
+        lst = pages if isinstance(pages, list) else list(range(*pages))
+        for key, obj in dests.items():
+            for j in lst:
+                if pdf.pages[j].get_object() == obj["/Page"].get_object():
+                    obj[NameObject("/Page")] = obj["/Page"].get_object()
+                    assert str_(key) == str_(obj["/Title"])
+                    new_dests.append(obj)
+                    break
+        return new_dests
+
+    def _trim_outline(
+        self,
+        pdf: PdfReader,
+        outline: OutlineType,
+        pages: Union[Tuple[int, int], Tuple[int, int, int], List[int]],
+    ) -> OutlineType:
+        """
+        Remove outline item entries that are not a part of the specified page set.
+
+        Args:
+            pdf:
+            outline:
+            pages:
+
+        Returns:
+            An outline type
+        """
+        new_outline = []
+        prev_header_added = True
+        lst = pages if isinstance(pages, list) else list(range(*pages))
+        for i, outline_item in enumerate(outline):
+            if isinstance(outline_item, list):
+                sub = self._trim_outline(pdf, outline_item, lst)  # type: ignore
+                if sub:
+                    if not prev_header_added:
+                        new_outline.append(outline[i - 1])
+                    new_outline.append(sub)  # type: ignore
+            else:
+                prev_header_added = False
+                for j in lst:
+                    if outline_item["/Page"] is None:
+                        continue
+                    if pdf.pages[j].get_object() == outline_item["/Page"].get_object():
+                        outline_item[NameObject("/Page")] = outline_item[
+                            "/Page"
+                        ].get_object()
+                        new_outline.append(outline_item)
+                        prev_header_added = True
+                        break
+        return new_outline
+
+    def _write_dests(self) -> None:
+        if self.output is None:
+            raise RuntimeError(ERR_CLOSED_WRITER)
+        for named_dest in self.named_dests:
+            page_index = None
+            if "/Page" in named_dest:  # deprecated
+                for page_index, page in enumerate(self.pages):  # noqa: B007
+                    if page.id == named_dest["/Page"]:
+                        named_dest[NameObject("/Page")] = page.out_pagedata
+                        break
+
+            if page_index is not None:  # deprecated
+                self.output.add_named_destination_object(named_dest)
+
+    def _write_outline(
+        self,
+        outline: Optional[Iterable[OutlineItem]] = None,
+        parent: Optional[TreeObject] = None,
+    ) -> None:
+        if self.output is None:
+            raise RuntimeError(ERR_CLOSED_WRITER)
+        if outline is None:
+            outline = self.outline  # type: ignore
+        assert outline is not None, "hint for mypy"  # TODO: is that true?
+
+        last_added = None
+        for outline_item in outline:
+            if isinstance(outline_item, list):
+                self._write_outline(outline_item, last_added)
+                continue
+
+            page_no = None
+            if "/Page" in outline_item:
+                for page_no, page in enumerate(self.pages):  # noqa: B007
+                    if page.id == outline_item["/Page"]:
+                        self._write_outline_item_on_page(outline_item, page)
+                        break
+            if page_no is not None:
+                del outline_item["/Page"], outline_item["/Type"]
+                last_added = self.output.add_outline_item_dict(outline_item, parent)
+
+    def _write_outline_item_on_page(
+        self, outline_item: Union[OutlineItem, Destination], page: _MergedPage
+    ) -> None:
+        oi_type = cast(str, outline_item["/Type"])
+        args = [NumberObject(page.id), NameObject(oi_type)]
+        fit2arg_keys: Dict[str, Tuple[str, ...]] = {
+            TypFitArguments.FIT_H: (TypArguments.TOP,),
+            TypFitArguments.FIT_BH: (TypArguments.TOP,),
+            TypFitArguments.FIT_V: (TypArguments.LEFT,),
+            TypFitArguments.FIT_BV: (TypArguments.LEFT,),
+            TypFitArguments.XYZ: (TypArguments.LEFT, TypArguments.TOP, "/Zoom"),
+            TypFitArguments.FIT_R: (
+                TypArguments.LEFT,
+                TypArguments.BOTTOM,
+                TypArguments.RIGHT,
+                TypArguments.TOP,
+            ),
+        }
+        for arg_key in fit2arg_keys.get(oi_type, ()):
+            if arg_key in outline_item and not isinstance(
+                outline_item[arg_key], NullObject
+            ):
+                args.append(FloatObject(outline_item[arg_key]))
+            else:
+                args.append(FloatObject(0))
+            del outline_item[arg_key]
+
+        outline_item[NameObject("/A")] = DictionaryObject(
+            {
+                NameObject(GoToActionArguments.S): NameObject("/GoTo"),
+                NameObject(GoToActionArguments.D): ArrayObject(args),
+            }
+        )
+
+    def _associate_dests_to_pages(self, pages: List[_MergedPage]) -> None:
+        for named_dest in self.named_dests:
+            page_index = None
+            np = named_dest["/Page"]
+
+            if isinstance(np, NumberObject):
+                continue
+
+            for page in pages:
+                if np.get_object() == page.pagedata.get_object():
+                    page_index = page.id
+
+            if page_index is None:  # deprecated
+                raise ValueError(
+                    f"Unresolved named destination '{named_dest['/Title']}'"
+                )
+            named_dest[NameObject("/Page")] = NumberObject(page_index)
+
+    def _associate_outline_items_to_pages(
+        self, pages: List[_MergedPage], outline: Optional[Iterable[OutlineItem]] = None
+    ) -> None:
+        if outline is None:
+            outline = self.outline  # type: ignore # TODO: self.bookmarks can be None!
+        assert outline is not None, "hint for mypy"
+        for outline_item in outline:
+            if isinstance(outline_item, list):
+                self._associate_outline_items_to_pages(pages, outline_item)
+                continue
+
+            page_index = None
+            outline_item_page = outline_item["/Page"]
+
+            if isinstance(outline_item_page, NumberObject):
+                continue
+
+            for p in pages:
+                if outline_item_page.get_object() == p.pagedata.get_object():
+                    page_index = p.id
+
+            if page_index is not None:
+                outline_item[NameObject("/Page")] = NumberObject(page_index)
+
+    def find_outline_item(
+        self,
+        outline_item: Dict[str, Any],
+        root: Optional[OutlineType] = None,
+    ) -> Optional[List[int]]:
+        if root is None:
+            root = self.outline
+
+        for i, oi_enum in enumerate(root):
+            if isinstance(oi_enum, list):
+                # oi_enum is still an inner node
+                # (OutlineType, if recursive types were supported by mypy)
+                res = self.find_outline_item(outline_item, oi_enum)  # type: ignore
+                if res:  # deprecated
+                    return [i] + res
+            elif (
+                oi_enum == outline_item
+                or cast(Dict[Any, Any], oi_enum["/Title"]) == outline_item
+            ):
+                # we found a leaf node
+                return [i]
+
+        return None
+
+    def add_outline_item(
+        self,
+        title: str,
+        page_number: int,
+        parent: Union[None, TreeObject, IndirectObject] = None,
+        color: Optional[Tuple[float, float, float]] = None,
+        bold: bool = False,
+        italic: bool = False,
+        fit: Fit = PAGE_FIT,
+    ) -> IndirectObject:
+        """
+        Add an outline item (commonly referred to as a "Bookmark") to this PDF file.
+
+        Args:
+            title: Title to use for this outline item.
+            page_number: Page number this outline item will point to.
+            parent: A reference to a parent outline item to create nested
+                outline items.
+            color: Color of the outline item's font as a red, green, blue tuple
+                from 0.0 to 1.0
+            bold: Outline item font is bold
+            italic: Outline item font is italic
+            fit: The fit of the destination page.
+        """
+        writer = self.output
+        if writer is None:
+            raise RuntimeError(ERR_CLOSED_WRITER)
+        return writer.add_outline_item(
+            title,
+            page_number,
+            parent,
+            None,
+            color,
+            bold,
+            italic,
+            fit,
+        )
+
+    def add_named_destination(
+        self,
+        title: str,
+        page_number: int,
+    ) -> None:
+        """
+        Add a destination to the output.
+
+        Args:
+            title: Title to use
+            page_number: Page number this destination points at.
+        """
+        dest = Destination(
+            TextStringObject(title),
+            NumberObject(page_number),
+            Fit.fit_horizontally(top=826),
+        )
+        self.named_dests.append(dest)
diff --git a/.venv/lib/python3.12/site-packages/pypdf/_page.py b/.venv/lib/python3.12/site-packages/pypdf/_page.py
new file mode 100644
index 00000000..63038d9d
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/_page.py
@@ -0,0 +1,2458 @@
+# Copyright (c) 2006, Mathieu Fenniak
+# Copyright (c) 2007, Ashish Kulkarni <kulkarni.ashish@gmail.com>
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# * The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+import math
+import sys
+from decimal import Decimal
+from pathlib import Path
+from typing import (
+    Any,
+    Callable,
+    Dict,
+    Iterable,
+    Iterator,
+    List,
+    Optional,
+    Sequence,
+    Set,
+    Tuple,
+    Union,
+    cast,
+    overload,
+)
+
+from ._cmap import build_char_map, unknown_char_map
+from ._protocols import PdfCommonDocProtocol
+from ._text_extraction import (
+    OrientationNotFoundError,
+    _layout_mode,
+    crlf_space_check,
+    handle_tj,
+    mult,
+)
+from ._utils import (
+    CompressedTransformationMatrix,
+    File,
+    ImageFile,
+    TransformationMatrixType,
+    logger_warning,
+    matrix_multiply,
+)
+from .constants import AnnotationDictionaryAttributes as ADA
+from .constants import ImageAttributes as IA
+from .constants import PageAttributes as PG
+from .constants import Resources as RES
+from .errors import PageSizeNotDefinedError, PdfReadError
+from .filters import _xobj_to_image
+from .generic import (
+    ArrayObject,
+    ContentStream,
+    DictionaryObject,
+    EncodedStreamObject,
+    FloatObject,
+    IndirectObject,
+    NameObject,
+    NullObject,
+    NumberObject,
+    PdfObject,
+    RectangleObject,
+    StreamObject,
+)
+
+if sys.version_info >= (3, 8):
+    from typing import Literal
+else:
+    from typing_extensions import Literal
+
+
+MERGE_CROP_BOX = "cropbox"  # pypdf<=3.4.0 used 'trimbox'
+
+
+def _get_rectangle(self: Any, name: str, defaults: Iterable[str]) -> RectangleObject:
+    retval: Union[None, RectangleObject, IndirectObject] = self.get(name)
+    if isinstance(retval, RectangleObject):
+        return retval
+    if retval is None:
+        for d in defaults:
+            retval = self.get(d)
+            if retval is not None:
+                break
+    if isinstance(retval, IndirectObject):
+        retval = self.pdf.get_object(retval)
+    retval = RectangleObject(retval)  # type: ignore
+    _set_rectangle(self, name, retval)
+    return retval
+
+
+def _set_rectangle(self: Any, name: str, value: Union[RectangleObject, float]) -> None:
+    name = NameObject(name)
+    self[name] = value
+
+
+def _delete_rectangle(self: Any, name: str) -> None:
+    del self[name]
+
+
+def _create_rectangle_accessor(name: str, fallback: Iterable[str]) -> property:
+    return property(
+        lambda self: _get_rectangle(self, name, fallback),
+        lambda self, value: _set_rectangle(self, name, value),
+        lambda self: _delete_rectangle(self, name),
+    )
+
+
+class Transformation:
+    """
+    Represent a 2D transformation.
+
+    The transformation between two coordinate systems is represented by a 3-by-3
+    transformation matrix matrix with the following form::
+
+        a b 0
+        c d 0
+        e f 1
+
+    Because a transformation matrix has only six elements that can be changed,
+    it is usually specified in PDF as the six-element array [ a b c d e f ].
+
+    Coordinate transformations are expressed as matrix multiplications::
+
+                                 a b 0
+     [ x′ y′ 1 ] = [ x y 1 ] ×   c d 0
+                                 e f 1
+
+
+    Example:
+        >>> from pypdf import Transformation
+        >>> op = Transformation().scale(sx=2, sy=3).translate(tx=10, ty=20)
+        >>> page.add_transformation(op)
+    """
+
+    # 9.5.4 Coordinate Systems for 3D
+    # 4.2.2 Common Transformations
+    def __init__(self, ctm: CompressedTransformationMatrix = (1, 0, 0, 1, 0, 0)):
+        self.ctm = ctm
+
+    @property
+    def matrix(self) -> TransformationMatrixType:
+        """
+        Return the transformation matrix as a tuple of tuples in the form:
+
+        ((a, b, 0), (c, d, 0), (e, f, 1))
+        """
+        return (
+            (self.ctm[0], self.ctm[1], 0),
+            (self.ctm[2], self.ctm[3], 0),
+            (self.ctm[4], self.ctm[5], 1),
+        )
+
+    @staticmethod
+    def compress(matrix: TransformationMatrixType) -> CompressedTransformationMatrix:
+        """
+        Compresses the transformation matrix into a tuple of (a, b, c, d, e, f).
+
+        Args:
+            matrix: The transformation matrix as a tuple of tuples.
+
+        Returns:
+            A tuple representing the transformation matrix as (a, b, c, d, e, f)
+        """
+        return (
+            matrix[0][0],
+            matrix[0][1],
+            matrix[1][0],
+            matrix[1][1],
+            matrix[2][0],
+            matrix[2][1],
+        )
+
+    def transform(self, m: "Transformation") -> "Transformation":
+        """
+        Apply one transformation to another.
+
+        Args:
+            m: a Transformation to apply.
+
+        Returns:
+            A new ``Transformation`` instance
+
+        Example:
+            >>> from pypdf import Transformation
+            >>> op = Transformation((1, 0, 0, -1, 0, height)) # vertical mirror
+            >>> op = Transformation().transform(Transformation((-1, 0, 0, 1, iwidth, 0))) # horizontal mirror
+            >>> page.add_transformation(op)
+        """
+        ctm = Transformation.compress(matrix_multiply(self.matrix, m.matrix))
+        return Transformation(ctm)
+
+    def translate(self, tx: float = 0, ty: float = 0) -> "Transformation":
+        """
+        Translate the contents of a page.
+
+        Args:
+            tx: The translation along the x-axis.
+            ty: The translation along the y-axis.
+
+        Returns:
+            A new ``Transformation`` instance
+        """
+        m = self.ctm
+        return Transformation(ctm=(m[0], m[1], m[2], m[3], m[4] + tx, m[5] + ty))
+
+    def scale(
+        self, sx: Optional[float] = None, sy: Optional[float] = None
+    ) -> "Transformation":
+        """
+        Scale the contents of a page towards the origin of the coordinate system.
+
+        Typically, that is the lower-left corner of the page. That can be
+        changed by translating the contents / the page boxes.
+
+        Args:
+            sx: The scale factor along the x-axis.
+            sy: The scale factor along the y-axis.
+
+        Returns:
+            A new Transformation instance with the scaled matrix.
+        """
+        if sx is None and sy is None:
+            raise ValueError("Either sx or sy must be specified")
+        if sx is None:
+            sx = sy
+        if sy is None:
+            sy = sx
+        assert sx is not None
+        assert sy is not None
+        op: TransformationMatrixType = ((sx, 0, 0), (0, sy, 0), (0, 0, 1))
+        ctm = Transformation.compress(matrix_multiply(self.matrix, op))
+        return Transformation(ctm)
+
+    def rotate(self, rotation: float) -> "Transformation":
+        """
+        Rotate the contents of a page.
+
+        Args:
+            rotation: The angle of rotation in degrees.
+
+        Returns:
+            A new ``Transformation`` instance with the rotated matrix.
+        """
+        rotation = math.radians(rotation)
+        op: TransformationMatrixType = (
+            (math.cos(rotation), math.sin(rotation), 0),
+            (-math.sin(rotation), math.cos(rotation), 0),
+            (0, 0, 1),
+        )
+        ctm = Transformation.compress(matrix_multiply(self.matrix, op))
+        return Transformation(ctm)
+
+    def __repr__(self) -> str:
+        return f"Transformation(ctm={self.ctm})"
+
+    @overload
+    def apply_on(self, pt: List[float], as_object: bool = False) -> List[float]:
+        ...
+
+    @overload
+    def apply_on(
+        self, pt: Tuple[float, float], as_object: bool = False
+    ) -> Tuple[float, float]:
+        ...
+
+    def apply_on(
+        self,
+        pt: Union[Tuple[float, float], List[float]],
+        as_object: bool = False,
+    ) -> Union[Tuple[float, float], List[float]]:
+        """
+        Apply the transformation matrix on the given point.
+
+        Args:
+            pt: A tuple or list representing the point in the form (x, y)
+
+        Returns:
+            A tuple or list representing the transformed point in the form (x', y')
+        """
+        typ = FloatObject if as_object else float
+        pt1 = (
+            typ(float(pt[0]) * self.ctm[0] + float(pt[1]) * self.ctm[2] + self.ctm[4]),
+            typ(float(pt[0]) * self.ctm[1] + float(pt[1]) * self.ctm[3] + self.ctm[5]),
+        )
+        return list(pt1) if isinstance(pt, list) else pt1
+
+
+class PageObject(DictionaryObject):
+    """
+    PageObject represents a single page within a PDF file.
+
+    Typically these objects will be created by accessing the
+    :attr:`pages<pypdf.PdfReader.pages>` property of the
+    :class:`PdfReader<pypdf.PdfReader>` class, but it is
+    also possible to create an empty page with the
+    :meth:`create_blank_page()<pypdf._page.PageObject.create_blank_page>` static method.
+
+    Args:
+        pdf: PDF file the page belongs to.
+        indirect_reference: Stores the original indirect reference to
+            this object in its source PDF
+    """
+
+    original_page: "PageObject"  # very local use in writer when appending
+
+    def __init__(
+        self,
+        pdf: Optional[PdfCommonDocProtocol] = None,
+        indirect_reference: Optional[IndirectObject] = None,
+    ) -> None:
+        DictionaryObject.__init__(self)
+        self.pdf = pdf
+        self.inline_images: Optional[Dict[str, ImageFile]] = None
+        # below Union for mypy but actually Optional[List[str]]
+        self.indirect_reference = indirect_reference
+
+    def hash_value_data(self) -> bytes:
+        data = super().hash_value_data()
+        data += b"%d" % id(self)
+        return data
+
+    @property
+    def user_unit(self) -> float:
+        """
+        A read-only positive number giving the size of user space units.
+
+        It is in multiples of 1/72 inch. Hence a value of 1 means a user
+        space unit is 1/72 inch, and a value of 3 means that a user
+        space unit is 3/72 inch.
+        """
+        return self.get(PG.USER_UNIT, 1)
+
+    @staticmethod
+    def create_blank_page(
+        pdf: Optional[PdfCommonDocProtocol] = None,
+        width: Union[float, Decimal, None] = None,
+        height: Union[float, Decimal, None] = None,
+    ) -> "PageObject":
+        """
+        Return a new blank page.
+
+        If ``width`` or ``height`` is ``None``, try to get the page size
+        from the last page of *pdf*.
+
+        Args:
+            pdf: PDF file the page is within.
+            width: The width of the new page expressed in default user
+                space units.
+            height: The height of the new page expressed in default user
+                space units.
+
+        Returns:
+            The new blank page
+
+        Raises:
+            PageSizeNotDefinedError: if ``pdf`` is ``None`` or contains
+                no page
+        """
+        page = PageObject(pdf)
+
+        # Creates a new page (cf PDF Reference  7.7.3.3)
+        page.__setitem__(NameObject(PG.TYPE), NameObject("/Page"))
+        page.__setitem__(NameObject(PG.PARENT), NullObject())
+        page.__setitem__(NameObject(PG.RESOURCES), DictionaryObject())
+        if width is None or height is None:
+            if pdf is not None and len(pdf.pages) > 0:
+                lastpage = pdf.pages[len(pdf.pages) - 1]
+                width = lastpage.mediabox.width
+                height = lastpage.mediabox.height
+            else:
+                raise PageSizeNotDefinedError
+        page.__setitem__(
+            NameObject(PG.MEDIABOX), RectangleObject((0, 0, width, height))  # type: ignore
+        )
+
+        return page
+
+    @property
+    def _old_images(self) -> List[File]:  # deprecated
+        """
+        Get a list of all images of the page.
+
+        This requires pillow. You can install it via 'pip install pypdf[image]'.
+
+        For the moment, this does NOT include inline images. They will be added
+        in future.
+        """
+        images_extracted: List[File] = []
+        if RES.XOBJECT not in self[PG.RESOURCES]:  # type: ignore
+            return images_extracted
+
+        x_object = self[PG.RESOURCES][RES.XOBJECT].get_object()  # type: ignore
+        for obj in x_object:
+            if x_object[obj][IA.SUBTYPE] == "/Image":
+                extension, byte_stream, img = _xobj_to_image(x_object[obj])
+                if extension is not None:
+                    filename = f"{obj[1:]}{extension}"
+                    images_extracted.append(File(name=filename, data=byte_stream))
+                    images_extracted[-1].image = img
+                    images_extracted[-1].indirect_reference = x_object[
+                        obj
+                    ].indirect_reference
+        return images_extracted
+
+    def _get_ids_image(
+        self,
+        obj: Optional[DictionaryObject] = None,
+        ancest: Optional[List[str]] = None,
+        call_stack: Optional[List[Any]] = None,
+    ) -> List[Union[str, List[str]]]:
+        if call_stack is None:
+            call_stack = []
+        _i = getattr(obj, "indirect_reference", None)
+        if _i in call_stack:
+            return []
+        else:
+            call_stack.append(_i)
+        if self.inline_images is None:
+            self.inline_images = self._get_inline_images()
+        if obj is None:
+            obj = self
+        if ancest is None:
+            ancest = []
+        lst: List[Union[str, List[str]]] = []
+        if PG.RESOURCES not in obj or RES.XOBJECT not in cast(
+            DictionaryObject, obj[PG.RESOURCES]
+        ):
+            return [] if self.inline_images is None else list(self.inline_images.keys())
+
+        x_object = obj[PG.RESOURCES][RES.XOBJECT].get_object()  # type: ignore
+        for o in x_object:
+            if not isinstance(x_object[o], StreamObject):
+                continue
+            if x_object[o][IA.SUBTYPE] == "/Image":
+                lst.append(o if len(ancest) == 0 else ancest + [o])
+            else:  # is a form with possible images inside
+                lst.extend(self._get_ids_image(x_object[o], ancest + [o], call_stack))
+        assert self.inline_images is not None
+        lst.extend(list(self.inline_images.keys()))
+        return lst
+
+    def _get_image(
+        self,
+        id: Union[str, List[str], Tuple[str]],
+        obj: Optional[DictionaryObject] = None,
+    ) -> ImageFile:
+        if obj is None:
+            obj = cast(DictionaryObject, self)
+        if isinstance(id, tuple):
+            id = list(id)
+        if isinstance(id, List) and len(id) == 1:
+            id = id[0]
+        try:
+            xobjs = cast(
+                DictionaryObject, cast(DictionaryObject, obj[PG.RESOURCES])[RES.XOBJECT]
+            )
+        except KeyError:
+            if not (id[0] == "~" and id[-1] == "~"):
+                raise
+        if isinstance(id, str):
+            if id[0] == "~" and id[-1] == "~":
+                if self.inline_images is None:
+                    self.inline_images = self._get_inline_images()
+                if self.inline_images is None:  # pragma: no cover
+                    raise KeyError("no inline image can be found")
+                return self.inline_images[id]
+
+            imgd = _xobj_to_image(cast(DictionaryObject, xobjs[id]))
+            extension, byte_stream = imgd[:2]
+            f = ImageFile(
+                name=f"{id[1:]}{extension}",
+                data=byte_stream,
+                image=imgd[2],
+                indirect_reference=xobjs[id].indirect_reference,
+            )
+            return f
+        else:  # in a sub object
+            ids = id[1:]
+            return self._get_image(ids, cast(DictionaryObject, xobjs[id[0]]))
+
+    @property
+    def images(self) -> List[ImageFile]:
+        """
+        Read-only property emulating a list of images on a page.
+
+        Get a list of all images on the page. The key can be:
+        - A string (for the top object)
+        - A tuple (for images within XObject forms)
+        - An integer
+
+        Examples:
+            reader.pages[0].images[0]        # return fist image
+            reader.pages[0].images['/I0']    # return image '/I0'
+            # return image '/Image1' within '/TP1' Xobject/Form:
+            reader.pages[0].images['/TP1','/Image1']
+            for img in reader.pages[0].images: # loop within all objects
+
+        images.keys() and images.items() can be used.
+
+        The ImageFile has the following properties:
+
+            `.name` : name of the object
+            `.data` : bytes of the object
+            `.image`  : PIL Image Object
+            `.indirect_reference` : object reference
+
+        and the following methods:
+            `.replace(new_image: PIL.Image.Image, **kwargs)` :
+                replace the image in the pdf with the new image
+                applying the saving parameters indicated (such as quality)
+
+        Example usage:
+
+            reader.pages[0].images[0]=replace(Image.open("new_image.jpg", quality = 20)
+
+        Inline images are extracted and named ~0~, ~1~, ..., with the
+        indirect_reference set to None.
+        """
+        return _VirtualListImages(self._get_ids_image, self._get_image)  # type: ignore
+
+    def _translate_value_inlineimage(self, k: str, v: PdfObject) -> PdfObject:
+        """Translate values used in inline image"""
+        try:
+            v = NameObject(
+                {
+                    "/G": "/DeviceGray",
+                    "/RGB": "/DeviceRGB",
+                    "/CMYK": "/DeviceCMYK",
+                    "/I": "/Indexed",
+                    "/AHx": "/ASCIIHexDecode",
+                    "/A85": "/ASCII85Decode",
+                    "/LZW": "/LZWDecode",
+                    "/Fl": "/FlateDecode",
+                    "/RL": "/RunLengthDecode",
+                    "/CCF": "/CCITTFaxDecode",
+                    "/DCT": "/DCTDecode",
+                    "/DeviceGray": "/DeviceGray",
+                    "/DeviceRGB": "/DeviceRGB",
+                    "/DeviceCMYK": "/DeviceCMYK",
+                    "/Indexed": "/Indexed",
+                    "/ASCIIHexDecode": "/ASCIIHexDecode",
+                    "/ASCII85Decode": "/ASCII85Decode",
+                    "/LZWDecode": "/LZWDecode",
+                    "/FlateDecode": "/FlateDecode",
+                    "/RunLengthDecode": "/RunLengthDecode",
+                    "/CCITTFaxDecode": "/CCITTFaxDecode",
+                    "/DCTDecode": "/DCTDecode",
+                }[cast(str, v)]
+            )
+        except (TypeError, KeyError):
+            if isinstance(v, NameObject):
+                # It is a custom name, thus we have to look in resources.
+                # The only applicable case is for ColorSpace.
+                try:
+                    res = cast(DictionaryObject, self["/Resources"])["/ColorSpace"]
+                    v = cast(DictionaryObject, res)[v]
+                except KeyError:  # for res and v
+                    raise PdfReadError(f"Cannot find resource entry {v} for {k}")
+        return v
+
+    def _get_inline_images(self) -> Dict[str, ImageFile]:
+        """
+        get inline_images
+        entries will be identified as ~1~
+        """
+        content = self.get_contents()
+        if content is None:
+            return {}
+        imgs_data = []
+        for param, ope in content.operations:
+            if ope == b"INLINE IMAGE":
+                imgs_data.append(
+                    {"settings": param["settings"], "__streamdata__": param["data"]}
+                )
+            elif ope in (b"BI", b"EI", b"ID"):  # pragma: no cover
+                raise PdfReadError(
+                    f"{ope} operator met whereas not expected,"
+                    "please share usecase with pypdf dev team"
+                )
+            """backup
+            elif ope == b"BI":
+                img_data["settings"] = {}
+            elif ope == b"EI":
+                imgs_data.append(img_data)
+                img_data = {}
+            elif ope == b"ID":
+                img_data["__streamdata__"] = b""
+            elif "__streamdata__" in img_data:
+                if len(img_data["__streamdata__"]) > 0:
+                    img_data["__streamdata__"] += b"\n"
+                    raise Exception("check append")
+                img_data["__streamdata__"] += param
+            elif "settings" in img_data:
+                img_data["settings"][ope.decode()] = param
+            """
+        files = {}
+        for num, ii in enumerate(imgs_data):
+            init = {
+                "__streamdata__": ii["__streamdata__"],
+                "/Length": len(ii["__streamdata__"]),
+            }
+            for k, v in ii["settings"].items():
+                if k in {"/Length", "/L"}:  # no length is expected
+                    continue
+                if isinstance(v, list):
+                    v = ArrayObject(
+                        [self._translate_value_inlineimage(k, x) for x in v]
+                    )
+                else:
+                    v = self._translate_value_inlineimage(k, v)
+                k = NameObject(
+                    {
+                        "/BPC": "/BitsPerComponent",
+                        "/CS": "/ColorSpace",
+                        "/D": "/Decode",
+                        "/DP": "/DecodeParms",
+                        "/F": "/Filter",
+                        "/H": "/Height",
+                        "/W": "/Width",
+                        "/I": "/Interpolate",
+                        "/Intent": "/Intent",
+                        "/IM": "/ImageMask",
+                        "/BitsPerComponent": "/BitsPerComponent",
+                        "/ColorSpace": "/ColorSpace",
+                        "/Decode": "/Decode",
+                        "/DecodeParms": "/DecodeParms",
+                        "/Filter": "/Filter",
+                        "/Height": "/Height",
+                        "/Width": "/Width",
+                        "/Interpolate": "/Interpolate",
+                        "/ImageMask": "/ImageMask",
+                    }[k]
+                )
+                if k not in init:
+                    init[k] = v
+            ii["object"] = EncodedStreamObject.initialize_from_dictionary(init)
+            extension, byte_stream, img = _xobj_to_image(ii["object"])
+            files[f"~{num}~"] = ImageFile(
+                name=f"~{num}~{extension}",
+                data=byte_stream,
+                image=img,
+                indirect_reference=None,
+            )
+        return files
+
+    @property
+    def rotation(self) -> int:
+        """
+        The visual rotation of the page.
+
+        This number has to be a multiple of 90 degrees: 0, 90, 180, or 270 are
+        valid values. This property does not affect ``/Contents``.
+        """
+        rotate_obj = self.get(PG.ROTATE, 0)
+        return rotate_obj if isinstance(rotate_obj, int) else rotate_obj.get_object()
+
+    @rotation.setter
+    def rotation(self, r: float) -> None:
+        self[NameObject(PG.ROTATE)] = NumberObject((((int(r) + 45) // 90) * 90) % 360)
+
+    def transfer_rotation_to_content(self) -> None:
+        """
+        Apply the rotation of the page to the content and the media/crop/...
+        boxes.
+
+        It is recommended to apply this function before page merging.
+        """
+        r = -self.rotation  # rotation to apply is in the otherway
+        self.rotation = 0
+        mb = RectangleObject(self.mediabox)
+        trsf = (
+            Transformation()
+            .translate(
+                -float(mb.left + mb.width / 2), -float(mb.bottom + mb.height / 2)
+            )
+            .rotate(r)
+        )
+        pt1 = trsf.apply_on(mb.lower_left)
+        pt2 = trsf.apply_on(mb.upper_right)
+        trsf = trsf.translate(-min(pt1[0], pt2[0]), -min(pt1[1], pt2[1]))
+        self.add_transformation(trsf, False)
+        for b in ["/MediaBox", "/CropBox", "/BleedBox", "/TrimBox", "/ArtBox"]:
+            if b in self:
+                rr = RectangleObject(self[b])  # type: ignore
+                pt1 = trsf.apply_on(rr.lower_left)
+                pt2 = trsf.apply_on(rr.upper_right)
+                self[NameObject(b)] = RectangleObject(
+                    (
+                        min(pt1[0], pt2[0]),
+                        min(pt1[1], pt2[1]),
+                        max(pt1[0], pt2[0]),
+                        max(pt1[1], pt2[1]),
+                    )
+                )
+
+    def rotate(self, angle: int) -> "PageObject":
+        """
+        Rotate a page clockwise by increments of 90 degrees.
+
+        Args:
+            angle: Angle to rotate the page. Must be an increment of 90 deg.
+
+        Returns:
+            The rotated PageObject
+        """
+        if angle % 90 != 0:
+            raise ValueError("Rotation angle must be a multiple of 90")
+        self[NameObject(PG.ROTATE)] = NumberObject(self.rotation + angle)
+        return self
+
+    def _merge_resources(
+        self,
+        res1: DictionaryObject,
+        res2: DictionaryObject,
+        resource: Any,
+        new_res1: bool = True,
+    ) -> Tuple[Dict[str, Any], Dict[str, Any]]:
+        try:
+            assert isinstance(self.indirect_reference, IndirectObject)
+            pdf = self.indirect_reference.pdf
+            is_pdf_writer = hasattr(
+                pdf, "_add_object"
+            )  # ---------- expect isinstance(pdf,PdfWriter)
+        except (AssertionError, AttributeError):
+            pdf = None
+            is_pdf_writer = False
+
+        def compute_unique_key(base_key: str) -> Tuple[str, bool]:
+            """
+            Find a key that either doesn't already exist or has the same value
+            (indicated by the bool)
+
+            Args:
+                base_key: An index is added to this to get the computed key
+
+            Returns:
+                A tuple (computed key, bool) where the boolean indicates
+                if there is a resource of the given computed_key with the same
+                value.
+            """
+            value = page2res.raw_get(base_key)
+            # TODO : possible improvement : in case of writer, the indirect_reference
+            # can not be found because translated : this may be improved
+
+            # try the current key first (e.g. "foo"), but otherwise iterate
+            # through "foo-0", "foo-1", etc. new_res can contain only finitely
+            # many keys, thus this'll eventually end, even if it's been crafted
+            # to be maximally annoying.
+            computed_key = base_key
+            idx = 0
+            while computed_key in new_res:
+                if new_res.raw_get(computed_key) == value:
+                    # there's already a resource of this name, with the exact
+                    # same value
+                    return computed_key, True
+                computed_key = f"{base_key}-{idx}"
+                idx += 1
+            return computed_key, False
+
+        if new_res1:
+            new_res = DictionaryObject()
+            new_res.update(res1.get(resource, DictionaryObject()).get_object())
+        else:
+            new_res = cast(DictionaryObject, res1[resource])
+        page2res = cast(
+            DictionaryObject, res2.get(resource, DictionaryObject()).get_object()
+        )
+        rename_res = {}
+        for key in page2res:
+            unique_key, same_value = compute_unique_key(key)
+            newname = NameObject(unique_key)
+            if key != unique_key:
+                # we have to use a different name for this
+                rename_res[key] = newname
+
+            if not same_value:
+                if is_pdf_writer:
+                    new_res[newname] = page2res.raw_get(key).clone(pdf)
+                    try:
+                        new_res[newname] = new_res[newname].indirect_reference
+                    except AttributeError:
+                        pass
+                else:
+                    new_res[newname] = page2res.raw_get(key)
+            lst = sorted(new_res.items())
+            new_res.clear()
+            for el in lst:
+                new_res[el[0]] = el[1]
+        return new_res, rename_res
+
+    @staticmethod
+    def _content_stream_rename(
+        stream: ContentStream,
+        rename: Dict[Any, Any],
+        pdf: Optional[PdfCommonDocProtocol],
+    ) -> ContentStream:
+        if not rename:
+            return stream
+        stream = ContentStream(stream, pdf)
+        for operands, _operator in stream.operations:
+            if isinstance(operands, list):
+                for i, op in enumerate(operands):
+                    if isinstance(op, NameObject):
+                        operands[i] = rename.get(op, op)
+            elif isinstance(operands, dict):
+                for i, op in operands.items():
+                    if isinstance(op, NameObject):
+                        operands[i] = rename.get(op, op)
+            else:
+                raise KeyError(f"type of operands is {type(operands)}")
+        return stream
+
+    @staticmethod
+    def _add_transformation_matrix(
+        contents: Any,
+        pdf: Optional[PdfCommonDocProtocol],
+        ctm: CompressedTransformationMatrix,
+    ) -> ContentStream:
+        """Add transformation matrix at the beginning of the given contents stream."""
+        a, b, c, d, e, f = ctm
+        contents = ContentStream(contents, pdf)
+        contents.operations.insert(
+            0,
+            [
+                [
+                    FloatObject(a),
+                    FloatObject(b),
+                    FloatObject(c),
+                    FloatObject(d),
+                    FloatObject(e),
+                    FloatObject(f),
+                ],
+                " cm",
+            ],
+        )
+        return contents
+
+    def _get_contents_as_bytes(self) -> Optional[bytes]:
+        """
+        Return the page contents as bytes.
+
+        Returns:
+            The ``/Contents`` object as bytes, or ``None`` if it doesn't exist.
+
+        """
+        if PG.CONTENTS in self:
+            obj = self[PG.CONTENTS].get_object()
+            if isinstance(obj, list):
+                return b"".join(x.get_object().get_data() for x in obj)
+            else:
+                return cast(bytes, cast(EncodedStreamObject, obj).get_data())
+        else:
+            return None
+
+    def get_contents(self) -> Optional[ContentStream]:
+        """
+        Access the page contents.
+
+        Returns:
+            The ``/Contents`` object, or ``None`` if it does not exist.
+            ``/Contents`` is optional, as described in §7.7.3.3 of the PDF Reference.
+        """
+        if PG.CONTENTS in self:
+            try:
+                pdf = cast(IndirectObject, self.indirect_reference).pdf
+            except AttributeError:
+                pdf = None
+            obj = self[PG.CONTENTS].get_object()
+            if isinstance(obj, NullObject):
+                return None
+            else:
+                return ContentStream(obj, pdf)
+        else:
+            return None
+
+    def replace_contents(
+        self, content: Union[None, ContentStream, EncodedStreamObject, ArrayObject]
+    ) -> None:
+        """
+        Replace the page contents with the new content and nullify old objects
+        Args:
+            content: new content; if None delete the content field.
+        """
+        if not hasattr(self, "indirect_reference") or self.indirect_reference is None:
+            # the page is not attached : the content is directly attached.
+            self[NameObject(PG.CONTENTS)] = content
+            return
+        if isinstance(self.get(PG.CONTENTS, None), ArrayObject):
+            for o in self[PG.CONTENTS]:  # type: ignore[attr-defined]
+                try:
+                    self._objects[o.indirect_reference.idnum - 1] = NullObject()  # type: ignore
+                except AttributeError:
+                    pass
+
+        if isinstance(content, ArrayObject):
+            for i in range(len(content)):
+                content[i] = self.indirect_reference.pdf._add_object(content[i])
+
+        if content is None:
+            if PG.CONTENTS not in self:
+                return
+            else:
+                assert self.indirect_reference is not None
+                assert self[PG.CONTENTS].indirect_reference is not None
+                self.indirect_reference.pdf._objects[
+                    self[PG.CONTENTS].indirect_reference.idnum - 1  # type: ignore
+                ] = NullObject()
+                del self[PG.CONTENTS]
+        elif not hasattr(self.get(PG.CONTENTS, None), "indirect_reference"):
+            try:
+                self[NameObject(PG.CONTENTS)] = self.indirect_reference.pdf._add_object(
+                    content
+                )
+            except AttributeError:
+                # applies at least for page not in writer
+                # as a backup solution, we put content as an object although not in accordance with pdf ref
+                # this will be fixed with the _add_object
+                self[NameObject(PG.CONTENTS)] = content
+        else:
+            content.indirect_reference = self[
+                PG.CONTENTS
+            ].indirect_reference  # TODO: in a future may required generation management
+            try:
+                self.indirect_reference.pdf._objects[
+                    content.indirect_reference.idnum - 1  # type: ignore
+                ] = content
+            except AttributeError:
+                # applies at least for page not in writer
+                # as a backup solution, we put content as an object although not in accordance with pdf ref
+                # this will be fixed with the _add_object
+                self[NameObject(PG.CONTENTS)] = content
+        # forces recalculation of inline_images
+        self.inline_images = None
+
+    def merge_page(
+        self, page2: "PageObject", expand: bool = False, over: bool = True
+    ) -> None:
+        """
+        Merge the content streams of two pages into one.
+
+        Resource references
+        (i.e. fonts) are maintained from both pages. The mediabox/cropbox/etc
+        of this page are not altered. The parameter page's content stream will
+        be added to the end of this page's content stream, meaning that it will
+        be drawn after, or "on top" of this page.
+
+        Args:
+            page2: The page to be merged into this one. Should be
+                an instance of :class:`PageObject<PageObject>`.
+            over: set the page2 content over page1 if True (default) else under
+            expand: If True, the current page dimensions will be
+                expanded to accommodate the dimensions of the page to be merged.
+        """
+        self._merge_page(page2, over=over, expand=expand)
+
+    def _merge_page(
+        self,
+        page2: "PageObject",
+        page2transformation: Optional[Callable[[Any], ContentStream]] = None,
+        ctm: Optional[CompressedTransformationMatrix] = None,
+        over: bool = True,
+        expand: bool = False,
+    ) -> None:
+        # First we work on merging the resource dictionaries. This allows us
+        # to find out what symbols in the content streams we might need to
+        # rename.
+        try:
+            assert isinstance(self.indirect_reference, IndirectObject)
+            if hasattr(
+                self.indirect_reference.pdf, "_add_object"
+            ):  # ---------- to detect PdfWriter
+                return self._merge_page_writer(
+                    page2, page2transformation, ctm, over, expand
+                )
+        except (AssertionError, AttributeError):
+            pass
+
+        new_resources = DictionaryObject()
+        rename = {}
+        try:
+            original_resources = cast(DictionaryObject, self[PG.RESOURCES].get_object())
+        except KeyError:
+            original_resources = DictionaryObject()
+        try:
+            page2resources = cast(DictionaryObject, page2[PG.RESOURCES].get_object())
+        except KeyError:
+            page2resources = DictionaryObject()
+        new_annots = ArrayObject()
+
+        for page in (self, page2):
+            if PG.ANNOTS in page:
+                annots = page[PG.ANNOTS]
+                if isinstance(annots, ArrayObject):
+                    new_annots.extend(annots)
+
+        for res in (
+            RES.EXT_G_STATE,
+            RES.FONT,
+            RES.XOBJECT,
+            RES.COLOR_SPACE,
+            RES.PATTERN,
+            RES.SHADING,
+            RES.PROPERTIES,
+        ):
+            new, newrename = self._merge_resources(
+                original_resources, page2resources, res
+            )
+            if new:
+                new_resources[NameObject(res)] = new
+                rename.update(newrename)
+
+        # Combine /ProcSet sets, making sure there's a consistent order
+        new_resources[NameObject(RES.PROC_SET)] = ArrayObject(
+            sorted(
+                set(
+                    original_resources.get(RES.PROC_SET, ArrayObject()).get_object()
+                ).union(
+                    set(page2resources.get(RES.PROC_SET, ArrayObject()).get_object())
+                )
+            )
+        )
+
+        new_content_array = ArrayObject()
+        original_content = self.get_contents()
+        if original_content is not None:
+            original_content.isolate_graphics_state()
+            new_content_array.append(original_content)
+
+        page2content = page2.get_contents()
+        if page2content is not None:
+            rect = getattr(page2, MERGE_CROP_BOX)
+            page2content.operations.insert(
+                0,
+                (
+                    map(
+                        FloatObject,
+                        [
+                            rect.left,
+                            rect.bottom,
+                            rect.width,
+                            rect.height,
+                        ],
+                    ),
+                    "re",
+                ),
+            )
+            page2content.operations.insert(1, ([], "W"))
+            page2content.operations.insert(2, ([], "n"))
+            if page2transformation is not None:
+                page2content = page2transformation(page2content)
+            page2content = PageObject._content_stream_rename(
+                page2content, rename, self.pdf
+            )
+            page2content.isolate_graphics_state()
+            if over:
+                new_content_array.append(page2content)
+            else:
+                new_content_array.insert(0, page2content)
+
+        # if expanding the page to fit a new page, calculate the new media box size
+        if expand:
+            self._expand_mediabox(page2, ctm)
+
+        self.replace_contents(ContentStream(new_content_array, self.pdf))
+        self[NameObject(PG.RESOURCES)] = new_resources
+        self[NameObject(PG.ANNOTS)] = new_annots
+
+    def _merge_page_writer(
+        self,
+        page2: "PageObject",
+        page2transformation: Optional[Callable[[Any], ContentStream]] = None,
+        ctm: Optional[CompressedTransformationMatrix] = None,
+        over: bool = True,
+        expand: bool = False,
+    ) -> None:
+        # First we work on merging the resource dictionaries. This allows us
+        # to find which symbols in the content streams we might need to
+        # rename.
+        assert isinstance(self.indirect_reference, IndirectObject)
+        pdf = self.indirect_reference.pdf
+
+        rename = {}
+        if PG.RESOURCES not in self:
+            self[NameObject(PG.RESOURCES)] = DictionaryObject()
+        original_resources = cast(DictionaryObject, self[PG.RESOURCES].get_object())
+        if PG.RESOURCES not in page2:
+            page2resources = DictionaryObject()
+        else:
+            page2resources = cast(DictionaryObject, page2[PG.RESOURCES].get_object())
+
+        for res in (
+            RES.EXT_G_STATE,
+            RES.FONT,
+            RES.XOBJECT,
+            RES.COLOR_SPACE,
+            RES.PATTERN,
+            RES.SHADING,
+            RES.PROPERTIES,
+        ):
+            if res in page2resources:
+                if res not in original_resources:
+                    original_resources[NameObject(res)] = DictionaryObject()
+                _, newrename = self._merge_resources(
+                    original_resources, page2resources, res, False
+                )
+                rename.update(newrename)
+        # Combine /ProcSet sets.
+        if RES.PROC_SET in page2resources:
+            if RES.PROC_SET not in original_resources:
+                original_resources[NameObject(RES.PROC_SET)] = ArrayObject()
+            arr = cast(ArrayObject, original_resources[RES.PROC_SET])
+            for x in cast(ArrayObject, page2resources[RES.PROC_SET]):
+                if x not in arr:
+                    arr.append(x)
+            arr.sort()
+
+        if PG.ANNOTS in page2:
+            if PG.ANNOTS not in self:
+                self[NameObject(PG.ANNOTS)] = ArrayObject()
+            annots = cast(ArrayObject, self[PG.ANNOTS].get_object())
+            if ctm is None:
+                trsf = Transformation()
+            else:
+                trsf = Transformation(ctm)
+            for a in cast(ArrayObject, page2[PG.ANNOTS]):
+                a = a.get_object()
+                aa = a.clone(
+                    pdf,
+                    ignore_fields=("/P", "/StructParent", "/Parent"),
+                    force_duplicate=True,
+                )
+                r = cast(ArrayObject, a["/Rect"])
+                pt1 = trsf.apply_on((r[0], r[1]), True)
+                pt2 = trsf.apply_on((r[2], r[3]), True)
+                aa[NameObject("/Rect")] = ArrayObject(
+                    (
+                        min(pt1[0], pt2[0]),
+                        min(pt1[1], pt2[1]),
+                        max(pt1[0], pt2[0]),
+                        max(pt1[1], pt2[1]),
+                    )
+                )
+                if "/QuadPoints" in a:
+                    q = cast(ArrayObject, a["/QuadPoints"])
+                    aa[NameObject("/QuadPoints")] = ArrayObject(
+                        trsf.apply_on((q[0], q[1]), True)
+                        + trsf.apply_on((q[2], q[3]), True)
+                        + trsf.apply_on((q[4], q[5]), True)
+                        + trsf.apply_on((q[6], q[7]), True)
+                    )
+                try:
+                    aa["/Popup"][NameObject("/Parent")] = aa.indirect_reference
+                except KeyError:
+                    pass
+                try:
+                    aa[NameObject("/P")] = self.indirect_reference
+                    annots.append(aa.indirect_reference)
+                except AttributeError:
+                    pass
+
+        new_content_array = ArrayObject()
+        original_content = self.get_contents()
+        if original_content is not None:
+            original_content.isolate_graphics_state()
+            new_content_array.append(original_content)
+
+        page2content = page2.get_contents()
+        if page2content is not None:
+            rect = getattr(page2, MERGE_CROP_BOX)
+            page2content.operations.insert(
+                0,
+                (
+                    map(
+                        FloatObject,
+                        [
+                            rect.left,
+                            rect.bottom,
+                            rect.width,
+                            rect.height,
+                        ],
+                    ),
+                    "re",
+                ),
+            )
+            page2content.operations.insert(1, ([], "W"))
+            page2content.operations.insert(2, ([], "n"))
+            if page2transformation is not None:
+                page2content = page2transformation(page2content)
+            page2content = PageObject._content_stream_rename(
+                page2content, rename, self.pdf
+            )
+            page2content.isolate_graphics_state()
+            if over:
+                new_content_array.append(page2content)
+            else:
+                new_content_array.insert(0, page2content)
+
+        # if expanding the page to fit a new page, calculate the new media box size
+        if expand:
+            self._expand_mediabox(page2, ctm)
+
+        self.replace_contents(new_content_array)
+        # self[NameObject(PG.CONTENTS)] = ContentStream(new_content_array, pdf)
+        # self[NameObject(PG.RESOURCES)] = new_resources
+        # self[NameObject(PG.ANNOTS)] = new_annots
+
+    def _expand_mediabox(
+        self, page2: "PageObject", ctm: Optional[CompressedTransformationMatrix]
+    ) -> None:
+        corners1 = (
+            self.mediabox.left.as_numeric(),
+            self.mediabox.bottom.as_numeric(),
+            self.mediabox.right.as_numeric(),
+            self.mediabox.top.as_numeric(),
+        )
+        corners2 = (
+            page2.mediabox.left.as_numeric(),
+            page2.mediabox.bottom.as_numeric(),
+            page2.mediabox.left.as_numeric(),
+            page2.mediabox.top.as_numeric(),
+            page2.mediabox.right.as_numeric(),
+            page2.mediabox.top.as_numeric(),
+            page2.mediabox.right.as_numeric(),
+            page2.mediabox.bottom.as_numeric(),
+        )
+        if ctm is not None:
+            ctm = tuple(float(x) for x in ctm)  # type: ignore[assignment]
+            new_x = tuple(
+                ctm[0] * corners2[i] + ctm[2] * corners2[i + 1] + ctm[4]
+                for i in range(0, 8, 2)
+            )
+            new_y = tuple(
+                ctm[1] * corners2[i] + ctm[3] * corners2[i + 1] + ctm[5]
+                for i in range(0, 8, 2)
+            )
+        else:
+            new_x = corners2[0:8:2]
+            new_y = corners2[1:8:2]
+        lowerleft = (min(new_x), min(new_y))
+        upperright = (max(new_x), max(new_y))
+        lowerleft = (min(corners1[0], lowerleft[0]), min(corners1[1], lowerleft[1]))
+        upperright = (
+            max(corners1[2], upperright[0]),
+            max(corners1[3], upperright[1]),
+        )
+
+        self.mediabox.lower_left = lowerleft
+        self.mediabox.upper_right = upperright
+
+    def merge_transformed_page(
+        self,
+        page2: "PageObject",
+        ctm: Union[CompressedTransformationMatrix, Transformation],
+        over: bool = True,
+        expand: bool = False,
+    ) -> None:
+        """
+        merge_transformed_page is similar to merge_page, but a transformation
+        matrix is applied to the merged stream.
+
+        Args:
+          page2: The page to be merged into this one.
+          ctm: a 6-element tuple containing the operands of the
+                 transformation matrix
+          over: set the page2 content over page1 if True (default) else under
+          expand: Whether the page should be expanded to fit the dimensions
+            of the page to be merged.
+        """
+        if isinstance(ctm, Transformation):
+            ctm = ctm.ctm
+        self._merge_page(
+            page2,
+            lambda page2Content: PageObject._add_transformation_matrix(
+                page2Content, page2.pdf, cast(CompressedTransformationMatrix, ctm)
+            ),
+            ctm,
+            over,
+            expand,
+        )
+
+    def merge_scaled_page(
+        self, page2: "PageObject", scale: float, over: bool = True, expand: bool = False
+    ) -> None:
+        """
+        merge_scaled_page is similar to merge_page, but the stream to be merged
+        is scaled by applying a transformation matrix.
+
+        Args:
+          page2: The page to be merged into this one.
+          scale: The scaling factor
+          over: set the page2 content over page1 if True (default) else under
+          expand: Whether the page should be expanded to fit the
+            dimensions of the page to be merged.
+        """
+        op = Transformation().scale(scale, scale)
+        self.merge_transformed_page(page2, op, over, expand)
+
+    def merge_rotated_page(
+        self,
+        page2: "PageObject",
+        rotation: float,
+        over: bool = True,
+        expand: bool = False,
+    ) -> None:
+        """
+        merge_rotated_page is similar to merge_page, but the stream to be merged
+        is rotated by applying a transformation matrix.
+
+        Args:
+          page2: The page to be merged into this one.
+          rotation: The angle of the rotation, in degrees
+          over: set the page2 content over page1 if True (default) else under
+          expand: Whether the page should be expanded to fit the
+            dimensions of the page to be merged.
+        """
+        op = Transformation().rotate(rotation)
+        self.merge_transformed_page(page2, op, over, expand)
+
+    def merge_translated_page(
+        self,
+        page2: "PageObject",
+        tx: float,
+        ty: float,
+        over: bool = True,
+        expand: bool = False,
+    ) -> None:
+        """
+        mergeTranslatedPage is similar to merge_page, but the stream to be
+        merged is translated by applying a transformation matrix.
+
+        Args:
+          page2: the page to be merged into this one.
+          tx: The translation on X axis
+          ty: The translation on Y axis
+          over: set the page2 content over page1 if True (default) else under
+          expand: Whether the page should be expanded to fit the
+            dimensions of the page to be merged.
+        """
+        op = Transformation().translate(tx, ty)
+        self.merge_transformed_page(page2, op, over, expand)
+
+    def add_transformation(
+        self,
+        ctm: Union[Transformation, CompressedTransformationMatrix],
+        expand: bool = False,
+    ) -> None:
+        """
+        Apply a transformation matrix to the page.
+
+        Args:
+            ctm: A 6-element tuple containing the operands of the
+                transformation matrix. Alternatively, a
+                :py:class:`Transformation<pypdf.Transformation>`
+                object can be passed.
+
+        See :doc:`/user/cropping-and-transforming`.
+        """
+        if isinstance(ctm, Transformation):
+            ctm = ctm.ctm
+        content = self.get_contents()
+        if content is not None:
+            content = PageObject._add_transformation_matrix(content, self.pdf, ctm)
+            content.isolate_graphics_state()
+            self.replace_contents(content)
+        # if expanding the page to fit a new page, calculate the new media box size
+        if expand:
+            corners = [
+                self.mediabox.left.as_numeric(),
+                self.mediabox.bottom.as_numeric(),
+                self.mediabox.left.as_numeric(),
+                self.mediabox.top.as_numeric(),
+                self.mediabox.right.as_numeric(),
+                self.mediabox.top.as_numeric(),
+                self.mediabox.right.as_numeric(),
+                self.mediabox.bottom.as_numeric(),
+            ]
+
+            ctm = tuple(float(x) for x in ctm)  # type: ignore[assignment]
+            new_x = [
+                ctm[0] * corners[i] + ctm[2] * corners[i + 1] + ctm[4]
+                for i in range(0, 8, 2)
+            ]
+            new_y = [
+                ctm[1] * corners[i] + ctm[3] * corners[i + 1] + ctm[5]
+                for i in range(0, 8, 2)
+            ]
+
+            lowerleft = (min(new_x), min(new_y))
+            upperright = (max(new_x), max(new_y))
+
+            self.mediabox.lower_left = lowerleft
+            self.mediabox.upper_right = upperright
+
+    def scale(self, sx: float, sy: float) -> None:
+        """
+        Scale a page by the given factors by applying a transformation matrix
+        to its content and updating the page size.
+
+        This updates the mediabox, the cropbox, and the contents
+        of the page.
+
+        Args:
+            sx: The scaling factor on horizontal axis.
+            sy: The scaling factor on vertical axis.
+        """
+        self.add_transformation((sx, 0, 0, sy, 0, 0))
+        self.cropbox = self.cropbox.scale(sx, sy)
+        self.artbox = self.artbox.scale(sx, sy)
+        self.bleedbox = self.bleedbox.scale(sx, sy)
+        self.trimbox = self.trimbox.scale(sx, sy)
+        self.mediabox = self.mediabox.scale(sx, sy)
+
+        if PG.ANNOTS in self:
+            annotations = self[PG.ANNOTS]
+            if isinstance(annotations, ArrayObject):
+                for annotation in annotations:
+                    annotation_obj = annotation.get_object()
+                    if ADA.Rect in annotation_obj:
+                        rectangle = annotation_obj[ADA.Rect]
+                        if isinstance(rectangle, ArrayObject):
+                            rectangle[0] = FloatObject(float(rectangle[0]) * sx)
+                            rectangle[1] = FloatObject(float(rectangle[1]) * sy)
+                            rectangle[2] = FloatObject(float(rectangle[2]) * sx)
+                            rectangle[3] = FloatObject(float(rectangle[3]) * sy)
+
+        if PG.VP in self:
+            viewport = self[PG.VP]
+            if isinstance(viewport, ArrayObject):
+                bbox = viewport[0]["/BBox"]
+            else:
+                bbox = viewport["/BBox"]  # type: ignore
+            scaled_bbox = RectangleObject(
+                (
+                    float(bbox[0]) * sx,
+                    float(bbox[1]) * sy,
+                    float(bbox[2]) * sx,
+                    float(bbox[3]) * sy,
+                )
+            )
+            if isinstance(viewport, ArrayObject):
+                self[NameObject(PG.VP)][NumberObject(0)][  # type: ignore
+                    NameObject("/BBox")
+                ] = scaled_bbox
+            else:
+                self[NameObject(PG.VP)][NameObject("/BBox")] = scaled_bbox  # type: ignore
+
+    def scale_by(self, factor: float) -> None:
+        """
+        Scale a page by the given factor by applying a transformation matrix to
+        its content and updating the page size.
+
+        Args:
+            factor: The scaling factor (for both X and Y axis).
+        """
+        self.scale(factor, factor)
+
+    def scale_to(self, width: float, height: float) -> None:
+        """
+        Scale a page to the specified dimensions by applying a transformation
+        matrix to its content and updating the page size.
+
+        Args:
+            width: The new width.
+            height: The new height.
+        """
+        sx = width / float(self.mediabox.width)
+        sy = height / float(self.mediabox.height)
+        self.scale(sx, sy)
+
+    def compress_content_streams(self, level: int = -1) -> None:
+        """
+        Compress the size of this page by joining all content streams and
+        applying a FlateDecode filter.
+
+        However, it is possible that this function will perform no action if
+        content stream compression becomes "automatic".
+        """
+        content = self.get_contents()
+        if content is not None:
+            content_obj = content.flate_encode(level)
+            try:
+                content.indirect_reference.pdf._objects[  # type: ignore
+                    content.indirect_reference.idnum - 1  # type: ignore
+                ] = content_obj
+            except AttributeError:
+                if self.indirect_reference is not None and hasattr(
+                    self.indirect_reference.pdf, "_add_object"
+                ):
+                    self.replace_contents(content_obj)
+                else:
+                    raise ValueError("Page must be part of a PdfWriter")
+
+    @property
+    def page_number(self) -> Optional[int]:
+        """
+        Read-only property which returns the page number within the PDF file.
+
+        Returns:
+            int : page number; None if the page is not attached to a PDF.
+        """
+        if self.indirect_reference is None:
+            return None
+        else:
+            try:
+                lst = self.indirect_reference.pdf.pages
+                return lst.index(self)
+            except ValueError:
+                return None
+
+    def _debug_for_extract(self) -> str:  # pragma: no cover
+        out = ""
+        for ope, op in ContentStream(
+            self["/Contents"].get_object(), self.pdf, "bytes"
+        ).operations:
+            if op == b"TJ":
+                s = [x for x in ope[0] if isinstance(x, str)]
+            else:
+                s = []
+            out += op.decode("utf-8") + " " + "".join(s) + ope.__repr__() + "\n"
+        out += "\n=============================\n"
+        try:
+            for fo in self[PG.RESOURCES]["/Font"]:  # type:ignore
+                out += fo + "\n"
+                out += self[PG.RESOURCES]["/Font"][fo].__repr__() + "\n"  # type:ignore
+                try:
+                    enc_repr = self[PG.RESOURCES]["/Font"][fo][  # type:ignore
+                        "/Encoding"
+                    ].__repr__()
+                    out += enc_repr + "\n"
+                except Exception:
+                    pass
+                try:
+                    out += (
+                        self[PG.RESOURCES]["/Font"][fo][  # type:ignore
+                            "/ToUnicode"
+                        ]
+                        .get_data()
+                        .decode()
+                        + "\n"
+                    )
+                except Exception:
+                    pass
+
+        except KeyError:
+            out += "No Font\n"
+        return out
+
+    def _extract_text(
+        self,
+        obj: Any,
+        pdf: Any,
+        orientations: Tuple[int, ...] = (0, 90, 180, 270),
+        space_width: float = 200.0,
+        content_key: Optional[str] = PG.CONTENTS,
+        visitor_operand_before: Optional[Callable[[Any, Any, Any, Any], None]] = None,
+        visitor_operand_after: Optional[Callable[[Any, Any, Any, Any], None]] = None,
+        visitor_text: Optional[Callable[[Any, Any, Any, Any, Any], None]] = None,
+    ) -> str:
+        """
+        See extract_text for most arguments.
+
+        Args:
+            content_key: indicate the default key where to extract data
+                None = the object; this allow to reuse the function on XObject
+                default = "/Content"
+        """
+        text: str = ""
+        output: str = ""
+        rtl_dir: bool = False  # right-to-left
+        cmaps: Dict[
+            str,
+            Tuple[
+                str, float, Union[str, Dict[int, str]], Dict[str, str], DictionaryObject
+            ],
+        ] = {}
+        try:
+            objr = obj
+            while NameObject(PG.RESOURCES) not in objr:
+                # /Resources can be inherited sometimes so we look to parents
+                objr = objr["/Parent"].get_object()
+                # if no parents we will have no /Resources will be available
+                # => an exception will be raised
+            resources_dict = cast(DictionaryObject, objr[PG.RESOURCES])
+        except Exception:
+            # no resources means no text is possible (no font) we consider the
+            # file as not damaged, no need to check for TJ or Tj
+            return ""
+        if "/Font" in resources_dict:
+            for f in cast(DictionaryObject, resources_dict["/Font"]):
+                cmaps[f] = build_char_map(f, space_width, obj)
+        cmap: Tuple[
+            Union[str, Dict[int, str]], Dict[str, str], str, Optional[DictionaryObject]
+        ] = (
+            "charmap",
+            {},
+            "NotInitialized",
+            None,
+        )  # (encoding,CMAP,font resource name,dictionary-object of font)
+        try:
+            content = (
+                obj[content_key].get_object() if isinstance(content_key, str) else obj
+            )
+            if not isinstance(content, ContentStream):
+                content = ContentStream(content, pdf, "bytes")
+        except KeyError:  # it means no content can be extracted(certainly empty page)
+            return ""
+        # Note: we check all strings are TextStringObjects. ByteStringObjects
+        # are strings where the byte->string encoding was unknown, so adding
+        # them to the text here would be gibberish.
+
+        cm_matrix: List[float] = [1.0, 0.0, 0.0, 1.0, 0.0, 0.0]
+        cm_stack = []
+        tm_matrix: List[float] = [1.0, 0.0, 0.0, 1.0, 0.0, 0.0]
+
+        # cm/tm_prev stores the last modified matrices can be an intermediate position
+        cm_prev: List[float] = [1.0, 0.0, 0.0, 1.0, 0.0, 0.0]
+        tm_prev: List[float] = [1.0, 0.0, 0.0, 1.0, 0.0, 0.0]
+
+        # memo_cm/tm will be used to store the position at the beginning of building the text
+        memo_cm: List[float] = [1.0, 0.0, 0.0, 1.0, 0.0, 0.0]
+        memo_tm: List[float] = [1.0, 0.0, 0.0, 1.0, 0.0, 0.0]
+        char_scale = 1.0
+        space_scale = 1.0
+        _space_width: float = 500.0  # will be set correctly at first Tf
+        TL = 0.0
+        font_size = 12.0  # init just in case of
+
+        def current_spacewidth() -> float:
+            return _space_width / 1000.0
+
+        def process_operation(operator: bytes, operands: List[Any]) -> None:
+            nonlocal cm_matrix, cm_stack, tm_matrix, cm_prev, tm_prev, memo_cm, memo_tm
+            nonlocal char_scale, space_scale, _space_width, TL, font_size, cmap
+            nonlocal orientations, rtl_dir, visitor_text, output, text
+            global CUSTOM_RTL_MIN, CUSTOM_RTL_MAX, CUSTOM_RTL_SPECIAL_CHARS
+
+            check_crlf_space: bool = False
+            # Table 5.4 page 405
+            if operator == b"BT":
+                tm_matrix = [1.0, 0.0, 0.0, 1.0, 0.0, 0.0]
+                output += text
+                if visitor_text is not None:
+                    visitor_text(text, memo_cm, memo_tm, cmap[3], font_size)
+                text = ""
+                memo_cm = cm_matrix.copy()
+                memo_tm = tm_matrix.copy()
+                return None
+            elif operator == b"ET":
+                output += text
+                if visitor_text is not None:
+                    visitor_text(text, memo_cm, memo_tm, cmap[3], font_size)
+                text = ""
+                memo_cm = cm_matrix.copy()
+                memo_tm = tm_matrix.copy()
+            # table 4.7 "Graphics state operators", page 219
+            # cm_matrix calculation is a reserved for the moment
+            elif operator == b"q":
+                cm_stack.append(
+                    (
+                        cm_matrix,
+                        cmap,
+                        font_size,
+                        char_scale,
+                        space_scale,
+                        _space_width,
+                        TL,
+                    )
+                )
+            elif operator == b"Q":
+                try:
+                    (
+                        cm_matrix,
+                        cmap,
+                        font_size,
+                        char_scale,
+                        space_scale,
+                        _space_width,
+                        TL,
+                    ) = cm_stack.pop()
+                except Exception:
+                    cm_matrix = [1.0, 0.0, 0.0, 1.0, 0.0, 0.0]
+            elif operator == b"cm":
+                output += text
+                if visitor_text is not None:
+                    visitor_text(text, memo_cm, memo_tm, cmap[3], font_size)
+                text = ""
+                cm_matrix = mult(
+                    [
+                        float(operands[0]),
+                        float(operands[1]),
+                        float(operands[2]),
+                        float(operands[3]),
+                        float(operands[4]),
+                        float(operands[5]),
+                    ],
+                    cm_matrix,
+                )
+                memo_cm = cm_matrix.copy()
+                memo_tm = tm_matrix.copy()
+            # Table 5.2 page 398
+            elif operator == b"Tz":
+                char_scale = float(operands[0]) / 100.0
+            elif operator == b"Tw":
+                space_scale = 1.0 + float(operands[0])
+            elif operator == b"TL":
+                TL = float(operands[0])
+            elif operator == b"Tf":
+                if text != "":
+                    output += text  # .translate(cmap)
+                    if visitor_text is not None:
+                        visitor_text(text, memo_cm, memo_tm, cmap[3], font_size)
+                text = ""
+                memo_cm = cm_matrix.copy()
+                memo_tm = tm_matrix.copy()
+                try:
+                    # charMapTuple: font_type, float(sp_width / 2), encoding,
+                    #               map_dict, font-dictionary
+                    charMapTuple = cmaps[operands[0]]
+                    _space_width = charMapTuple[1]
+                    # current cmap: encoding, map_dict, font resource name
+                    #               (internal name, not the real font-name),
+                    # font-dictionary. The font-dictionary describes the font.
+                    cmap = (
+                        charMapTuple[2],
+                        charMapTuple[3],
+                        operands[0],
+                        charMapTuple[4],
+                    )
+                except KeyError:  # font not found
+                    _space_width = unknown_char_map[1]
+                    cmap = (
+                        unknown_char_map[2],
+                        unknown_char_map[3],
+                        "???" + operands[0],
+                        None,
+                    )
+                try:
+                    font_size = float(operands[1])
+                except Exception:
+                    pass  # keep previous size
+            # Table 5.5 page 406
+            elif operator == b"Td":
+                check_crlf_space = True
+                # A special case is a translating only tm:
+                # tm[0..5] = 1 0 0 1 e f,
+                # i.e. tm[4] += tx, tm[5] += ty.
+                tx = float(operands[0])
+                ty = float(operands[1])
+                tm_matrix[4] += tx * tm_matrix[0] + ty * tm_matrix[2]
+                tm_matrix[5] += tx * tm_matrix[1] + ty * tm_matrix[3]
+            elif operator == b"Tm":
+                check_crlf_space = True
+                tm_matrix = [
+                    float(operands[0]),
+                    float(operands[1]),
+                    float(operands[2]),
+                    float(operands[3]),
+                    float(operands[4]),
+                    float(operands[5]),
+                ]
+            elif operator == b"T*":
+                check_crlf_space = True
+                tm_matrix[5] -= TL
+
+            elif operator == b"Tj":
+                check_crlf_space = True
+                text, rtl_dir = handle_tj(
+                    text,
+                    operands,
+                    cm_matrix,
+                    tm_matrix,  # text matrix
+                    cmap,
+                    orientations,
+                    output,
+                    font_size,
+                    rtl_dir,
+                    visitor_text,
+                )
+            else:
+                return None
+            if check_crlf_space:
+                try:
+                    text, output, cm_prev, tm_prev = crlf_space_check(
+                        text,
+                        (cm_prev, tm_prev),
+                        (cm_matrix, tm_matrix),
+                        (memo_cm, memo_tm),
+                        cmap,
+                        orientations,
+                        output,
+                        font_size,
+                        visitor_text,
+                        current_spacewidth(),
+                    )
+                    if text == "":
+                        memo_cm = cm_matrix.copy()
+                        memo_tm = tm_matrix.copy()
+                except OrientationNotFoundError:
+                    return None
+
+        for operands, operator in content.operations:
+            if visitor_operand_before is not None:
+                visitor_operand_before(operator, operands, cm_matrix, tm_matrix)
+            # multiple operators are defined in here ####
+            if operator == b"'":
+                process_operation(b"T*", [])
+                process_operation(b"Tj", operands)
+            elif operator == b'"':
+                process_operation(b"Tw", [operands[0]])
+                process_operation(b"Tc", [operands[1]])
+                process_operation(b"T*", [])
+                process_operation(b"Tj", operands[2:])
+            elif operator == b"TD":
+                process_operation(b"TL", [-operands[1]])
+                process_operation(b"Td", operands)
+            elif operator == b"TJ":
+                for op in operands[0]:
+                    if isinstance(op, (str, bytes)):
+                        process_operation(b"Tj", [op])
+                    if isinstance(op, (int, float, NumberObject, FloatObject)) and (
+                        (abs(float(op)) >= _space_width)
+                        and (len(text) > 0)
+                        and (text[-1] != " ")
+                    ):
+                        process_operation(b"Tj", [" "])
+            elif operator == b"Do":
+                output += text
+                if visitor_text is not None:
+                    visitor_text(text, memo_cm, memo_tm, cmap[3], font_size)
+                try:
+                    if output[-1] != "\n":
+                        output += "\n"
+                        if visitor_text is not None:
+                            visitor_text(
+                                "\n",
+                                memo_cm,
+                                memo_tm,
+                                cmap[3],
+                                font_size,
+                            )
+                except IndexError:
+                    pass
+                try:
+                    xobj = resources_dict["/XObject"]
+                    if xobj[operands[0]]["/Subtype"] != "/Image":  # type: ignore
+                        text = self.extract_xform_text(
+                            xobj[operands[0]],  # type: ignore
+                            orientations,
+                            space_width,
+                            visitor_operand_before,
+                            visitor_operand_after,
+                            visitor_text,
+                        )
+                        output += text
+                        if visitor_text is not None:
+                            visitor_text(
+                                text,
+                                memo_cm,
+                                memo_tm,
+                                cmap[3],
+                                font_size,
+                            )
+                except Exception:
+                    logger_warning(
+                        f" impossible to decode XFormObject {operands[0]}",
+                        __name__,
+                    )
+                finally:
+                    text = ""
+                    memo_cm = cm_matrix.copy()
+                    memo_tm = tm_matrix.copy()
+
+            else:
+                process_operation(operator, operands)
+            if visitor_operand_after is not None:
+                visitor_operand_after(operator, operands, cm_matrix, tm_matrix)
+        output += text  # just in case of
+        if text != "" and visitor_text is not None:
+            visitor_text(text, memo_cm, memo_tm, cmap[3], font_size)
+        return output
+
+    def _layout_mode_fonts(self) -> Dict[str, _layout_mode.Font]:
+        """
+        Get fonts formatted for "layout" mode text extraction.
+
+        Returns:
+            Dict[str, Font]: dictionary of _layout_mode.Font instances keyed by font name
+        """
+        # Font retrieval logic adapted from pypdf.PageObject._extract_text()
+        objr: Any = self
+        fonts: Dict[str, _layout_mode.Font] = {}
+        while objr is not None:
+            try:
+                resources_dict: Any = objr[PG.RESOURCES]
+            except KeyError:
+                resources_dict = {}
+            if "/Font" in resources_dict and self.pdf is not None:
+                for font_name in resources_dict["/Font"]:
+                    *cmap, font_dict_obj = build_char_map(font_name, 200.0, self)
+                    font_dict = {
+                        k: v.get_object()
+                        if isinstance(v, IndirectObject)
+                        else [_v.get_object() for _v in v]
+                        if isinstance(v, ArrayObject)
+                        else v
+                        for k, v in font_dict_obj.items()
+                    }
+                    # mypy really sucks at unpacking
+                    fonts[font_name] = _layout_mode.Font(*cmap, font_dict)  # type: ignore[call-arg,arg-type]
+            try:
+                objr = objr["/Parent"].get_object()
+            except KeyError:
+                objr = None
+
+        return fonts
+
+    def _layout_mode_text(
+        self,
+        space_vertically: bool = True,
+        scale_weight: float = 1.25,
+        strip_rotated: bool = True,
+        debug_path: Optional[Path] = None,
+    ) -> str:
+        """
+        Get text preserving fidelity to source PDF text layout.
+
+        Args:
+            space_vertically: include blank lines inferred from y distance + font
+                height. Defaults to True.
+            scale_weight: multiplier for string length when calculating weighted
+                average character width. Defaults to 1.25.
+            strip_rotated: Removes text that is rotated w.r.t. to the page from
+                layout mode output. Defaults to True.
+            debug_path (Path | None): if supplied, must target a directory.
+                creates the following files with debug information for layout mode
+                functions if supplied:
+                  - fonts.json: output of self._layout_mode_fonts
+                  - tjs.json: individual text render ops with corresponding transform matrices
+                  - bts.json: text render ops left justified and grouped by BT/ET operators
+                  - bt_groups.json: BT/ET operations grouped by rendered y-coord (aka lines)
+                Defaults to None.
+
+        Returns:
+            str: multiline string containing page text in a fixed width format that
+                closely adheres to the rendered layout in the source pdf.
+        """
+        fonts = self._layout_mode_fonts()
+        if debug_path:  # pragma: no cover
+            import json
+
+            debug_path.joinpath("fonts.json").write_text(
+                json.dumps(
+                    fonts, indent=2, default=lambda x: getattr(x, "to_dict", str)(x)
+                ),
+                "utf-8",
+            )
+
+        ops = iter(
+            ContentStream(self["/Contents"].get_object(), self.pdf, "bytes").operations
+        )
+        bt_groups = _layout_mode.text_show_operations(
+            ops, fonts, strip_rotated, debug_path
+        )
+
+        if not bt_groups:
+            return ""
+
+        ty_groups = _layout_mode.y_coordinate_groups(bt_groups, debug_path)
+
+        char_width = _layout_mode.fixed_char_width(bt_groups, scale_weight)
+
+        return _layout_mode.fixed_width_page(ty_groups, char_width, space_vertically)
+
+    def extract_text(
+        self,
+        *args: Any,
+        orientations: Union[int, Tuple[int, ...]] = (0, 90, 180, 270),
+        space_width: float = 200.0,
+        visitor_operand_before: Optional[Callable[[Any, Any, Any, Any], None]] = None,
+        visitor_operand_after: Optional[Callable[[Any, Any, Any, Any], None]] = None,
+        visitor_text: Optional[Callable[[Any, Any, Any, Any, Any], None]] = None,
+        extraction_mode: Literal["plain", "layout"] = "plain",
+        **kwargs: Any,
+    ) -> str:
+        """
+        Locate all text drawing commands, in the order they are provided in the
+        content stream, and extract the text.
+
+        This works well for some PDF files, but poorly for others, depending on
+        the generator used. This will be refined in the future.
+
+        Do not rely on the order of text coming out of this function, as it
+        will change if this function is made more sophisticated.
+
+        Arabic and Hebrew are extracted in the correct order.
+        If required a custom RTL range of characters can be defined;
+        see function set_custom_rtl.
+
+        Additionally you can provide visitor methods to get informed on all
+        operations and all text objects.
+        For example in some PDF files this can be useful to parse tables.
+
+        Args:
+            orientations: list of orientations extract_text will look for
+                default = (0, 90, 180, 270)
+                note: currently only 0 (up),90 (turned left), 180 (upside down),
+                270 (turned right)
+            space_width: force default space width
+                if not extracted from font (default: 200)
+            visitor_operand_before: function to be called before processing an operation.
+                It has four arguments: operator, operand-arguments,
+                current transformation matrix and text matrix.
+            visitor_operand_after: function to be called after processing an operation.
+                It has four arguments: operator, operand-arguments,
+                current transformation matrix and text matrix.
+            visitor_text: function to be called when extracting some text at some position.
+                It has five arguments: text, current transformation matrix,
+                text matrix, font-dictionary and font-size.
+                The font-dictionary may be None in case of unknown fonts.
+                If not None it may e.g. contain key "/BaseFont" with value "/Arial,Bold".
+            extraction_mode (Literal["plain", "layout"]): "plain" for legacy functionality,
+                "layout" for experimental layout mode functionality.
+                NOTE: orientations, space_width, and visitor_* parameters are NOT respected
+                in "layout" mode.
+
+        kwargs:
+            layout_mode_space_vertically (bool): include blank lines inferred from
+                y distance + font height. Defaults to True.
+            layout_mode_scale_weight (float): multiplier for string length when calculating
+                weighted average character width. Defaults to 1.25.
+            layout_mode_strip_rotated (bool): layout mode does not support rotated text.
+                Set to False to include rotated text anyway. If rotated text is discovered,
+                layout will be degraded and a warning will result. Defaults to True.
+            layout_mode_debug_path (Path | None): if supplied, must target a directory.
+                creates the following files with debug information for layout mode
+                functions if supplied:
+
+                  - fonts.json: output of self._layout_mode_fonts
+                  - tjs.json: individual text render ops with corresponding transform matrices
+                  - bts.json: text render ops left justified and grouped by BT/ET operators
+                  - bt_groups.json: BT/ET operations grouped by rendered y-coord (aka lines)
+
+        Returns:
+            The extracted text
+        """
+        if extraction_mode not in ["plain", "layout"]:
+            raise ValueError(f"Invalid text extraction mode '{extraction_mode}'")
+        if extraction_mode == "layout":
+            return self._layout_mode_text(
+                space_vertically=kwargs.get("layout_mode_space_vertically", True),
+                scale_weight=kwargs.get("layout_mode_scale_weight", 1.25),
+                strip_rotated=kwargs.get("layout_mode_strip_rotated", True),
+                debug_path=kwargs.get("layout_mode_debug_path", None),
+            )
+        if len(args) >= 1:
+            if isinstance(args[0], str):
+                if len(args) >= 3:
+                    if isinstance(args[2], (tuple, int)):
+                        orientations = args[2]
+                    else:
+                        raise TypeError(f"Invalid positional parameter {args[2]}")
+                if len(args) >= 4:
+                    if isinstance(args[3], (float, int)):
+                        space_width = args[3]
+                    else:
+                        raise TypeError(f"Invalid positional parameter {args[3]}")
+            elif isinstance(args[0], (tuple, int)):
+                orientations = args[0]
+                if len(args) >= 2:
+                    if isinstance(args[1], (float, int)):
+                        space_width = args[1]
+                    else:
+                        raise TypeError(f"Invalid positional parameter {args[1]}")
+            else:
+                raise TypeError(f"Invalid positional parameter {args[0]}")
+
+        if isinstance(orientations, int):
+            orientations = (orientations,)
+
+        return self._extract_text(
+            self,
+            self.pdf,
+            orientations,
+            space_width,
+            PG.CONTENTS,
+            visitor_operand_before,
+            visitor_operand_after,
+            visitor_text,
+        )
+
+    def extract_xform_text(
+        self,
+        xform: EncodedStreamObject,
+        orientations: Tuple[int, ...] = (0, 90, 270, 360),
+        space_width: float = 200.0,
+        visitor_operand_before: Optional[Callable[[Any, Any, Any, Any], None]] = None,
+        visitor_operand_after: Optional[Callable[[Any, Any, Any, Any], None]] = None,
+        visitor_text: Optional[Callable[[Any, Any, Any, Any, Any], None]] = None,
+    ) -> str:
+        """
+        Extract text from an XObject.
+
+        Args:
+            xform:
+            orientations:
+            space_width:  force default space width (if not extracted from font (default 200)
+            visitor_operand_before:
+            visitor_operand_after:
+            visitor_text:
+
+        Returns:
+            The extracted text
+        """
+        return self._extract_text(
+            xform,
+            self.pdf,
+            orientations,
+            space_width,
+            None,
+            visitor_operand_before,
+            visitor_operand_after,
+            visitor_text,
+        )
+
+    def _get_fonts(self) -> Tuple[Set[str], Set[str]]:
+        """
+        Get the names of embedded fonts and unembedded fonts.
+
+        Returns:
+            A tuple (Set of embedded fonts, set of unembedded fonts)
+        """
+        obj = self.get_object()
+        assert isinstance(obj, DictionaryObject)
+        fonts: Set[str] = set()
+        embedded: Set[str] = set()
+        fonts, embedded = _get_fonts_walk(obj, fonts, embedded)
+        unembedded = fonts - embedded
+        return embedded, unembedded
+
+    mediabox = _create_rectangle_accessor(PG.MEDIABOX, ())
+    """A :class:`RectangleObject<pypdf.generic.RectangleObject>`, expressed in
+    default user space units, defining the boundaries of the physical medium on
+    which the page is intended to be displayed or printed."""
+
+    cropbox = _create_rectangle_accessor("/CropBox", (PG.MEDIABOX,))
+    """
+    A :class:`RectangleObject<pypdf.generic.RectangleObject>`, expressed in
+    default user space units, defining the visible region of default user
+    space.
+
+    When the page is displayed or printed, its contents are to be clipped
+    (cropped) to this rectangle and then imposed on the output medium in some
+    implementation-defined manner. Default value: same as
+    :attr:`mediabox<mediabox>`.
+    """
+
+    bleedbox = _create_rectangle_accessor("/BleedBox", ("/CropBox", PG.MEDIABOX))
+    """A :class:`RectangleObject<pypdf.generic.RectangleObject>`, expressed in
+    default user space units, defining the region to which the contents of the
+    page should be clipped when output in a production environment."""
+
+    trimbox = _create_rectangle_accessor("/TrimBox", ("/CropBox", PG.MEDIABOX))
+    """A :class:`RectangleObject<pypdf.generic.RectangleObject>`, expressed in
+    default user space units, defining the intended dimensions of the finished
+    page after trimming."""
+
+    artbox = _create_rectangle_accessor("/ArtBox", ("/CropBox", PG.MEDIABOX))
+    """A :class:`RectangleObject<pypdf.generic.RectangleObject>`, expressed in
+    default user space units, defining the extent of the page's meaningful
+    content as intended by the page's creator."""
+
+    @property
+    def annotations(self) -> Optional[ArrayObject]:
+        if "/Annots" not in self:
+            return None
+        else:
+            return cast(ArrayObject, self["/Annots"])
+
+    @annotations.setter
+    def annotations(self, value: Optional[ArrayObject]) -> None:
+        """
+        Set the annotations array of the page.
+
+        Typically you do not want to set this value, but append to it.
+        If you append to it, remember to add the object first to the writer
+        and only add the indirect object.
+        """
+        if value is None:
+            del self[NameObject("/Annots")]
+        else:
+            self[NameObject("/Annots")] = value
+
+
+class _VirtualList(Sequence[PageObject]):
+    def __init__(
+        self,
+        length_function: Callable[[], int],
+        get_function: Callable[[int], PageObject],
+    ) -> None:
+        self.length_function = length_function
+        self.get_function = get_function
+        self.current = -1
+
+    def __len__(self) -> int:
+        return self.length_function()
+
+    @overload
+    def __getitem__(self, index: int) -> PageObject:
+        ...
+
+    @overload
+    def __getitem__(self, index: slice) -> Sequence[PageObject]:
+        ...
+
+    def __getitem__(
+        self, index: Union[int, slice]
+    ) -> Union[PageObject, Sequence[PageObject]]:
+        if isinstance(index, slice):
+            indices = range(*index.indices(len(self)))
+            cls = type(self)
+            return cls(indices.__len__, lambda idx: self[indices[idx]])
+        if not isinstance(index, int):
+            raise TypeError("sequence indices must be integers")
+        len_self = len(self)
+        if index < 0:
+            # support negative indexes
+            index = len_self + index
+        if index < 0 or index >= len_self:
+            raise IndexError("sequence index out of range")
+        return self.get_function(index)
+
+    def __delitem__(self, index: Union[int, slice]) -> None:
+        if isinstance(index, slice):
+            r = list(range(*index.indices(len(self))))
+            # pages have to be deleted from last to first
+            r.sort()
+            r.reverse()
+            for p in r:
+                del self[p]  # recursive call
+            return
+        if not isinstance(index, int):
+            raise TypeError("index must be integers")
+        len_self = len(self)
+        if index < 0:
+            # support negative indexes
+            index = len_self + index
+        if index < 0 or index >= len_self:
+            raise IndexError("index out of range")
+        ind = self[index].indirect_reference
+        assert ind is not None
+        parent = cast(DictionaryObject, ind.get_object()).get("/Parent", None)
+        while parent is not None:
+            parent = cast(DictionaryObject, parent.get_object())
+            try:
+                i = parent["/Kids"].index(ind)
+                del parent["/Kids"][i]
+                try:
+                    assert ind is not None
+                    del ind.pdf.flattened_pages[index]  # case of page in a Reader
+                except Exception:  # pragma: no cover
+                    pass
+                if "/Count" in parent:
+                    parent[NameObject("/Count")] = NumberObject(parent["/Count"] - 1)
+                if len(parent["/Kids"]) == 0:
+                    # No more objects in this part of this sub tree
+                    ind = parent.indirect_reference
+                    parent = cast(DictionaryObject, parent.get("/Parent", None))
+                else:
+                    parent = None
+            except ValueError:  # from index
+                raise PdfReadError(f"Page Not Found in Page Tree {ind}")
+
+    def __iter__(self) -> Iterator[PageObject]:
+        for i in range(len(self)):
+            yield self[i]
+
+    def __str__(self) -> str:
+        p = [f"PageObject({i})" for i in range(self.length_function())]
+        return f"[{', '.join(p)}]"
+
+
+def _get_fonts_walk(
+    obj: DictionaryObject,
+    fnt: Set[str],
+    emb: Set[str],
+) -> Tuple[Set[str], Set[str]]:
+    """
+    Get the set of all fonts and all embedded fonts.
+
+    Args:
+        obj: Page resources dictionary
+        fnt: font
+        emb: embedded fonts
+
+    Returns:
+        A tuple (fnt, emb)
+
+    If there is a key called 'BaseFont', that is a font that is used in the document.
+    If there is a key called 'FontName' and another key in the same dictionary object
+    that is called 'FontFilex' (where x is null, 2, or 3), then that fontname is
+    embedded.
+
+    We create and add to two sets, fnt = fonts used and emb = fonts embedded.
+    """
+    fontkeys = ("/FontFile", "/FontFile2", "/FontFile3")
+
+    def process_font(f: DictionaryObject) -> None:
+        nonlocal fnt, emb
+        f = cast(DictionaryObject, f.get_object())  # to be sure
+        if "/BaseFont" in f:
+            fnt.add(cast(str, f["/BaseFont"]))
+
+        if (
+            ("/CharProcs" in f)
+            or (
+                "/FontDescriptor" in f
+                and any(
+                    x in cast(DictionaryObject, f["/FontDescriptor"]) for x in fontkeys
+                )
+            )
+            or (
+                "/DescendantFonts" in f
+                and "/FontDescriptor"
+                in cast(
+                    DictionaryObject,
+                    cast(ArrayObject, f["/DescendantFonts"])[0].get_object(),
+                )
+                and any(
+                    x
+                    in cast(
+                        DictionaryObject,
+                        cast(
+                            DictionaryObject,
+                            cast(ArrayObject, f["/DescendantFonts"])[0].get_object(),
+                        )["/FontDescriptor"],
+                    )
+                    for x in fontkeys
+                )
+            )
+        ):
+            # the list comprehension ensures there is FontFile
+            try:
+                emb.add(cast(str, f["/BaseFont"]))
+            except KeyError:
+                emb.add("(" + cast(str, f["/Subtype"]) + ")")
+
+    if "/DR" in obj and "/Font" in cast(DictionaryObject, obj["/DR"]):
+        for f in cast(DictionaryObject, cast(DictionaryObject, obj["/DR"])["/Font"]):
+            process_font(f)
+    if "/Resources" in obj:
+        if "/Font" in cast(DictionaryObject, obj["/Resources"]):
+            for f in cast(
+                DictionaryObject, cast(DictionaryObject, obj["/Resources"])["/Font"]
+            ).values():
+                process_font(f)
+        if "/XObject" in cast(DictionaryObject, obj["/Resources"]):
+            for x in cast(
+                DictionaryObject, cast(DictionaryObject, obj["/Resources"])["/XObject"]
+            ).values():
+                _get_fonts_walk(cast(DictionaryObject, x.get_object()), fnt, emb)
+    if "/Annots" in obj:
+        for a in cast(ArrayObject, obj["/Annots"]):
+            _get_fonts_walk(cast(DictionaryObject, a.get_object()), fnt, emb)
+    if "/AP" in obj:
+        if (
+            cast(DictionaryObject, cast(DictionaryObject, obj["/AP"])["/N"]).get(
+                "/Type"
+            )
+            == "/XObject"
+        ):
+            _get_fonts_walk(
+                cast(DictionaryObject, cast(DictionaryObject, obj["/AP"])["/N"]),
+                fnt,
+                emb,
+            )
+        else:
+            for a in cast(DictionaryObject, cast(DictionaryObject, obj["/AP"])["/N"]):
+                _get_fonts_walk(cast(DictionaryObject, a), fnt, emb)
+    return fnt, emb  # return the sets for each page
+
+
+class _VirtualListImages(Sequence[ImageFile]):
+    def __init__(
+        self,
+        ids_function: Callable[[], List[Union[str, List[str]]]],
+        get_function: Callable[[Union[str, List[str], Tuple[str]]], ImageFile],
+    ) -> None:
+        self.ids_function = ids_function
+        self.get_function = get_function
+        self.current = -1
+
+    def __len__(self) -> int:
+        return len(self.ids_function())
+
+    def keys(self) -> List[Union[str, List[str]]]:
+        return self.ids_function()
+
+    def items(self) -> List[Tuple[Union[str, List[str]], ImageFile]]:
+        return [(x, self[x]) for x in self.ids_function()]
+
+    @overload
+    def __getitem__(self, index: Union[int, str, List[str]]) -> ImageFile:
+        ...
+
+    @overload
+    def __getitem__(self, index: slice) -> Sequence[ImageFile]:
+        ...
+
+    def __getitem__(
+        self, index: Union[int, slice, str, List[str], Tuple[str]]
+    ) -> Union[ImageFile, Sequence[ImageFile]]:
+        lst = self.ids_function()
+        if isinstance(index, slice):
+            indices = range(*index.indices(len(self)))
+            lst = [lst[x] for x in indices]
+            cls = type(self)
+            return cls((lambda: lst), self.get_function)
+        if isinstance(index, (str, list, tuple)):
+            return self.get_function(index)
+        if not isinstance(index, int):
+            raise TypeError("invalid sequence indices type")
+        len_self = len(lst)
+        if index < 0:
+            # support negative indexes
+            index = len_self + index
+        if index < 0 or index >= len_self:
+            raise IndexError("sequence index out of range")
+        return self.get_function(lst[index])
+
+    def __iter__(self) -> Iterator[ImageFile]:
+        for i in range(len(self)):
+            yield self[i]
+
+    def __str__(self) -> str:
+        p = [f"Image_{i}={n}" for i, n in enumerate(self.ids_function())]
+        return f"[{', '.join(p)}]"
diff --git a/.venv/lib/python3.12/site-packages/pypdf/_page_labels.py b/.venv/lib/python3.12/site-packages/pypdf/_page_labels.py
new file mode 100644
index 00000000..b0252795
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/_page_labels.py
@@ -0,0 +1,280 @@
+"""
+Page labels are shown by PDF viewers as "the page number".
+
+A page has a numeric index, starting at 0. Additionally, the page
+has a label. In the most simple case:
+
+    label = index + 1
+
+However, the title page and the table of contents might have Roman numerals as
+page labels. This makes things more complicated.
+
+Example 1
+---------
+
+>>> reader.root_object["/PageLabels"]["/Nums"]
+[0, IndirectObject(18, 0, 139929798197504),
+ 8, IndirectObject(19, 0, 139929798197504)]
+>>> reader.get_object(reader.root_object["/PageLabels"]["/Nums"][1])
+{'/S': '/r'}
+>>> reader.get_object(reader.root_object["/PageLabels"]["/Nums"][3])
+{'/S': '/D'}
+
+Example 2
+---------
+The following is a document with pages labeled
+i, ii, iii, iv, 1, 2, 3, A-8, A-9, ...
+
+1 0 obj
+    << /Type /Catalog
+       /PageLabels << /Nums [
+                        0 << /S /r >>
+                        4 << /S /D >>
+                        7 << /S /D
+                             /P ( A- )
+                             /St 8
+                        >>
+                        % A number tree containing
+                        % three page label dictionaries
+                        ]
+                   >>
+    ...
+    >>
+endobj
+
+
+§12.4.2 PDF Specification 1.7 and 2.0
+=====================================
+
+Entries in a page label dictionary
+----------------------------------
+The /S key:
+D       Decimal Arabic numerals
+R       Uppercase Roman numerals
+r       Lowercase Roman numerals
+A       Uppercase letters (A to Z for the first 26 pages,
+                           AA to ZZ for the next 26, and so on)
+a       Lowercase letters (a to z for the first 26 pages,
+                           aa to zz for the next 26, and so on)
+"""
+
+from typing import Iterator, List, Optional, Tuple, cast
+
+from ._protocols import PdfCommonDocProtocol
+from ._utils import logger_warning
+from .generic import ArrayObject, DictionaryObject, NullObject, NumberObject
+
+
+def number2uppercase_roman_numeral(num: int) -> str:
+    roman = [
+        (1000, "M"),
+        (900, "CM"),
+        (500, "D"),
+        (400, "CD"),
+        (100, "C"),
+        (90, "XC"),
+        (50, "L"),
+        (40, "XL"),
+        (10, "X"),
+        (9, "IX"),
+        (5, "V"),
+        (4, "IV"),
+        (1, "I"),
+    ]
+
+    def roman_num(num: int) -> Iterator[str]:
+        for decimal, roman_repr in roman:
+            x, _ = divmod(num, decimal)
+            yield roman_repr * x
+            num -= decimal * x
+            if num <= 0:
+                break
+
+    return "".join(list(roman_num(num)))
+
+
+def number2lowercase_roman_numeral(number: int) -> str:
+    return number2uppercase_roman_numeral(number).lower()
+
+
+def number2uppercase_letter(number: int) -> str:
+    if number <= 0:
+        raise ValueError("Expecting a positive number")
+    alphabet = [chr(i) for i in range(ord("A"), ord("Z") + 1)]
+    rep = ""
+    while number > 0:
+        remainder = number % 26
+        if remainder == 0:
+            remainder = 26
+        rep = alphabet[remainder - 1] + rep
+        # update
+        number -= remainder
+        number = number // 26
+    return rep
+
+
+def number2lowercase_letter(number: int) -> str:
+    return number2uppercase_letter(number).lower()
+
+
+def get_label_from_nums(dictionary_object: DictionaryObject, index: int) -> str:
+    # [Nums] shall be an array of the form
+    #   [ key 1 value 1 key 2 value 2 ... key n value n ]
+    # where each key_i is an integer and the corresponding
+    # value_i shall be the object associated with that key.
+    # The keys shall be sorted in numerical order,
+    # analogously to the arrangement of keys in a name tree
+    # as described in 7.9.6, "Name Trees."
+    nums = cast(ArrayObject, dictionary_object["/Nums"])
+    i = 0
+    value = None
+    start_index = 0
+    while i < len(nums):
+        start_index = nums[i]
+        value = nums[i + 1].get_object()
+        if i + 2 == len(nums):
+            break
+        if nums[i + 2] > index:
+            break
+        i += 2
+    m = {
+        None: lambda n: "",
+        "/D": lambda n: str(n),
+        "/R": number2uppercase_roman_numeral,
+        "/r": number2lowercase_roman_numeral,
+        "/A": number2uppercase_letter,
+        "/a": number2lowercase_letter,
+    }
+    # if /Nums array is not following the specification or if /Nums is empty
+    if not isinstance(value, dict):
+        return str(index + 1)  # Fallback
+    start = value.get("/St", 1)
+    prefix = value.get("/P", "")
+    return prefix + m[value.get("/S")](index - start_index + start)
+
+
+def index2label(reader: PdfCommonDocProtocol, index: int) -> str:
+    """
+    See 7.9.7 "Number Trees".
+
+    Args:
+        reader: The PdfReader
+        index: The index of the page
+
+    Returns:
+        The label of the page, e.g. "iv" or "4".
+    """
+    root = cast(DictionaryObject, reader.root_object)
+    if "/PageLabels" not in root:
+        return str(index + 1)  # Fallback
+    number_tree = cast(DictionaryObject, root["/PageLabels"].get_object())
+    if "/Nums" in number_tree:
+        return get_label_from_nums(number_tree, index)
+    if "/Kids" in number_tree and not isinstance(number_tree["/Kids"], NullObject):
+        # number_tree = {'/Kids': [IndirectObject(7333, 0, 140132998195856), ...]}
+        # Limit maximum depth.
+        level = 0
+        while level < 100:
+            kids = cast(List[DictionaryObject], number_tree["/Kids"])
+            for kid in kids:
+                # kid = {'/Limits': [0, 63], '/Nums': [0, {'/P': 'C1'}, ...]}
+                limits = cast(List[int], kid["/Limits"])
+                if limits[0] <= index <= limits[1]:
+                    if kid.get("/Kids", None) is not None:
+                        # Recursive definition.
+                        level += 1
+                        if level == 100:  # pragma: no cover
+                            raise NotImplementedError("Too deep nesting is not supported.")
+                        number_tree = kid
+                        # Exit the inner `for` loop and continue at the next level with the
+                        # next iteration of the `while` loop.
+                        break
+                    return get_label_from_nums(kid, index)
+            else:
+                # When there are no kids, make sure to exit the `while` loop directly
+                # and continue with the fallback.
+                break
+
+    logger_warning(
+        f"Could not reliably determine page label for {index}.",
+        __name__
+    )
+    return str(index + 1)  # Fallback if neither /Nums nor /Kids is in the number_tree
+
+
+def nums_insert(
+    key: NumberObject,
+    value: DictionaryObject,
+    nums: ArrayObject,
+) -> None:
+    """
+    Insert a key, value pair in a Nums array.
+
+    See 7.9.7 "Number Trees".
+
+    Args:
+        key: number key of the entry
+        value: value of the entry
+        nums: Nums array to modify
+    """
+    if len(nums) % 2 != 0:
+        raise ValueError("a nums like array must have an even number of elements")
+
+    i = len(nums)
+    while i != 0 and key <= nums[i - 2]:
+        i = i - 2
+
+    if i < len(nums) and key == nums[i]:
+        nums[i + 1] = value
+    else:
+        nums.insert(i, key)
+        nums.insert(i + 1, value)
+
+
+def nums_clear_range(
+    key: NumberObject,
+    page_index_to: int,
+    nums: ArrayObject,
+) -> None:
+    """
+    Remove all entries in a number tree in a range after an entry.
+
+    See 7.9.7 "Number Trees".
+
+    Args:
+        key: number key of the entry before the range
+        page_index_to: The page index of the upper limit of the range
+        nums: Nums array to modify
+    """
+    if len(nums) % 2 != 0:
+        raise ValueError("a nums like array must have an even number of elements")
+    if page_index_to < key:
+        raise ValueError("page_index_to must be greater or equal than key")
+
+    i = nums.index(key) + 2
+    while i < len(nums) and nums[i] <= page_index_to:
+        nums.pop(i)
+        nums.pop(i)
+
+
+def nums_next(
+    key: NumberObject,
+    nums: ArrayObject,
+) -> Tuple[Optional[NumberObject], Optional[DictionaryObject]]:
+    """
+    Return the (key, value) pair of the entry after the given one.
+
+    See 7.9.7 "Number Trees".
+
+    Args:
+        key: number key of the entry
+        nums: Nums array
+    """
+    if len(nums) % 2 != 0:
+        raise ValueError("a nums like array must have an even number of elements")
+
+    i = nums.index(key) + 2
+    if i < len(nums):
+        return (nums[i], nums[i + 1])
+    else:
+        return (None, None)
diff --git a/.venv/lib/python3.12/site-packages/pypdf/_protocols.py b/.venv/lib/python3.12/site-packages/pypdf/_protocols.py
new file mode 100644
index 00000000..9f413660
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/_protocols.py
@@ -0,0 +1,89 @@
+"""Helpers for working with PDF types."""
+
+from abc import abstractmethod
+from pathlib import Path
+from typing import IO, Any, Dict, List, Optional, Tuple, Union
+
+try:
+    # Python 3.8+: https://peps.python.org/pep-0586
+    from typing import Protocol
+except ImportError:
+    from typing_extensions import Protocol  # type: ignore[assignment]
+
+from ._utils import StrByteType, StreamType
+
+
+class PdfObjectProtocol(Protocol):
+    indirect_reference: Any
+
+    def clone(
+        self,
+        pdf_dest: Any,
+        force_duplicate: bool = False,
+        ignore_fields: Union[Tuple[str, ...], List[str], None] = (),
+    ) -> Any:
+        ...  # pragma: no cover
+
+    def _reference_clone(self, clone: Any, pdf_dest: Any) -> Any:
+        ...  # pragma: no cover
+
+    def get_object(self) -> Optional["PdfObjectProtocol"]:
+        ...  # pragma: no cover
+
+    def hash_value(self) -> bytes:
+        ...  # pragma: no cover
+
+    def write_to_stream(
+        self, stream: StreamType, encryption_key: Union[None, str, bytes] = None
+    ) -> None:
+        ...  # pragma: no cover
+
+
+class XmpInformationProtocol(PdfObjectProtocol):
+    pass
+
+
+class PdfCommonDocProtocol(Protocol):
+    @property
+    def pdf_header(self) -> str:
+        ...  # pragma: no cover
+
+    @property
+    def pages(self) -> List[Any]:
+        ...  # pragma: no cover
+
+    @property
+    def root_object(self) -> PdfObjectProtocol:
+        ...  # pragma: no cover
+
+    def get_object(self, indirect_reference: Any) -> Optional[PdfObjectProtocol]:
+        ...  # pragma: no cover
+
+    @property
+    def strict(self) -> bool:
+        ...  # pragma: no cover
+
+
+class PdfReaderProtocol(PdfCommonDocProtocol, Protocol):
+    @property
+    @abstractmethod
+    def xref(self) -> Dict[int, Dict[int, Any]]:
+        ...  # pragma: no cover
+
+    @property
+    @abstractmethod
+    def trailer(self) -> Dict[str, Any]:
+        ...  # pragma: no cover
+
+
+class PdfWriterProtocol(PdfCommonDocProtocol, Protocol):
+    _objects: List[Any]
+    _id_translated: Dict[int, Dict[int, int]]
+
+    @abstractmethod
+    def write(self, stream: Union[Path, StrByteType]) -> Tuple[bool, IO[Any]]:
+        ...  # pragma: no cover
+
+    @abstractmethod
+    def _add_object(self, obj: Any) -> Any:
+        ...  # pragma: no cover
diff --git a/.venv/lib/python3.12/site-packages/pypdf/_reader.py b/.venv/lib/python3.12/site-packages/pypdf/_reader.py
new file mode 100644
index 00000000..aeababa7
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/_reader.py
@@ -0,0 +1,1159 @@
+# Copyright (c) 2006, Mathieu Fenniak
+# Copyright (c) 2007, Ashish Kulkarni <kulkarni.ashish@gmail.com>
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# * The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+import os
+import re
+from io import BytesIO, UnsupportedOperation
+from pathlib import Path
+from types import TracebackType
+from typing import (
+    Any,
+    Callable,
+    Dict,
+    Iterable,
+    List,
+    Optional,
+    Tuple,
+    Type,
+    Union,
+    cast,
+)
+
+from ._doc_common import PdfDocCommon, convert_to_int
+from ._encryption import Encryption, PasswordType
+from ._page import PageObject
+from ._utils import (
+    StrByteType,
+    StreamType,
+    b_,
+    logger_warning,
+    read_non_whitespace,
+    read_previous_line,
+    read_until_whitespace,
+    skip_over_comment,
+    skip_over_whitespace,
+)
+from .constants import TrailerKeys as TK
+from .errors import (
+    EmptyFileError,
+    FileNotDecryptedError,
+    PdfReadError,
+    PdfStreamError,
+    WrongPasswordError,
+)
+from .generic import (
+    ArrayObject,
+    ContentStream,
+    DecodedStreamObject,
+    DictionaryObject,
+    EncodedStreamObject,
+    IndirectObject,
+    NameObject,
+    NullObject,
+    NumberObject,
+    PdfObject,
+    TextStringObject,
+    read_object,
+)
+from .xmp import XmpInformation
+
+
+class PdfReader(PdfDocCommon):
+    """
+    Initialize a PdfReader object.
+
+    This operation can take some time, as the PDF stream's cross-reference
+    tables are read into memory.
+
+    Args:
+        stream: A File object or an object that supports the standard read
+            and seek methods similar to a File object. Could also be a
+            string representing a path to a PDF file.
+        strict: Determines whether user should be warned of all
+            problems and also causes some correctable problems to be fatal.
+            Defaults to ``False``.
+        password: Decrypt PDF file at initialization. If the
+            password is None, the file will not be decrypted.
+            Defaults to ``None``.
+    """
+
+    def __init__(
+        self,
+        stream: Union[StrByteType, Path],
+        strict: bool = False,
+        password: Union[None, str, bytes] = None,
+    ) -> None:
+        self.strict = strict
+        self.flattened_pages: Optional[List[PageObject]] = None
+        #: Storage of parsed PDF objects.
+        self.resolved_objects: Dict[Tuple[Any, Any], Optional[PdfObject]] = {}
+
+        self.xref_index = 0
+        self.xref: Dict[int, Dict[Any, Any]] = {}
+        self.xref_free_entry: Dict[int, Dict[Any, Any]] = {}
+        self.xref_objStm: Dict[int, Tuple[Any, Any]] = {}
+        self.trailer = DictionaryObject()
+
+        self._page_id2num: Optional[
+            Dict[Any, Any]
+        ] = None  # map page indirect_reference number to Page Number
+        if hasattr(stream, "mode") and "b" not in stream.mode:
+            logger_warning(
+                "PdfReader stream/file object is not in binary mode. "
+                "It may not be read correctly.",
+                __name__,
+            )
+        self._stream_opened = False
+        if isinstance(stream, (str, Path)):
+            with open(stream, "rb") as fh:
+                stream = BytesIO(fh.read())
+            self._stream_opened = True
+        self.read(stream)
+        self.stream = stream
+
+        self._override_encryption = False
+        self._encryption: Optional[Encryption] = None
+        if self.is_encrypted:
+            self._override_encryption = True
+            # Some documents may not have a /ID, use two empty
+            # byte strings instead. Solves
+            # https://github.com/py-pdf/pypdf/issues/608
+            id_entry = self.trailer.get(TK.ID)
+            id1_entry = id_entry[0].get_object().original_bytes if id_entry else b""
+            encrypt_entry = cast(
+                DictionaryObject, self.trailer[TK.ENCRYPT].get_object()
+            )
+            self._encryption = Encryption.read(encrypt_entry, id1_entry)
+
+            # try empty password if no password provided
+            pwd = password if password is not None else b""
+            if (
+                self._encryption.verify(pwd) == PasswordType.NOT_DECRYPTED
+                and password is not None
+            ):
+                # raise if password provided
+                raise WrongPasswordError("Wrong password")
+            self._override_encryption = False
+        elif password is not None:
+            raise PdfReadError("Not encrypted file")
+
+    def __enter__(self) -> "PdfReader":
+        return self
+
+    def __exit__(
+        self,
+        exc_type: Optional[Type[BaseException]],
+        exc_val: Optional[BaseException],
+        exc_tb: Optional[TracebackType],
+    ) -> None:
+        self.close()
+
+    def close(self) -> None:
+        """Close the stream if opened in __init__ and clear memory."""
+        if self._stream_opened:
+            self.stream.close()
+        self.flattened_pages = []
+        self.resolved_objects = {}
+        self.trailer = DictionaryObject()
+        self.xref = {}
+        self.xref_free_entry = {}
+        self.xref_objStm = {}
+
+    @property
+    def root_object(self) -> DictionaryObject:
+        """Provide access to "/Root". Standardized with PdfWriter."""
+        return cast(DictionaryObject, self.trailer[TK.ROOT].get_object())
+
+    @property
+    def _info(self) -> Optional[DictionaryObject]:
+        """
+        Provide access to "/Info". Standardized with PdfWriter.
+
+        Returns:
+            /Info Dictionary; None if the entry does not exist
+        """
+        info = self.trailer.get(TK.INFO, None)
+        if info is None:
+            return None
+        else:
+            info = info.get_object()
+            if info is None:
+                raise PdfReadError(
+                    "Trailer not found or does not point to document information directory"
+                )
+            return cast(DictionaryObject, info)
+
+    @property
+    def _ID(self) -> Optional[ArrayObject]:
+        """
+        Provide access to "/ID". Standardized with PdfWriter.
+
+        Returns:
+            /ID array; None if the entry does not exist
+        """
+        id = self.trailer.get(TK.ID, None)
+        return None if id is None else cast(ArrayObject, id.get_object())
+
+    def _repr_mimebundle_(
+        self,
+        include: Union[None, Iterable[str]] = None,
+        exclude: Union[None, Iterable[str]] = None,
+    ) -> Dict[str, Any]:
+        """
+        Integration into Jupyter Notebooks.
+
+        This method returns a dictionary that maps a mime-type to its
+        representation.
+
+        See https://ipython.readthedocs.io/en/stable/config/integrating.html
+        """
+        self.stream.seek(0)
+        pdf_data = self.stream.read()
+        data = {
+            "application/pdf": pdf_data,
+        }
+
+        if include is not None:
+            # Filter representations based on include list
+            data = {k: v for k, v in data.items() if k in include}
+
+        if exclude is not None:
+            # Remove representations based on exclude list
+            data = {k: v for k, v in data.items() if k not in exclude}
+
+        return data
+
+    @property
+    def pdf_header(self) -> str:
+        """
+        The first 8 bytes of the file.
+
+        This is typically something like ``'%PDF-1.6'`` and can be used to
+        detect if the file is actually a PDF file and which version it is.
+        """
+        # TODO: Make this return a bytes object for consistency
+        #       but that needs a deprecation
+        loc = self.stream.tell()
+        self.stream.seek(0, 0)
+        pdf_file_version = self.stream.read(8).decode("utf-8", "backslashreplace")
+        self.stream.seek(loc, 0)  # return to where it was
+        return pdf_file_version
+
+    @property
+    def xmp_metadata(self) -> Optional[XmpInformation]:
+        """XMP (Extensible Metadata Platform) data."""
+        try:
+            self._override_encryption = True
+            return cast(XmpInformation, self.root_object.xmp_metadata)
+        finally:
+            self._override_encryption = False
+
+    def _get_page(self, page_number: int) -> PageObject:
+        """
+        Retrieve a page by number from this PDF file.
+
+        Args:
+            page_number: The page number to retrieve
+                (pages begin at zero)
+
+        Returns:
+            A :class:`PageObject<pypdf._page.PageObject>` instance.
+        """
+        if self.flattened_pages is None:
+            self._flatten()
+        assert self.flattened_pages is not None, "hint for mypy"
+        return self.flattened_pages[page_number]
+
+    def _get_page_number_by_indirect(
+        self, indirect_reference: Union[None, int, NullObject, IndirectObject]
+    ) -> Optional[int]:
+        """
+        Generate _page_id2num.
+
+        Args:
+            indirect_reference:
+
+        Returns:
+            The page number or None
+        """
+        if self._page_id2num is None:
+            self._page_id2num = {
+                x.indirect_reference.idnum: i for i, x in enumerate(self.pages)  # type: ignore
+            }
+
+        if indirect_reference is None or isinstance(indirect_reference, NullObject):
+            return None
+        if isinstance(indirect_reference, int):
+            idnum = indirect_reference
+        else:
+            idnum = indirect_reference.idnum
+        assert self._page_id2num is not None, "hint for mypy"
+        ret = self._page_id2num.get(idnum, None)
+        return ret
+
+    def _get_object_from_stream(
+        self, indirect_reference: IndirectObject
+    ) -> Union[int, PdfObject, str]:
+        # indirect reference to object in object stream
+        # read the entire object stream into memory
+        stmnum, idx = self.xref_objStm[indirect_reference.idnum]
+        obj_stm: EncodedStreamObject = IndirectObject(stmnum, 0, self).get_object()  # type: ignore
+        # This is an xref to a stream, so its type better be a stream
+        assert cast(str, obj_stm["/Type"]) == "/ObjStm"
+        # /N is the number of indirect objects in the stream
+        assert idx < obj_stm["/N"]
+        stream_data = BytesIO(b_(obj_stm.get_data()))
+        for i in range(obj_stm["/N"]):  # type: ignore
+            read_non_whitespace(stream_data)
+            stream_data.seek(-1, 1)
+            objnum = NumberObject.read_from_stream(stream_data)
+            read_non_whitespace(stream_data)
+            stream_data.seek(-1, 1)
+            offset = NumberObject.read_from_stream(stream_data)
+            read_non_whitespace(stream_data)
+            stream_data.seek(-1, 1)
+            if objnum != indirect_reference.idnum:
+                # We're only interested in one object
+                continue
+            if self.strict and idx != i:
+                raise PdfReadError("Object is in wrong index.")
+            stream_data.seek(int(obj_stm["/First"] + offset), 0)  # type: ignore
+
+            # to cope with some case where the 'pointer' is on a white space
+            read_non_whitespace(stream_data)
+            stream_data.seek(-1, 1)
+
+            try:
+                obj = read_object(stream_data, self)
+            except PdfStreamError as exc:
+                # Stream object cannot be read. Normally, a critical error, but
+                # Adobe Reader doesn't complain, so continue (in strict mode?)
+                logger_warning(
+                    f"Invalid stream (index {i}) within object "
+                    f"{indirect_reference.idnum} {indirect_reference.generation}: "
+                    f"{exc}",
+                    __name__,
+                )
+
+                if self.strict:  # pragma: no cover
+                    raise PdfReadError(
+                        f"Cannot read object stream: {exc}"
+                    )  # pragma: no cover
+                # Replace with null. Hopefully it's nothing important.
+                obj = NullObject()  # pragma: no cover
+            return obj
+
+        if self.strict:  # pragma: no cover
+            raise PdfReadError(
+                "This is a fatal error in strict mode."
+            )  # pragma: no cover
+        return NullObject()  # pragma: no cover
+
+    def get_object(
+        self, indirect_reference: Union[int, IndirectObject]
+    ) -> Optional[PdfObject]:
+        if isinstance(indirect_reference, int):
+            indirect_reference = IndirectObject(indirect_reference, 0, self)
+        retval = self.cache_get_indirect_object(
+            indirect_reference.generation, indirect_reference.idnum
+        )
+        if retval is not None:
+            return retval
+        if (
+            indirect_reference.generation == 0
+            and indirect_reference.idnum in self.xref_objStm
+        ):
+            retval = self._get_object_from_stream(indirect_reference)  # type: ignore
+        elif (
+            indirect_reference.generation in self.xref
+            and indirect_reference.idnum in self.xref[indirect_reference.generation]
+        ):
+            if self.xref_free_entry.get(indirect_reference.generation, {}).get(
+                indirect_reference.idnum, False
+            ):
+                return NullObject()
+            start = self.xref[indirect_reference.generation][indirect_reference.idnum]
+            self.stream.seek(start, 0)
+            try:
+                idnum, generation = self.read_object_header(self.stream)
+                if (
+                    idnum != indirect_reference.idnum
+                    or generation != indirect_reference.generation
+                ):
+                    raise PdfReadError("not matching, we parse the file for it")
+            except Exception:
+                if hasattr(self.stream, "getbuffer"):
+                    buf = bytes(self.stream.getbuffer())
+                else:
+                    p = self.stream.tell()
+                    self.stream.seek(0, 0)
+                    buf = self.stream.read(-1)
+                    self.stream.seek(p, 0)
+                m = re.search(
+                    rf"\s{indirect_reference.idnum}\s+{indirect_reference.generation}\s+obj".encode(),
+                    buf,
+                )
+                if m is not None:
+                    logger_warning(
+                        f"Object ID {indirect_reference.idnum},{indirect_reference.generation} ref repaired",
+                        __name__,
+                    )
+                    self.xref[indirect_reference.generation][
+                        indirect_reference.idnum
+                    ] = (m.start(0) + 1)
+                    self.stream.seek(m.start(0) + 1)
+                    idnum, generation = self.read_object_header(self.stream)
+                else:
+                    idnum = -1
+                    generation = -1  # exception will be raised below
+            if idnum != indirect_reference.idnum and self.xref_index:
+                # Xref table probably had bad indexes due to not being zero-indexed
+                if self.strict:
+                    raise PdfReadError(
+                        f"Expected object ID ({indirect_reference.idnum} {indirect_reference.generation}) "
+                        f"does not match actual ({idnum} {generation}); "
+                        "xref table not zero-indexed."
+                    )
+                # xref table is corrected in non-strict mode
+            elif idnum != indirect_reference.idnum and self.strict:
+                # some other problem
+                raise PdfReadError(
+                    f"Expected object ID ({indirect_reference.idnum} "
+                    f"{indirect_reference.generation}) does not match actual "
+                    f"({idnum} {generation})."
+                )
+            if self.strict:
+                assert generation == indirect_reference.generation
+            retval = read_object(self.stream, self)  # type: ignore
+
+            # override encryption is used for the /Encrypt dictionary
+            if not self._override_encryption and self._encryption is not None:
+                # if we don't have the encryption key:
+                if not self._encryption.is_decrypted():
+                    raise FileNotDecryptedError("File has not been decrypted")
+                # otherwise, decrypt here...
+                retval = cast(PdfObject, retval)
+                retval = self._encryption.decrypt_object(
+                    retval, indirect_reference.idnum, indirect_reference.generation
+                )
+        else:
+            if hasattr(self.stream, "getbuffer"):
+                buf = bytes(self.stream.getbuffer())
+            else:
+                p = self.stream.tell()
+                self.stream.seek(0, 0)
+                buf = self.stream.read(-1)
+                self.stream.seek(p, 0)
+            m = re.search(
+                rf"\s{indirect_reference.idnum}\s+{indirect_reference.generation}\s+obj".encode(),
+                buf,
+            )
+            if m is not None:
+                logger_warning(
+                    f"Object {indirect_reference.idnum} {indirect_reference.generation} found",
+                    __name__,
+                )
+                if indirect_reference.generation not in self.xref:
+                    self.xref[indirect_reference.generation] = {}
+                self.xref[indirect_reference.generation][indirect_reference.idnum] = (
+                    m.start(0) + 1
+                )
+                self.stream.seek(m.end(0) + 1)
+                skip_over_whitespace(self.stream)
+                self.stream.seek(-1, 1)
+                retval = read_object(self.stream, self)  # type: ignore
+
+                # override encryption is used for the /Encrypt dictionary
+                if not self._override_encryption and self._encryption is not None:
+                    # if we don't have the encryption key:
+                    if not self._encryption.is_decrypted():
+                        raise FileNotDecryptedError("File has not been decrypted")
+                    # otherwise, decrypt here...
+                    retval = cast(PdfObject, retval)
+                    retval = self._encryption.decrypt_object(
+                        retval, indirect_reference.idnum, indirect_reference.generation
+                    )
+            else:
+                logger_warning(
+                    f"Object {indirect_reference.idnum} {indirect_reference.generation} not defined.",
+                    __name__,
+                )
+                if self.strict:
+                    raise PdfReadError("Could not find object.")
+        self.cache_indirect_object(
+            indirect_reference.generation, indirect_reference.idnum, retval
+        )
+        return retval
+
+    def read_object_header(self, stream: StreamType) -> Tuple[int, int]:
+        # Should never be necessary to read out whitespace, since the
+        # cross-reference table should put us in the right spot to read the
+        # object header. In reality some files have stupid cross reference
+        # tables that are off by whitespace bytes.
+        extra = False
+        skip_over_comment(stream)
+        extra |= skip_over_whitespace(stream)
+        stream.seek(-1, 1)
+        idnum = read_until_whitespace(stream)
+        extra |= skip_over_whitespace(stream)
+        stream.seek(-1, 1)
+        generation = read_until_whitespace(stream)
+        extra |= skip_over_whitespace(stream)
+        stream.seek(-1, 1)
+
+        # although it's not used, it might still be necessary to read
+        _obj = stream.read(3)
+
+        read_non_whitespace(stream)
+        stream.seek(-1, 1)
+        if extra and self.strict:
+            logger_warning(
+                f"Superfluous whitespace found in object header {idnum} {generation}",  # type: ignore
+                __name__,
+            )
+        return int(idnum), int(generation)
+
+    def cache_get_indirect_object(
+        self, generation: int, idnum: int
+    ) -> Optional[PdfObject]:
+        return self.resolved_objects.get((generation, idnum))
+
+    def cache_indirect_object(
+        self, generation: int, idnum: int, obj: Optional[PdfObject]
+    ) -> Optional[PdfObject]:
+        if (generation, idnum) in self.resolved_objects:
+            msg = f"Overwriting cache for {generation} {idnum}"
+            if self.strict:
+                raise PdfReadError(msg)
+            logger_warning(msg, __name__)
+        self.resolved_objects[(generation, idnum)] = obj
+        if obj is not None:
+            obj.indirect_reference = IndirectObject(idnum, generation, self)
+        return obj
+
+    def _replace_object(self, indirect: IndirectObject, obj: PdfObject) -> PdfObject:
+        # function reserved for future dev
+        if indirect.pdf != self:
+            raise ValueError("Cannot update PdfReader with external object")
+        if (indirect.generation, indirect.idnum) not in self.resolved_objects:
+            raise ValueError("Cannot find referenced object")
+        self.resolved_objects[(indirect.generation, indirect.idnum)] = obj
+        obj.indirect_reference = indirect
+        return obj
+
+    def read(self, stream: StreamType) -> None:
+        self._basic_validation(stream)
+        self._find_eof_marker(stream)
+        startxref = self._find_startxref_pos(stream)
+
+        # check and eventually correct the startxref only in not strict
+        xref_issue_nr = self._get_xref_issues(stream, startxref)
+        if xref_issue_nr != 0:
+            if self.strict and xref_issue_nr:
+                raise PdfReadError("Broken xref table")
+            logger_warning(f"incorrect startxref pointer({xref_issue_nr})", __name__)
+
+        # read all cross reference tables and their trailers
+        self._read_xref_tables_and_trailers(stream, startxref, xref_issue_nr)
+
+        # if not zero-indexed, verify that the table is correct; change it if necessary
+        if self.xref_index and not self.strict:
+            loc = stream.tell()
+            for gen, xref_entry in self.xref.items():
+                if gen == 65535:
+                    continue
+                xref_k = sorted(
+                    xref_entry.keys()
+                )  # must ensure ascendant to prevent damage
+                for id in xref_k:
+                    stream.seek(xref_entry[id], 0)
+                    try:
+                        pid, _pgen = self.read_object_header(stream)
+                    except ValueError:
+                        self._rebuild_xref_table(stream)
+                        break
+                    if pid == id - self.xref_index:
+                        # fixing index item per item is required for revised PDF.
+                        self.xref[gen][pid] = self.xref[gen][id]
+                        del self.xref[gen][id]
+                    # if not, then either it's just plain wrong, or the
+                    # non-zero-index is actually correct
+            stream.seek(loc, 0)  # return to where it was
+
+        # remove wrong objects (not pointing to correct structures) - cf #2326
+        if not self.strict:
+            loc = stream.tell()
+            for gen, xref_entry in self.xref.items():
+                if gen == 65535:
+                    continue
+                ids = list(xref_entry.keys())
+                for id in ids:
+                    stream.seek(xref_entry[id], 0)
+                    try:
+                        self.read_object_header(stream)
+                    except ValueError:
+                        logger_warning(
+                            f"Ignoring wrong pointing object {id} {gen} (offset {xref_entry[id]})",
+                            __name__,
+                        )
+                        del xref_entry[id]  # we can delete the id, we are parsing ids
+            stream.seek(loc, 0)  # return to where it was
+
+    def _basic_validation(self, stream: StreamType) -> None:
+        """Ensure file is not empty. Read at most 5 bytes."""
+        stream.seek(0, os.SEEK_SET)
+        try:
+            header_byte = stream.read(5)
+        except UnicodeDecodeError:
+            raise UnsupportedOperation("cannot read header")
+        if header_byte == b"":
+            raise EmptyFileError("Cannot read an empty file")
+        elif header_byte != b"%PDF-":
+            if self.strict:
+                raise PdfReadError(
+                    f"PDF starts with '{header_byte.decode('utf8')}', "
+                    "but '%PDF-' expected"
+                )
+            else:
+                logger_warning(f"invalid pdf header: {header_byte}", __name__)
+        stream.seek(0, os.SEEK_END)
+
+    def _find_eof_marker(self, stream: StreamType) -> None:
+        """
+        Jump to the %%EOF marker.
+
+        According to the specs, the %%EOF marker should be at the very end of
+        the file. Hence for standard-compliant PDF documents this function will
+        read only the last part (DEFAULT_BUFFER_SIZE).
+        """
+        HEADER_SIZE = 8  # to parse whole file, Header is e.g. '%PDF-1.6'
+        line = b""
+        while line[:5] != b"%%EOF":
+            if stream.tell() < HEADER_SIZE:
+                if self.strict:
+                    raise PdfReadError("EOF marker not found")
+                else:
+                    logger_warning("EOF marker not found", __name__)
+            line = read_previous_line(stream)
+
+    def _find_startxref_pos(self, stream: StreamType) -> int:
+        """
+        Find startxref entry - the location of the xref table.
+
+        Args:
+            stream:
+
+        Returns:
+            The bytes offset
+        """
+        line = read_previous_line(stream)
+        try:
+            startxref = int(line)
+        except ValueError:
+            # 'startxref' may be on the same line as the location
+            if not line.startswith(b"startxref"):
+                raise PdfReadError("startxref not found")
+            startxref = int(line[9:].strip())
+            logger_warning("startxref on same line as offset", __name__)
+        else:
+            line = read_previous_line(stream)
+            if line[:9] != b"startxref":
+                raise PdfReadError("startxref not found")
+        return startxref
+
+    def _read_standard_xref_table(self, stream: StreamType) -> None:
+        # standard cross-reference table
+        ref = stream.read(3)
+        if ref != b"ref":
+            raise PdfReadError("xref table read error")
+        read_non_whitespace(stream)
+        stream.seek(-1, 1)
+        first_time = True  # check if the first time looking at the xref table
+        while True:
+            num = cast(int, read_object(stream, self))
+            if first_time and num != 0:
+                self.xref_index = num
+                if self.strict:
+                    logger_warning(
+                        "Xref table not zero-indexed. ID numbers for objects will be corrected.",
+                        __name__,
+                    )
+                    # if table not zero indexed, could be due to error from when PDF was created
+                    # which will lead to mismatched indices later on, only warned and corrected if self.strict==True
+            first_time = False
+            read_non_whitespace(stream)
+            stream.seek(-1, 1)
+            size = cast(int, read_object(stream, self))
+            if not isinstance(size, int):
+                logger_warning(
+                    "Invalid/Truncated xref table. Rebuilding it.",
+                    __name__,
+                )
+                self._rebuild_xref_table(stream)
+                stream.read()
+                return
+            read_non_whitespace(stream)
+            stream.seek(-1, 1)
+            cnt = 0
+            while cnt < size:
+                line = stream.read(20)
+
+                # It's very clear in section 3.4.3 of the PDF spec
+                # that all cross-reference table lines are a fixed
+                # 20 bytes (as of PDF 1.7). However, some files have
+                # 21-byte entries (or more) due to the use of \r\n
+                # (CRLF) EOL's. Detect that case, and adjust the line
+                # until it does not begin with a \r (CR) or \n (LF).
+                while line[0] in b"\x0D\x0A":
+                    stream.seek(-20 + 1, 1)
+                    line = stream.read(20)
+
+                # On the other hand, some malformed PDF files
+                # use a single character EOL without a preceding
+                # space. Detect that case, and seek the stream
+                # back one character (0-9 means we've bled into
+                # the next xref entry, t means we've bled into the
+                # text "trailer"):
+                if line[-1] in b"0123456789t":
+                    stream.seek(-1, 1)
+
+                try:
+                    offset_b, generation_b = line[:16].split(b" ")
+                    entry_type_b = line[17:18]
+
+                    offset, generation = int(offset_b), int(generation_b)
+                except Exception:
+                    # if something wrong occurred
+                    if hasattr(stream, "getbuffer"):
+                        buf = bytes(stream.getbuffer())
+                    else:
+                        p = stream.tell()
+                        stream.seek(0, 0)
+                        buf = stream.read(-1)
+                        stream.seek(p)
+
+                    f = re.search(f"{num}\\s+(\\d+)\\s+obj".encode(), buf)
+                    if f is None:
+                        logger_warning(
+                            f"entry {num} in Xref table invalid; object not found",
+                            __name__,
+                        )
+                        generation = 65535
+                        offset = -1
+                    else:
+                        logger_warning(
+                            f"entry {num} in Xref table invalid but object found",
+                            __name__,
+                        )
+                        generation = int(f.group(1))
+                        offset = f.start()
+
+                if generation not in self.xref:
+                    self.xref[generation] = {}
+                    self.xref_free_entry[generation] = {}
+                if num in self.xref[generation]:
+                    # It really seems like we should allow the last
+                    # xref table in the file to override previous
+                    # ones. Since we read the file backwards, assume
+                    # any existing key is already set correctly.
+                    pass
+                else:
+                    if entry_type_b == b"n":
+                        self.xref[generation][num] = offset
+                    try:
+                        self.xref_free_entry[generation][num] = entry_type_b == b"f"
+                    except Exception:
+                        pass
+                    try:
+                        self.xref_free_entry[65535][num] = entry_type_b == b"f"
+                    except Exception:
+                        pass
+                cnt += 1
+                num += 1
+            read_non_whitespace(stream)
+            stream.seek(-1, 1)
+            trailer_tag = stream.read(7)
+            if trailer_tag != b"trailer":
+                # more xrefs!
+                stream.seek(-7, 1)
+            else:
+                break
+
+    def _read_xref_tables_and_trailers(
+        self, stream: StreamType, startxref: Optional[int], xref_issue_nr: int
+    ) -> None:
+        self.xref = {}
+        self.xref_free_entry = {}
+        self.xref_objStm = {}
+        self.trailer = DictionaryObject()
+        while startxref is not None:
+            # load the xref table
+            stream.seek(startxref, 0)
+            x = stream.read(1)
+            if x in b"\r\n":
+                x = stream.read(1)
+            if x == b"x":
+                startxref = self._read_xref(stream)
+            elif xref_issue_nr:
+                try:
+                    self._rebuild_xref_table(stream)
+                    break
+                except Exception:
+                    xref_issue_nr = 0
+            elif x.isdigit():
+                try:
+                    xrefstream = self._read_pdf15_xref_stream(stream)
+                except Exception as e:
+                    if TK.ROOT in self.trailer:
+                        logger_warning(
+                            f"Previous trailer can not be read {e.args}",
+                            __name__,
+                        )
+                        break
+                    else:
+                        raise PdfReadError(f"trailer can not be read {e.args}")
+                trailer_keys = TK.ROOT, TK.ENCRYPT, TK.INFO, TK.ID, TK.SIZE
+                for key in trailer_keys:
+                    if key in xrefstream and key not in self.trailer:
+                        self.trailer[NameObject(key)] = xrefstream.raw_get(key)
+                if "/XRefStm" in xrefstream:
+                    p = stream.tell()
+                    stream.seek(cast(int, xrefstream["/XRefStm"]) + 1, 0)
+                    self._read_pdf15_xref_stream(stream)
+                    stream.seek(p, 0)
+                if "/Prev" in xrefstream:
+                    startxref = cast(int, xrefstream["/Prev"])
+                else:
+                    break
+            else:
+                startxref = self._read_xref_other_error(stream, startxref)
+
+    def _read_xref(self, stream: StreamType) -> Optional[int]:
+        self._read_standard_xref_table(stream)
+        if stream.read(1) == b"":
+            return None
+        stream.seek(-1, 1)
+        read_non_whitespace(stream)
+        stream.seek(-1, 1)
+        new_trailer = cast(Dict[str, Any], read_object(stream, self))
+        for key, value in new_trailer.items():
+            if key not in self.trailer:
+                self.trailer[key] = value
+        if "/XRefStm" in new_trailer:
+            p = stream.tell()
+            stream.seek(cast(int, new_trailer["/XRefStm"]) + 1, 0)
+            try:
+                self._read_pdf15_xref_stream(stream)
+            except Exception:
+                logger_warning(
+                    f"XRef object at {new_trailer['/XRefStm']} can not be read, some object may be missing",
+                    __name__,
+                )
+            stream.seek(p, 0)
+        if "/Prev" in new_trailer:
+            startxref = new_trailer["/Prev"]
+            return startxref
+        else:
+            return None
+
+    def _read_xref_other_error(
+        self, stream: StreamType, startxref: int
+    ) -> Optional[int]:
+        # some PDFs have /Prev=0 in the trailer, instead of no /Prev
+        if startxref == 0:
+            if self.strict:
+                raise PdfReadError(
+                    "/Prev=0 in the trailer (try opening with strict=False)"
+                )
+            logger_warning(
+                "/Prev=0 in the trailer - assuming there is no previous xref table",
+                __name__,
+            )
+            return None
+        # bad xref character at startxref. Let's see if we can find
+        # the xref table nearby, as we've observed this error with an
+        # off-by-one before.
+        stream.seek(-11, 1)
+        tmp = stream.read(20)
+        xref_loc = tmp.find(b"xref")
+        if xref_loc != -1:
+            startxref -= 10 - xref_loc
+            return startxref
+        # No explicit xref table, try finding a cross-reference stream.
+        stream.seek(startxref, 0)
+        for look in range(25):  # value extended to cope with more linearized files
+            if stream.read(1).isdigit():
+                # This is not a standard PDF, consider adding a warning
+                startxref += look
+                return startxref
+        # no xref table found at specified location
+        if "/Root" in self.trailer and not self.strict:
+            # if Root has been already found, just raise warning
+            logger_warning("Invalid parent xref., rebuild xref", __name__)
+            try:
+                self._rebuild_xref_table(stream)
+                return None
+            except Exception:
+                raise PdfReadError("can not rebuild xref")
+        raise PdfReadError("Could not find xref table at specified location")
+
+    def _read_pdf15_xref_stream(
+        self, stream: StreamType
+    ) -> Union[ContentStream, EncodedStreamObject, DecodedStreamObject]:
+        # PDF 1.5+ Cross-Reference Stream
+        stream.seek(-1, 1)
+        idnum, generation = self.read_object_header(stream)
+        xrefstream = cast(ContentStream, read_object(stream, self))
+        assert cast(str, xrefstream["/Type"]) == "/XRef"
+        self.cache_indirect_object(generation, idnum, xrefstream)
+        stream_data = BytesIO(b_(xrefstream.get_data()))
+        # Index pairs specify the subsections in the dictionary. If
+        # none create one subsection that spans everything.
+        idx_pairs = xrefstream.get("/Index", [0, xrefstream.get("/Size")])
+        entry_sizes = cast(Dict[Any, Any], xrefstream.get("/W"))
+        assert len(entry_sizes) >= 3
+        if self.strict and len(entry_sizes) > 3:
+            raise PdfReadError(f"Too many entry sizes: {entry_sizes}")
+
+        def get_entry(i: int) -> Union[int, Tuple[int, ...]]:
+            # Reads the correct number of bytes for each entry. See the
+            # discussion of the W parameter in PDF spec table 17.
+            if entry_sizes[i] > 0:
+                d = stream_data.read(entry_sizes[i])
+                return convert_to_int(d, entry_sizes[i])
+
+            # PDF Spec Table 17: A value of zero for an element in the
+            # W array indicates...the default value shall be used
+            if i == 0:
+                return 1  # First value defaults to 1
+            else:
+                return 0
+
+        def used_before(num: int, generation: Union[int, Tuple[int, ...]]) -> bool:
+            # We move backwards through the xrefs, don't replace any.
+            return num in self.xref.get(generation, []) or num in self.xref_objStm  # type: ignore
+
+        # Iterate through each subsection
+        self._read_xref_subsections(idx_pairs, get_entry, used_before)
+        return xrefstream
+
+    @staticmethod
+    def _get_xref_issues(stream: StreamType, startxref: int) -> int:
+        """
+        Return an int which indicates an issue. 0 means there is no issue.
+
+        Args:
+            stream:
+            startxref:
+
+        Returns:
+            0 means no issue, other values represent specific issues.
+        """
+        stream.seek(startxref - 1, 0)  # -1 to check character before
+        line = stream.read(1)
+        if line == b"j":
+            line = stream.read(1)
+        if line not in b"\r\n \t":
+            return 1
+        line = stream.read(4)
+        if line != b"xref":
+            # not an xref so check if it is an XREF object
+            line = b""
+            while line in b"0123456789 \t":
+                line = stream.read(1)
+                if line == b"":
+                    return 2
+            line += stream.read(2)  # 1 char already read, +2 to check "obj"
+            if line.lower() != b"obj":
+                return 3
+        return 0
+
+    def _rebuild_xref_table(self, stream: StreamType) -> None:
+        self.xref = {}
+        stream.seek(0, 0)
+        f_ = stream.read(-1)
+
+        for m in re.finditer(rb"[\r\n \t][ \t]*(\d+)[ \t]+(\d+)[ \t]+obj", f_):
+            idnum = int(m.group(1))
+            generation = int(m.group(2))
+            if generation not in self.xref:
+                self.xref[generation] = {}
+            self.xref[generation][idnum] = m.start(1)
+        stream.seek(0, 0)
+        for m in re.finditer(rb"[\r\n \t][ \t]*trailer[\r\n \t]*(<<)", f_):
+            stream.seek(m.start(1), 0)
+            new_trailer = cast(Dict[Any, Any], read_object(stream, self))
+            # Here, we are parsing the file from start to end, the new data have to erase the existing.
+            for key, value in list(new_trailer.items()):
+                self.trailer[key] = value
+
+    def _read_xref_subsections(
+        self,
+        idx_pairs: List[int],
+        get_entry: Callable[[int], Union[int, Tuple[int, ...]]],
+        used_before: Callable[[int, Union[int, Tuple[int, ...]]], bool],
+    ) -> None:
+        for start, size in self._pairs(idx_pairs):
+            # The subsections must increase
+            for num in range(start, start + size):
+                # The first entry is the type
+                xref_type = get_entry(0)
+                # The rest of the elements depend on the xref_type
+                if xref_type == 0:
+                    # linked list of free objects
+                    next_free_object = get_entry(1)  # noqa: F841
+                    next_generation = get_entry(2)  # noqa: F841
+                elif xref_type == 1:
+                    # objects that are in use but are not compressed
+                    byte_offset = get_entry(1)
+                    generation = get_entry(2)
+                    if generation not in self.xref:
+                        self.xref[generation] = {}  # type: ignore
+                    if not used_before(num, generation):
+                        self.xref[generation][num] = byte_offset  # type: ignore
+                elif xref_type == 2:
+                    # compressed objects
+                    objstr_num = get_entry(1)
+                    obstr_idx = get_entry(2)
+                    generation = 0  # PDF spec table 18, generation is 0
+                    if not used_before(num, generation):
+                        self.xref_objStm[num] = (objstr_num, obstr_idx)
+                elif self.strict:
+                    raise PdfReadError(f"Unknown xref type: {xref_type}")
+
+    def _pairs(self, array: List[int]) -> Iterable[Tuple[int, int]]:
+        i = 0
+        while True:
+            yield array[i], array[i + 1]
+            i += 2
+            if (i + 1) >= len(array):
+                break
+
+    def decrypt(self, password: Union[str, bytes]) -> PasswordType:
+        """
+        When using an encrypted / secured PDF file with the PDF Standard
+        encryption handler, this function will allow the file to be decrypted.
+        It checks the given password against the document's user password and
+        owner password, and then stores the resulting decryption key if either
+        password is correct.
+
+        It does not matter which password was matched. Both passwords provide
+        the correct decryption key that will allow the document to be used with
+        this library.
+
+        Args:
+            password: The password to match.
+
+        Returns:
+            An indicator if the document was decrypted and whether it was the
+            owner password or the user password.
+        """
+        if not self._encryption:
+            raise PdfReadError("Not encrypted file")
+        # TODO: raise Exception for wrong password
+        return self._encryption.verify(password)
+
+    @property
+    def is_encrypted(self) -> bool:
+        """
+        Read-only boolean property showing whether this PDF file is encrypted.
+
+        Note that this property, if true, will remain true even after the
+        :meth:`decrypt()<pypdf.PdfReader.decrypt>` method is called.
+        """
+        return TK.ENCRYPT in self.trailer
+
+    def add_form_topname(self, name: str) -> Optional[DictionaryObject]:
+        """
+        Add a top level form that groups all form fields below it.
+
+        Args:
+            name: text string of the "/T" Attribute of the created object
+
+        Returns:
+            The created object. ``None`` means no object was created.
+        """
+        catalog = self.root_object
+
+        if "/AcroForm" not in catalog or not isinstance(
+            catalog["/AcroForm"], DictionaryObject
+        ):
+            return None
+        acroform = cast(DictionaryObject, catalog[NameObject("/AcroForm")])
+        if "/Fields" not in acroform:
+            # TODO: :No error returns but may be extended for XFA Forms
+            return None
+
+        interim = DictionaryObject()
+        interim[NameObject("/T")] = TextStringObject(name)
+        interim[NameObject("/Kids")] = acroform[NameObject("/Fields")]
+        self.cache_indirect_object(
+            0,
+            max([i for (g, i) in self.resolved_objects if g == 0]) + 1,
+            interim,
+        )
+        arr = ArrayObject()
+        arr.append(interim.indirect_reference)
+        acroform[NameObject("/Fields")] = arr
+        for o in cast(ArrayObject, interim["/Kids"]):
+            obj = o.get_object()
+            if "/Parent" in obj:
+                logger_warning(
+                    f"Top Level Form Field {obj.indirect_reference} have a non-expected parent",
+                    __name__,
+                )
+            obj[NameObject("/Parent")] = interim.indirect_reference
+        return interim
+
+    def rename_form_topname(self, name: str) -> Optional[DictionaryObject]:
+        """
+        Rename top level form field that all form fields below it.
+
+        Args:
+            name: text string of the "/T" field of the created object
+
+        Returns:
+            The modified object. ``None`` means no object was modified.
+        """
+        catalog = self.root_object
+
+        if "/AcroForm" not in catalog or not isinstance(
+            catalog["/AcroForm"], DictionaryObject
+        ):
+            return None
+        acroform = cast(DictionaryObject, catalog[NameObject("/AcroForm")])
+        if "/Fields" not in acroform:
+            return None
+
+        interim = cast(
+            DictionaryObject,
+            cast(ArrayObject, acroform[NameObject("/Fields")])[0].get_object(),
+        )
+        interim[NameObject("/T")] = TextStringObject(name)
+        return interim
diff --git a/.venv/lib/python3.12/site-packages/pypdf/_text_extraction/__init__.py b/.venv/lib/python3.12/site-packages/pypdf/_text_extraction/__init__.py
new file mode 100644
index 00000000..3b1d687e
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/_text_extraction/__init__.py
@@ -0,0 +1,285 @@
+"""
+Code related to text extraction.
+
+Some parts are still in _page.py. In doubt, they will stay there.
+"""
+
+import math
+from typing import Any, Callable, Dict, List, Optional, Tuple, Union
+
+from ..generic import DictionaryObject, TextStringObject, encode_pdfdocencoding
+
+CUSTOM_RTL_MIN: int = -1
+CUSTOM_RTL_MAX: int = -1
+CUSTOM_RTL_SPECIAL_CHARS: List[int] = []
+LAYOUT_NEW_BT_GROUP_SPACE_WIDTHS: int = 5
+
+
+class OrientationNotFoundError(Exception):
+    pass
+
+
+def set_custom_rtl(
+    _min: Union[str, int, None] = None,
+    _max: Union[str, int, None] = None,
+    specials: Union[str, List[int], None] = None,
+) -> Tuple[int, int, List[int]]:
+    """
+    Change the Right-To-Left and special characters custom parameters.
+
+    Args:
+        _min: The new minimum value for the range of custom characters that
+            will be written right to left.
+            If set to ``None``, the value will not be changed.
+            If set to an integer or string, it will be converted to its ASCII code.
+            The default value is -1, which sets no additional range to be converted.
+        _max: The new maximum value for the range of custom characters that will
+            be written right to left.
+            If set to ``None``, the value will not be changed.
+            If set to an integer or string, it will be converted to its ASCII code.
+            The default value is -1, which sets no additional range to be converted.
+        specials: The new list of special characters to be inserted in the
+            current insertion order.
+            If set to ``None``, the current value will not be changed.
+            If set to a string, it will be converted to a list of ASCII codes.
+            The default value is an empty list.
+
+    Returns:
+        A tuple containing the new values for ``CUSTOM_RTL_MIN``,
+        ``CUSTOM_RTL_MAX``, and ``CUSTOM_RTL_SPECIAL_CHARS``.
+    """
+    global CUSTOM_RTL_MIN, CUSTOM_RTL_MAX, CUSTOM_RTL_SPECIAL_CHARS
+    if isinstance(_min, int):
+        CUSTOM_RTL_MIN = _min
+    elif isinstance(_min, str):
+        CUSTOM_RTL_MIN = ord(_min)
+    if isinstance(_max, int):
+        CUSTOM_RTL_MAX = _max
+    elif isinstance(_max, str):
+        CUSTOM_RTL_MAX = ord(_max)
+    if isinstance(specials, str):
+        CUSTOM_RTL_SPECIAL_CHARS = [ord(x) for x in specials]
+    elif isinstance(specials, list):
+        CUSTOM_RTL_SPECIAL_CHARS = specials
+    return CUSTOM_RTL_MIN, CUSTOM_RTL_MAX, CUSTOM_RTL_SPECIAL_CHARS
+
+
+def mult(m: List[float], n: List[float]) -> List[float]:
+    return [
+        m[0] * n[0] + m[1] * n[2],
+        m[0] * n[1] + m[1] * n[3],
+        m[2] * n[0] + m[3] * n[2],
+        m[2] * n[1] + m[3] * n[3],
+        m[4] * n[0] + m[5] * n[2] + n[4],
+        m[4] * n[1] + m[5] * n[3] + n[5],
+    ]
+
+
+def orient(m: List[float]) -> int:
+    if m[3] > 1e-6:
+        return 0
+    elif m[3] < -1e-6:
+        return 180
+    elif m[1] > 0:
+        return 90
+    else:
+        return 270
+
+
+def crlf_space_check(
+    text: str,
+    cmtm_prev: Tuple[List[float], List[float]],
+    cmtm_matrix: Tuple[List[float], List[float]],
+    memo_cmtm: Tuple[List[float], List[float]],
+    cmap: Tuple[
+        Union[str, Dict[int, str]], Dict[str, str], str, Optional[DictionaryObject]
+    ],
+    orientations: Tuple[int, ...],
+    output: str,
+    font_size: float,
+    visitor_text: Optional[Callable[[Any, Any, Any, Any, Any], None]],
+    spacewidth: float,
+) -> Tuple[str, str, List[float], List[float]]:
+    cm_prev = cmtm_prev[0]
+    tm_prev = cmtm_prev[1]
+    cm_matrix = cmtm_matrix[0]
+    tm_matrix = cmtm_matrix[1]
+    memo_cm = memo_cmtm[0]
+    memo_tm = memo_cmtm[1]
+
+    m_prev = mult(tm_prev, cm_prev)
+    m = mult(tm_matrix, cm_matrix)
+    orientation = orient(m)
+    delta_x = m[4] - m_prev[4]
+    delta_y = m[5] - m_prev[5]
+    k = math.sqrt(abs(m[0] * m[3]) + abs(m[1] * m[2]))
+    f = font_size * k
+    cm_prev = m
+    if orientation not in orientations:
+        raise OrientationNotFoundError
+    try:
+        if orientation == 0:
+            if delta_y < -0.8 * f:
+                if (output + text)[-1] != "\n":
+                    output += text + "\n"
+                    if visitor_text is not None:
+                        visitor_text(
+                            text + "\n",
+                            memo_cm,
+                            memo_tm,
+                            cmap[3],
+                            font_size,
+                        )
+                    text = ""
+            elif (
+                abs(delta_y) < f * 0.3
+                and abs(delta_x) > spacewidth * f * 15
+                and (output + text)[-1] != " "
+            ):
+                text += " "
+        elif orientation == 180:
+            if delta_y > 0.8 * f:
+                if (output + text)[-1] != "\n":
+                    output += text + "\n"
+                    if visitor_text is not None:
+                        visitor_text(
+                            text + "\n",
+                            memo_cm,
+                            memo_tm,
+                            cmap[3],
+                            font_size,
+                        )
+                    text = ""
+            elif (
+                abs(delta_y) < f * 0.3
+                and abs(delta_x) > spacewidth * f * 15
+                and (output + text)[-1] != " "
+            ):
+                text += " "
+        elif orientation == 90:
+            if delta_x > 0.8 * f:
+                if (output + text)[-1] != "\n":
+                    output += text + "\n"
+                    if visitor_text is not None:
+                        visitor_text(
+                            text + "\n",
+                            memo_cm,
+                            memo_tm,
+                            cmap[3],
+                            font_size,
+                        )
+                    text = ""
+            elif (
+                abs(delta_x) < f * 0.3
+                and abs(delta_y) > spacewidth * f * 15
+                and (output + text)[-1] != " "
+            ):
+                text += " "
+        elif orientation == 270:
+            if delta_x < -0.8 * f:
+                if (output + text)[-1] != "\n":
+                    output += text + "\n"
+                    if visitor_text is not None:
+                        visitor_text(
+                            text + "\n",
+                            memo_cm,
+                            memo_tm,
+                            cmap[3],
+                            font_size,
+                        )
+                    text = ""
+            elif (
+                abs(delta_x) < f * 0.3
+                and abs(delta_y) > spacewidth * f * 15
+                and (output + text)[-1] != " "
+            ):
+                text += " "
+    except Exception:
+        pass
+    tm_prev = tm_matrix.copy()
+    cm_prev = cm_matrix.copy()
+    return text, output, cm_prev, tm_prev
+
+
+def handle_tj(
+    text: str,
+    operands: List[Union[str, TextStringObject]],
+    cm_matrix: List[float],
+    tm_matrix: List[float],
+    cmap: Tuple[
+        Union[str, Dict[int, str]], Dict[str, str], str, Optional[DictionaryObject]
+    ],
+    orientations: Tuple[int, ...],
+    output: str,
+    font_size: float,
+    rtl_dir: bool,
+    visitor_text: Optional[Callable[[Any, Any, Any, Any, Any], None]],
+) -> Tuple[str, bool]:
+    m = mult(tm_matrix, cm_matrix)
+    orientation = orient(m)
+    if orientation in orientations and len(operands) > 0:
+        if isinstance(operands[0], str):
+            text += operands[0]
+        else:
+            t: str = ""
+            tt: bytes = (
+                encode_pdfdocencoding(operands[0])
+                if isinstance(operands[0], str)
+                else operands[0]
+            )
+            if isinstance(cmap[0], str):
+                try:
+                    t = tt.decode(cmap[0], "surrogatepass")  # apply str encoding
+                except Exception:
+                    # the data does not match the expectation,
+                    # we use the alternative ;
+                    # text extraction may not be good
+                    t = tt.decode(
+                        "utf-16-be" if cmap[0] == "charmap" else "charmap",
+                        "surrogatepass",
+                    )  # apply str encoding
+            else:  # apply dict encoding
+                t = "".join(
+                    [cmap[0][x] if x in cmap[0] else bytes((x,)).decode() for x in tt]
+                )
+            # "\u0590 - \u08FF \uFB50 - \uFDFF"
+            for x in [cmap[1][x] if x in cmap[1] else x for x in t]:
+                # x can be a sequence of bytes ; ex: habibi.pdf
+                if len(x) == 1:
+                    xx = ord(x)
+                else:
+                    xx = 1
+                # fmt: off
+                if (
+                    # cases where the current inserting order is kept
+                    (xx <= 0x2F)                        # punctuations but...
+                    or 0x3A <= xx <= 0x40               # numbers (x30-39)
+                    or 0x2000 <= xx <= 0x206F           # upper punctuations..
+                    or 0x20A0 <= xx <= 0x21FF           # but (numbers) indices/exponents
+                    or xx in CUSTOM_RTL_SPECIAL_CHARS   # customized....
+                ):
+                    text = x + text if rtl_dir else text + x
+                elif (  # right-to-left characters set
+                    0x0590 <= xx <= 0x08FF
+                    or 0xFB1D <= xx <= 0xFDFF
+                    or 0xFE70 <= xx <= 0xFEFF
+                    or CUSTOM_RTL_MIN <= xx <= CUSTOM_RTL_MAX
+                ):
+                    if not rtl_dir:
+                        rtl_dir = True
+                        output += text
+                        if visitor_text is not None:
+                            visitor_text(text, cm_matrix, tm_matrix, cmap[3], font_size)
+                        text = ""
+                    text = x + text
+                else:  # left-to-right
+                    # print(">",xx,x,end="")
+                    if rtl_dir:
+                        rtl_dir = False
+                        output += text
+                        if visitor_text is not None:
+                            visitor_text(text, cm_matrix, tm_matrix, cmap[3], font_size)
+                        text = ""
+                    text = text + x
+                # fmt: on
+    return text, rtl_dir
diff --git a/.venv/lib/python3.12/site-packages/pypdf/_text_extraction/_layout_mode/__init__.py b/.venv/lib/python3.12/site-packages/pypdf/_text_extraction/_layout_mode/__init__.py
new file mode 100644
index 00000000..8f4d5929
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/_text_extraction/_layout_mode/__init__.py
@@ -0,0 +1,16 @@
+"""Layout mode text extraction extension for pypdf"""
+from ._fixed_width_page import (
+    fixed_char_width,
+    fixed_width_page,
+    text_show_operations,
+    y_coordinate_groups,
+)
+from ._font import Font
+
+__all__ = [
+    "fixed_char_width",
+    "fixed_width_page",
+    "text_show_operations",
+    "y_coordinate_groups",
+    "Font",
+]
diff --git a/.venv/lib/python3.12/site-packages/pypdf/_text_extraction/_layout_mode/_fixed_width_page.py b/.venv/lib/python3.12/site-packages/pypdf/_text_extraction/_layout_mode/_fixed_width_page.py
new file mode 100644
index 00000000..1be50095
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/_text_extraction/_layout_mode/_fixed_width_page.py
@@ -0,0 +1,381 @@
+"""Extract PDF text preserving the layout of the source PDF"""
+
+import sys
+from itertools import groupby
+from math import ceil
+from pathlib import Path
+from typing import Any, Dict, Iterator, List, Optional, Tuple
+
+from ..._utils import logger_warning
+from .. import LAYOUT_NEW_BT_GROUP_SPACE_WIDTHS
+from ._font import Font
+from ._text_state_manager import TextStateManager
+from ._text_state_params import TextStateParams
+
+if sys.version_info >= (3, 8):
+    from typing import Literal, TypedDict
+else:
+    from typing_extensions import Literal, TypedDict
+
+
+class BTGroup(TypedDict):
+    """
+    Dict describing a line of text rendered within a BT/ET operator pair.
+    If multiple text show operations render text on the same line, the text
+    will be combined into a single BTGroup dict.
+
+    Keys:
+        tx: x coordinate of first character in BTGroup
+        ty: y coordinate of first character in BTGroup
+        font_size: nominal font size
+        font_height: effective font height
+        text: rendered text
+        displaced_tx: x coordinate of last character in BTGroup
+        flip_sort: -1 if page is upside down, else 1
+    """
+
+    tx: float
+    ty: float
+    font_size: float
+    font_height: float
+    text: str
+    displaced_tx: float
+    flip_sort: Literal[-1, 1]
+
+
+def bt_group(tj_op: TextStateParams, rendered_text: str, dispaced_tx: float) -> BTGroup:
+    """
+    BTGroup constructed from a TextStateParams instance, rendered text, and
+    displaced tx value.
+
+    Args:
+        tj_op (TextStateParams): TextStateParams instance
+        rendered_text (str): rendered text
+        dispaced_tx (float): x coordinate of last character in BTGroup
+    """
+    return BTGroup(
+        tx=tj_op.tx,
+        ty=tj_op.ty,
+        font_size=tj_op.font_size,
+        font_height=tj_op.font_height,
+        text=rendered_text,
+        displaced_tx=dispaced_tx,
+        flip_sort=-1 if tj_op.flip_vertical else 1,
+    )
+
+
+def recurs_to_target_op(
+    ops: Iterator[Tuple[List[Any], bytes]],
+    text_state_mgr: TextStateManager,
+    end_target: Literal[b"Q", b"ET"],
+    fonts: Dict[str, Font],
+    strip_rotated: bool = True,
+) -> Tuple[List[BTGroup], List[TextStateParams]]:
+    """
+    Recurse operators between BT/ET and/or q/Q operators managing the transform
+    stack and capturing text positioning and rendering data.
+
+    Args:
+        ops: iterator of operators in content stream
+        text_state_mgr: a TextStateManager instance
+        end_target: Either b"Q" (ends b"q" op) or b"ET" (ends b"BT" op)
+        fonts: font dictionary as returned by PageObject._layout_mode_fonts()
+
+    Returns:
+        tuple: list of BTGroup dicts + list of TextStateParams dataclass instances.
+    """
+    # 1 entry per line of text rendered within each BT/ET operation.
+    bt_groups: List[BTGroup] = []
+
+    # 1 entry per text show operator (Tj/TJ/'/")
+    tj_ops: List[TextStateParams] = []
+
+    if end_target == b"Q":
+        # add new q level. cm's added at this level will be popped at next b'Q'
+        text_state_mgr.add_q()
+
+    while True:
+        try:
+            operands, op = next(ops)
+        except StopIteration:
+            return bt_groups, tj_ops
+        if op == end_target:
+            if op == b"Q":
+                text_state_mgr.remove_q()
+            if op == b"ET":
+                if not tj_ops:
+                    return bt_groups, tj_ops
+                _text = ""
+                bt_idx = 0  # idx of first tj in this bt group
+                last_displaced_tx = tj_ops[bt_idx].displaced_tx
+                last_ty = tj_ops[bt_idx].ty
+                for _idx, _tj in enumerate(
+                    tj_ops
+                ):  # ... build text from new Tj operators
+                    if strip_rotated and _tj.rotated:
+                        continue
+                    # if the y position of the text is greater than the font height, assume
+                    # the text is on a new line and start a new group
+                    if abs(_tj.ty - last_ty) > _tj.font_height:
+                        if _text.strip():
+                            bt_groups.append(
+                                bt_group(tj_ops[bt_idx], _text, last_displaced_tx)
+                            )
+                        bt_idx = _idx
+                        _text = ""
+
+                    # if the x position of the text is less than the last x position by
+                    # more than 5 spaces widths, assume the text order should be flipped
+                    # and start a new group
+                    if (
+                        last_displaced_tx - _tj.tx
+                        > _tj.space_tx * LAYOUT_NEW_BT_GROUP_SPACE_WIDTHS
+                    ):
+                        if _text.strip():
+                            bt_groups.append(
+                                bt_group(tj_ops[bt_idx], _text, last_displaced_tx)
+                            )
+                        bt_idx = _idx
+                        last_displaced_tx = _tj.displaced_tx
+                        _text = ""
+
+                    # calculate excess x translation based on ending tx of previous Tj.
+                    # multiply by bool (_idx != bt_idx) to ensure spaces aren't double
+                    # applied to the first tj of a BTGroup in fixed_width_page().
+                    excess_tx = round(_tj.tx - last_displaced_tx, 3) * (_idx != bt_idx)
+                    # space_tx could be 0 if either Tz or font_size was 0 for this _tj.
+                    spaces = int(excess_tx // _tj.space_tx) if _tj.space_tx else 0
+                    new_text = f'{" " * spaces}{_tj.txt}'
+
+                    last_ty = _tj.ty
+                    _text = f"{_text}{new_text}"
+                    last_displaced_tx = _tj.displaced_tx
+                if _text:
+                    bt_groups.append(bt_group(tj_ops[bt_idx], _text, last_displaced_tx))
+                text_state_mgr.reset_tm()
+            return bt_groups, tj_ops
+        if op == b"q":
+            bts, tjs = recurs_to_target_op(
+                ops, text_state_mgr, b"Q", fonts, strip_rotated
+            )
+            bt_groups.extend(bts)
+            tj_ops.extend(tjs)
+        elif op == b"cm":
+            text_state_mgr.add_cm(*operands)
+        elif op == b"BT":
+            bts, tjs = recurs_to_target_op(
+                ops, text_state_mgr, b"ET", fonts, strip_rotated
+            )
+            bt_groups.extend(bts)
+            tj_ops.extend(tjs)
+        elif op == b"Tj":
+            tj_ops.append(text_state_mgr.text_state_params(operands[0]))
+        elif op == b"TJ":
+            _tj = text_state_mgr.text_state_params()
+            for tj_op in operands[0]:
+                if isinstance(tj_op, bytes):
+                    _tj = text_state_mgr.text_state_params(tj_op)
+                    tj_ops.append(_tj)
+                else:
+                    text_state_mgr.add_trm(_tj.displacement_matrix(TD_offset=tj_op))
+        elif op == b"'":
+            text_state_mgr.reset_trm()
+            text_state_mgr.add_tm([0, -text_state_mgr.TL])
+            tj_ops.append(text_state_mgr.text_state_params(operands[0]))
+        elif op == b'"':
+            text_state_mgr.reset_trm()
+            text_state_mgr.set_state_param(b"Tw", operands[0])
+            text_state_mgr.set_state_param(b"Tc", operands[1])
+            text_state_mgr.add_tm([0, -text_state_mgr.TL])
+            tj_ops.append(text_state_mgr.text_state_params(operands[2]))
+        elif op in (b"Td", b"Tm", b"TD", b"T*"):
+            text_state_mgr.reset_trm()
+            if op == b"Tm":
+                text_state_mgr.reset_tm()
+            elif op == b"TD":
+                text_state_mgr.set_state_param(b"TL", -operands[1])
+            elif op == b"T*":
+                operands = [0, -text_state_mgr.TL]
+            text_state_mgr.add_tm(operands)
+        elif op == b"Tf":
+            text_state_mgr.set_font(fonts[operands[0]], operands[1])
+        else:  # handle Tc, Tw, Tz, TL, and Ts operators
+            text_state_mgr.set_state_param(op, operands)
+
+
+def y_coordinate_groups(
+    bt_groups: List[BTGroup], debug_path: Optional[Path] = None
+) -> Dict[int, List[BTGroup]]:
+    """
+    Group text operations by rendered y coordinate, i.e. the line number.
+
+    Args:
+        bt_groups: list of dicts as returned by text_show_operations()
+        debug_path (Path, optional): Path to a directory for saving debug output.
+
+    Returns:
+        Dict[int, List[BTGroup]]: dict of lists of text rendered by each BT operator
+            keyed by y coordinate
+    """
+    ty_groups = {
+        ty: sorted(grp, key=lambda x: x["tx"])
+        for ty, grp in groupby(
+            bt_groups, key=lambda bt_grp: int(bt_grp["ty"] * bt_grp["flip_sort"])
+        )
+    }
+    # combine groups whose y coordinates differ by less than the effective font height
+    # (accounts for mixed fonts and other minor oddities)
+    last_ty = next(iter(ty_groups))
+    last_txs = {int(_t["tx"]) for _t in ty_groups[last_ty] if _t["text"].strip()}
+    for ty in list(ty_groups)[1:]:
+        fsz = min(ty_groups[_y][0]["font_height"] for _y in (ty, last_ty))
+        txs = {int(_t["tx"]) for _t in ty_groups[ty] if _t["text"].strip()}
+        # prevent merge if both groups are rendering in the same x position.
+        no_text_overlap = not (txs & last_txs)
+        offset_less_than_font_height = abs(ty - last_ty) < fsz
+        if no_text_overlap and offset_less_than_font_height:
+            ty_groups[last_ty] = sorted(
+                ty_groups.pop(ty) + ty_groups[last_ty], key=lambda x: x["tx"]
+            )
+            last_txs |= txs
+        else:
+            last_ty = ty
+            last_txs = txs
+    if debug_path:  # pragma: no cover
+        import json
+
+        debug_path.joinpath("bt_groups.json").write_text(
+            json.dumps(ty_groups, indent=2, default=str), "utf-8"
+        )
+    return ty_groups
+
+
+def text_show_operations(
+    ops: Iterator[Tuple[List[Any], bytes]],
+    fonts: Dict[str, Font],
+    strip_rotated: bool = True,
+    debug_path: Optional[Path] = None,
+) -> List[BTGroup]:
+    """
+    Extract text from BT/ET operator pairs.
+
+    Args:
+        ops (Iterator[Tuple[List, bytes]]): iterator of operators in content stream
+        fonts (Dict[str, Font]): font dictionary
+        strip_rotated: Removes text if rotated w.r.t. to the page. Defaults to True.
+        debug_path (Path, optional): Path to a directory for saving debug output.
+
+    Returns:
+        List[BTGroup]: list of dicts of text rendered by each BT operator
+    """
+    state_mgr = TextStateManager()  # transformation stack manager
+    debug = bool(debug_path)
+    bt_groups: List[BTGroup] = []  # BT operator dict
+    tj_debug: List[TextStateParams] = []  # Tj/TJ operator data (debug only)
+    try:
+        warned_rotation = False
+        while True:
+            operands, op = next(ops)
+            if op in (b"BT", b"q"):
+                bts, tjs = recurs_to_target_op(
+                    ops, state_mgr, b"ET" if op == b"BT" else b"Q", fonts, strip_rotated
+                )
+                if not warned_rotation and any(tj.rotated for tj in tjs):
+                    warned_rotation = True
+                    if strip_rotated:
+                        logger_warning(
+                            "Rotated text discovered. Output will be incomplete.",
+                            __name__,
+                        )
+                    else:
+                        logger_warning(
+                            "Rotated text discovered. Layout will be degraded.",
+                            __name__,
+                        )
+                bt_groups.extend(bts)
+                if debug:  # pragma: no cover
+                    tj_debug.extend(tjs)
+            else:  # set Tc, Tw, Tz, TL, and Ts if required. ignores all other ops
+                state_mgr.set_state_param(op, operands)
+    except StopIteration:
+        pass
+
+    # left align the data, i.e. decrement all tx values by min(tx)
+    min_x = min((x["tx"] for x in bt_groups), default=0.0)
+    bt_groups = [
+        dict(ogrp, tx=ogrp["tx"] - min_x, displaced_tx=ogrp["displaced_tx"] - min_x)  # type: ignore[misc]
+        for ogrp in sorted(
+            bt_groups, key=lambda x: (x["ty"] * x["flip_sort"], -x["tx"]), reverse=True
+        )
+    ]
+
+    if debug_path:  # pragma: no cover
+        import json
+
+        debug_path.joinpath("bts.json").write_text(
+            json.dumps(bt_groups, indent=2, default=str), "utf-8"
+        )
+        debug_path.joinpath("tjs.json").write_text(
+            json.dumps(
+                tj_debug, indent=2, default=lambda x: getattr(x, "to_dict", str)(x)
+            ),
+            "utf-8",
+        )
+    return bt_groups
+
+
+def fixed_char_width(bt_groups: List[BTGroup], scale_weight: float = 1.25) -> float:
+    """
+    Calculate average character width weighted by the length of the rendered
+    text in each sample for conversion to fixed-width layout.
+
+    Args:
+        bt_groups (List[BTGroup]): List of dicts of text rendered by each
+            BT operator
+
+    Returns:
+        float: fixed character width
+    """
+    char_widths = []
+    for _bt in bt_groups:
+        _len = len(_bt["text"]) * scale_weight
+        char_widths.append(((_bt["displaced_tx"] - _bt["tx"]) / _len, _len))
+    return sum(_w * _l for _w, _l in char_widths) / sum(_l for _, _l in char_widths)
+
+
+def fixed_width_page(
+    ty_groups: Dict[int, List[BTGroup]], char_width: float, space_vertically: bool
+) -> str:
+    """
+    Generate page text from text operations grouped by rendered y coordinate.
+
+    Args:
+        ty_groups: dict of text show ops as returned by y_coordinate_groups()
+        char_width: fixed character width
+        space_vertically: include blank lines inferred from y distance + font height.
+
+    Returns:
+        str: page text in a fixed width format that closely adheres to the rendered
+            layout in the source pdf.
+    """
+    lines: List[str] = []
+    last_y_coord = 0
+    for y_coord, line_data in ty_groups.items():
+        if space_vertically and lines:
+            blank_lines = (
+                int(abs(y_coord - last_y_coord) / line_data[0]["font_height"]) - 1
+            )
+            lines.extend([""] * blank_lines)
+        line = ""
+        last_disp = 0.0
+        for bt_op in line_data:
+            offset = int(bt_op["tx"] // char_width)
+            spaces = (offset - len(line)) * (ceil(last_disp) < int(bt_op["tx"]))
+            line = f"{line}{' ' * spaces}{bt_op['text']}"
+            last_disp = bt_op["displaced_tx"]
+        if line.strip() or lines:
+            lines.append(
+                "".join(c if ord(c) < 14 or ord(c) > 31 else " " for c in line)
+            )
+        last_y_coord = y_coord
+    return "\n".join(ln.rstrip() for ln in lines if space_vertically or ln.strip())
diff --git a/.venv/lib/python3.12/site-packages/pypdf/_text_extraction/_layout_mode/_font.py b/.venv/lib/python3.12/site-packages/pypdf/_text_extraction/_layout_mode/_font.py
new file mode 100644
index 00000000..a912fddb
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/_text_extraction/_layout_mode/_font.py
@@ -0,0 +1,112 @@
+"""Font constants and classes for "layout" mode text operations"""
+
+from dataclasses import dataclass, field
+from typing import Any, Dict, Sequence, Union
+
+from ...generic import IndirectObject
+from ._font_widths import STANDARD_WIDTHS
+
+
+@dataclass
+class Font:
+    """
+    A font object formatted for use during "layout" mode text extraction
+
+    Attributes:
+        subtype (str): font subtype
+        space_width (int | float): width of a space character
+        encoding (str | Dict[int, str]): font encoding
+        char_map (dict): character map
+        font_dictionary (dict): font dictionary
+    """
+
+    subtype: str
+    space_width: Union[int, float]
+    encoding: Union[str, Dict[int, str]]
+    char_map: Dict[Any, Any]
+    font_dictionary: Dict[Any, Any]
+    width_map: Dict[str, int] = field(default_factory=dict, init=False)
+
+    def __post_init__(self) -> None:
+        # TrueType fonts have a /Widths array mapping character codes to widths
+        if isinstance(self.encoding, dict) and "/Widths" in self.font_dictionary:
+            first_char = self.font_dictionary.get("/FirstChar", 0)
+            self.width_map = {
+                self.encoding.get(idx + first_char, chr(idx + first_char)): width
+                for idx, width in enumerate(self.font_dictionary["/Widths"])
+            }
+
+        # CID fonts have a /W array mapping character codes to widths stashed in /DescendantFonts
+        if "/DescendantFonts" in self.font_dictionary:
+            d_font: Dict[Any, Any]
+            for d_font_idx, d_font in enumerate(
+                self.font_dictionary["/DescendantFonts"]
+            ):
+                while isinstance(d_font, IndirectObject):
+                    d_font = d_font.get_object()  # type: ignore[assignment]
+                self.font_dictionary["/DescendantFonts"][d_font_idx] = d_font
+                ord_map = {
+                    ord(_target): _surrogate
+                    for _target, _surrogate in self.char_map.items()
+                    if isinstance(_target, str)
+                }
+                # /W width definitions have two valid formats which can be mixed and matched:
+                #   (1) A character start index followed by a list of widths, e.g.
+                #       `45 [500 600 700]` applies widths 500, 600, 700 to characters 45-47.
+                #   (2) A character start index, a character stop index, and a width, e.g.
+                #       `45 65 500` applies width 500 to characters 45-65.
+                skip_count = 0
+                _w = d_font.get("/W", [])
+                for idx, w_entry in enumerate(_w):
+                    if skip_count:
+                        skip_count -= 1
+                        continue
+                    if not isinstance(w_entry, (int, float)):  # pragma: no cover
+                        # We should never get here due to skip_count above. Add a
+                        # warning and or use reader's "strict" to force an ex???
+                        continue
+                    # check for format (1): `int [int int int int ...]`
+                    if isinstance(_w[idx + 1], Sequence):
+                        start_idx, width_list = _w[idx : idx + 2]
+                        self.width_map.update(
+                            {
+                                ord_map[_cidx]: _width
+                                for _cidx, _width in zip(
+                                    range(start_idx, start_idx + len(width_list), 1),
+                                    width_list,
+                                )
+                                if _cidx in ord_map
+                            }
+                        )
+                        skip_count = 1
+                    # check for format (2): `int int int`
+                    if not isinstance(_w[idx + 1], Sequence) and not isinstance(
+                        _w[idx + 2], Sequence
+                    ):
+                        start_idx, stop_idx, const_width = _w[idx : idx + 3]
+                        self.width_map.update(
+                            {
+                                ord_map[_cidx]: const_width
+                                for _cidx in range(start_idx, stop_idx + 1, 1)
+                                if _cidx in ord_map
+                            }
+                        )
+                        skip_count = 2
+        if not self.width_map and "/BaseFont" in self.font_dictionary:
+            for key in STANDARD_WIDTHS:
+                if self.font_dictionary["/BaseFont"].startswith(f"/{key}"):
+                    self.width_map = STANDARD_WIDTHS[key]
+                    break
+
+    def word_width(self, word: str) -> float:
+        """Sum of character widths specified in PDF font for the supplied word"""
+        return sum(
+            [self.width_map.get(char, self.space_width * 2) for char in word], 0.0
+        )
+
+    @staticmethod
+    def to_dict(font_instance: "Font") -> Dict[str, Any]:
+        """Dataclass to dict for json.dumps serialization."""
+        return {
+            k: getattr(font_instance, k) for k in font_instance.__dataclass_fields__
+        }
diff --git a/.venv/lib/python3.12/site-packages/pypdf/_text_extraction/_layout_mode/_font_widths.py b/.venv/lib/python3.12/site-packages/pypdf/_text_extraction/_layout_mode/_font_widths.py
new file mode 100644
index 00000000..39092bcd
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/_text_extraction/_layout_mode/_font_widths.py
@@ -0,0 +1,208 @@
+# Widths for the standard 14 fonts as described on page 416 of the PDF 1.7 standard
+STANDARD_WIDTHS = {
+    "Helvetica": {  # 4 fonts, includes bold, oblique and boldoblique variants
+        " ": 278,
+        "!": 278,
+        '"': 355,
+        "#": 556,
+        "$": 556,
+        "%": 889,
+        "&": 667,
+        "'": 191,
+        "(": 333,
+        ")": 333,
+        "*": 389,
+        "+": 584,
+        ",": 278,
+        "-": 333,
+        ".": 278,
+        "/": 278,
+        "0": 556,
+        "1": 556,
+        "2": 556,
+        "3": 556,
+        "4": 556,
+        "5": 556,
+        "6": 556,
+        "7": 556,
+        "8": 556,
+        "9": 556,
+        ":": 278,
+        ";": 278,
+        "<": 584,
+        "=": 584,
+        ">": 584,
+        "?": 611,
+        "@": 975,
+        "A": 667,
+        "B": 667,
+        "C": 722,
+        "D": 722,
+        "E": 667,
+        "F": 611,
+        "G": 778,
+        "H": 722,
+        "I": 278,
+        "J": 500,
+        "K": 667,
+        "L": 556,
+        "M": 833,
+        "N": 722,
+        "O": 778,
+        "P": 667,
+        "Q": 944,
+        "R": 667,
+        "S": 667,
+        "T": 611,
+        "U": 278,
+        "V": 278,
+        "W": 584,
+        "X": 556,
+        "Y": 556,
+        "Z": 500,
+        "[": 556,
+        "\\": 556,
+        "]": 556,
+        "^": 278,
+        "_": 278,
+        "`": 278,
+        "a": 278,
+        "b": 278,
+        "c": 333,
+        "d": 556,
+        "e": 556,
+        "f": 556,
+        "g": 556,
+        "h": 556,
+        "i": 556,
+        "j": 556,
+        "k": 556,
+        "l": 556,
+        "m": 556,
+        "n": 278,
+        "o": 278,
+        "p": 556,
+        "q": 556,
+        "r": 500,
+        "s": 556,
+        "t": 556,
+        "u": 278,
+        "v": 500,
+        "w": 500,
+        "x": 222,
+        "y": 222,
+        "z": 556,
+        "{": 222,
+        "|": 833,
+        "}": 556,
+        "~": 556,
+    },
+    "Times": {  # 4 fonts, includes bold, oblique and boldoblique variants
+        " ": 250,
+        "!": 333,
+        '"': 408,
+        "#": 500,
+        "$": 500,
+        "%": 833,
+        "&": 778,
+        "'": 180,
+        "(": 333,
+        ")": 333,
+        "*": 500,
+        "+": 564,
+        ",": 250,
+        "-": 333,
+        ".": 250,
+        "/": 564,
+        "0": 500,
+        "1": 500,
+        "2": 500,
+        "3": 500,
+        "4": 500,
+        "5": 500,
+        "6": 500,
+        "7": 500,
+        "8": 500,
+        "9": 500,
+        ":": 278,
+        ";": 278,
+        "<": 564,
+        "=": 564,
+        ">": 564,
+        "?": 444,
+        "@": 921,
+        "A": 722,
+        "B": 667,
+        "C": 667,
+        "D": 722,
+        "E": 611,
+        "F": 556,
+        "G": 722,
+        "H": 722,
+        "I": 333,
+        "J": 389,
+        "K": 722,
+        "L": 611,
+        "M": 889,
+        "N": 722,
+        "O": 722,
+        "P": 556,
+        "Q": 722,
+        "R": 667,
+        "S": 556,
+        "T": 611,
+        "U": 722,
+        "V": 722,
+        "W": 944,
+        "X": 722,
+        "Y": 722,
+        "Z": 611,
+        "[": 333,
+        "\\": 278,
+        "]": 333,
+        "^": 469,
+        "_": 500,
+        "`": 333,
+        "a": 444,
+        "b": 500,
+        "c": 444,
+        "d": 500,
+        "e": 444,
+        "f": 333,
+        "g": 500,
+        "h": 500,
+        "i": 278,
+        "j": 278,
+        "k": 500,
+        "l": 278,
+        "m": 722,
+        "n": 500,
+        "o": 500,
+        "p": 500,
+        "q": 500,
+        "r": 333,
+        "s": 389,
+        "t": 278,
+        "u": 500,
+        "v": 444,
+        "w": 722,
+        "x": 500,
+        "y": 444,
+        "z": 389,
+        "{": 348,
+        "|": 220,
+        "}": 348,
+        "~": 469,
+    },
+}
+STANDARD_WIDTHS[
+    "Courier"
+] = {  # 4 fonts, includes bold, oblique and boldoblique variants
+    c: 600 for c in STANDARD_WIDTHS["Times"]  # fixed width
+}
+STANDARD_WIDTHS["ZapfDingbats"] = {c: 1000 for c in STANDARD_WIDTHS["Times"]}  # 1 font
+STANDARD_WIDTHS["Symbol"] = {c: 500 for c in STANDARD_WIDTHS["Times"]}  # 1 font
+# add aliases per table H.3 on page 1110 of the PDF 1.7 standard
+STANDARD_WIDTHS["CourierNew"] = STANDARD_WIDTHS["Courier"]
+STANDARD_WIDTHS["Arial"] = STANDARD_WIDTHS["Helvetica"]
+STANDARD_WIDTHS["TimesNewRoman"] = STANDARD_WIDTHS["Times"]
diff --git a/.venv/lib/python3.12/site-packages/pypdf/_text_extraction/_layout_mode/_text_state_manager.py b/.venv/lib/python3.12/site-packages/pypdf/_text_extraction/_layout_mode/_text_state_manager.py
new file mode 100644
index 00000000..3c5d4736
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/_text_extraction/_layout_mode/_text_state_manager.py
@@ -0,0 +1,213 @@
+"""manage the PDF transform stack during "layout" mode text extraction"""
+
+from collections import ChainMap, Counter
+from typing import Any, Dict, List, MutableMapping, Union
+from typing import ChainMap as ChainMapType
+from typing import Counter as CounterType
+
+from ...errors import PdfReadError
+from .. import mult
+from ._font import Font
+from ._text_state_params import TextStateParams
+
+TextStateManagerChainMapType = ChainMapType[Union[int, str], Union[float, bool]]
+TextStateManagerDictType = MutableMapping[Union[int, str], Union[float, bool]]
+
+
+class TextStateManager:
+    """
+    Tracks the current text state including cm/tm/trm transformation matrices.
+
+    Attributes:
+        transform_stack (ChainMap): ChainMap of cm/tm transformation matrices
+        q_queue (Counter[int]): Counter of q operators
+        q_depth (List[int]): list of q operator nesting levels
+        Tc (float): character spacing
+        Tw (float): word spacing
+        Tz (int): horizontal scaling
+        TL (float): leading
+        Ts (float): text rise
+        font (Font): font object
+        font_size (int | float): font size
+    """
+
+    def __init__(self) -> None:
+        self.transform_stack: TextStateManagerChainMapType = ChainMap(
+            self.new_transform()
+        )
+        self.q_queue: CounterType[int] = Counter()
+        self.q_depth = [0]
+        self.Tc: float = 0.0
+        self.Tw: float = 0.0
+        self.Tz: float = 100.0
+        self.TL: float = 0.0
+        self.Ts: float = 0.0
+        self.font: Union[Font, None] = None
+        self.font_size: Union[int, float] = 0
+
+    def set_state_param(self, op: bytes, value: Union[float, List[Any]]) -> None:
+        """
+        Set a text state parameter. Supports Tc, Tz, Tw, TL, and Ts operators.
+
+        Args:
+            op: operator read from PDF stream as bytes. No action is taken
+                for unsupported operators (see supported operators above).
+            value (float | List[Any]): new parameter value. If a list,
+                value[0] is used.
+        """
+        if op not in [b"Tc", b"Tz", b"Tw", b"TL", b"Ts"]:
+            return
+        self.__setattr__(op.decode(), value[0] if isinstance(value, list) else value)
+
+    def set_font(self, font: Font, size: float) -> None:
+        """
+        Set the current font and font_size.
+
+        Args:
+            font (Font): a layout mode Font
+            size (float): font size
+        """
+        self.font = font
+        self.font_size = size
+
+    def text_state_params(self, value: Union[bytes, str] = "") -> TextStateParams:
+        """
+        Create a TextStateParams instance to display a text string. Type[bytes] values
+        will be decoded implicitly.
+
+        Args:
+            value (str | bytes): text to associate with the captured state.
+
+        Raises:
+            PdfReadError: if font not set (no Tf operator in incoming pdf content stream)
+
+        Returns:
+            TextStateParams: current text state parameters
+        """
+        if not isinstance(self.font, Font):
+            raise PdfReadError(
+                "font not set: is PDF missing a Tf operator?"
+            )  # pragma: no cover
+        if isinstance(value, bytes):
+            try:
+                if isinstance(self.font.encoding, str):
+                    txt = value.decode(self.font.encoding, "surrogatepass")
+                else:
+                    txt = "".join(
+                        self.font.encoding[x]
+                        if x in self.font.encoding
+                        else bytes((x,)).decode()
+                        for x in value
+                    )
+            except (UnicodeEncodeError, UnicodeDecodeError):
+                txt = value.decode("utf-8", "replace")
+            txt = "".join(
+                self.font.char_map[x] if x in self.font.char_map else x for x in txt
+            )
+        else:
+            txt = value
+        return TextStateParams(
+            txt,
+            self.font,
+            self.font_size,
+            self.Tc,
+            self.Tw,
+            self.Tz,
+            self.TL,
+            self.Ts,
+            self.effective_transform,
+        )
+
+    @staticmethod
+    def raw_transform(
+        _a: float = 1.0,
+        _b: float = 0.0,
+        _c: float = 0.0,
+        _d: float = 1.0,
+        _e: float = 0.0,
+        _f: float = 0.0,
+    ) -> Dict[int, float]:
+        """Only a/b/c/d/e/f matrix params"""
+        return dict(zip(range(6), map(float, (_a, _b, _c, _d, _e, _f))))
+
+    @staticmethod
+    def new_transform(
+        _a: float = 1.0,
+        _b: float = 0.0,
+        _c: float = 0.0,
+        _d: float = 1.0,
+        _e: float = 0.0,
+        _f: float = 0.0,
+        is_text: bool = False,
+        is_render: bool = False,
+    ) -> TextStateManagerDictType:
+        """Standard a/b/c/d/e/f matrix params + 'is_text' and 'is_render' keys"""
+        result: Any = TextStateManager.raw_transform(_a, _b, _c, _d, _e, _f)
+        result.update({"is_text": is_text, "is_render": is_render})
+        return result
+
+    def reset_tm(self) -> TextStateManagerChainMapType:
+        """Clear all transforms from chainmap having is_text==True or is_render==True"""
+        while (
+            self.transform_stack.maps[0]["is_text"]
+            or self.transform_stack.maps[0]["is_render"]
+        ):
+            self.transform_stack = self.transform_stack.parents
+        return self.transform_stack
+
+    def reset_trm(self) -> TextStateManagerChainMapType:
+        """Clear all transforms from chainmap having is_render==True"""
+        while self.transform_stack.maps[0]["is_render"]:
+            self.transform_stack = self.transform_stack.parents
+        return self.transform_stack
+
+    def remove_q(self) -> TextStateManagerChainMapType:
+        """Rewind to stack prior state after closing a 'q' with internal 'cm' ops"""
+        self.transform_stack = self.reset_tm()
+        self.transform_stack.maps = self.transform_stack.maps[
+            self.q_queue.pop(self.q_depth.pop(), 0) :
+        ]
+        return self.transform_stack
+
+    def add_q(self) -> None:
+        """Add another level to q_queue"""
+        self.q_depth.append(len(self.q_depth))
+
+    def add_cm(self, *args: Any) -> TextStateManagerChainMapType:
+        """Concatenate an additional transform matrix"""
+        self.transform_stack = self.reset_tm()
+        self.q_queue.update(self.q_depth[-1:])
+        self.transform_stack = self.transform_stack.new_child(self.new_transform(*args))
+        return self.transform_stack
+
+    def _complete_matrix(self, operands: List[float]) -> List[float]:
+        """Adds a, b, c, and d to an "e/f only" operand set (e.g Td)"""
+        if len(operands) == 2:  # this is a Td operator or equivalent
+            operands = [1.0, 0.0, 0.0, 1.0, *operands]
+        return operands
+
+    def add_tm(self, operands: List[float]) -> TextStateManagerChainMapType:
+        """Append a text transform matrix"""
+        self.transform_stack = self.transform_stack.new_child(
+            self.new_transform(  # type: ignore[misc]
+                *self._complete_matrix(operands), is_text=True  # type: ignore[arg-type]
+            )
+        )
+        return self.transform_stack
+
+    def add_trm(self, operands: List[float]) -> TextStateManagerChainMapType:
+        """Append a text rendering transform matrix"""
+        self.transform_stack = self.transform_stack.new_child(
+            self.new_transform(  # type: ignore[misc]
+                *self._complete_matrix(operands), is_text=True, is_render=True  # type: ignore[arg-type]
+            )
+        )
+        return self.transform_stack
+
+    @property
+    def effective_transform(self) -> List[float]:
+        """Current effective transform accounting for cm, tm, and trm transforms"""
+        eff_transform = [*self.transform_stack.maps[0].values()]
+        for transform in self.transform_stack.maps[1:]:
+            eff_transform = mult(eff_transform, transform)  # type: ignore[arg-type]  # dict has int keys 0-5
+        return eff_transform
diff --git a/.venv/lib/python3.12/site-packages/pypdf/_text_extraction/_layout_mode/_text_state_params.py b/.venv/lib/python3.12/site-packages/pypdf/_text_extraction/_layout_mode/_text_state_params.py
new file mode 100644
index 00000000..b6e6930c
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/_text_extraction/_layout_mode/_text_state_params.py
@@ -0,0 +1,127 @@
+"""A dataclass that captures the CTM and Text State for a tj operation"""
+
+import math
+from dataclasses import dataclass, field
+from typing import Any, Dict, List, Union
+
+from .. import mult, orient
+from ._font import Font
+
+
+@dataclass
+class TextStateParams:
+    """
+    Text state parameters and operator values for a single text value in a
+    TJ or Tj PDF operation.
+
+    Attributes:
+        txt (str): the text to be rendered.
+        font (Font): font object
+        font_size (int | float): font size
+        Tc (float): character spacing. Defaults to 0.0.
+        Tw (float): word spacing. Defaults to 0.0.
+        Tz (float): horizontal scaling. Defaults to 100.0.
+        TL (float): leading, vertical displacement between text lines. Defaults to 0.0.
+        Ts (float): text rise. Used for super/subscripts. Defaults to 0.0.
+        transform (List[float]): effective transformation matrix.
+        tx (float): x cood of rendered text, i.e. self.transform[4]
+        ty (float): y cood of rendered text. May differ from self.transform[5] per self.Ts.
+        displaced_tx (float): x coord immediately following rendered text
+        space_tx (float): tx for a space character
+        font_height (float): effective font height accounting for CTM
+        flip_vertical (bool): True if y axis has been inverted (i.e. if self.transform[3] < 0.)
+        rotated (bool): True if the text orientation is rotated with respect to the page.
+    """
+
+    txt: str
+    font: Font
+    font_size: Union[int, float]
+    Tc: float = 0.0
+    Tw: float = 0.0
+    Tz: float = 100.0
+    TL: float = 0.0
+    Ts: float = 0.0
+    transform: List[float] = field(
+        default_factory=lambda: [1.0, 0.0, 0.0, 1.0, 0.0, 0.0]
+    )
+    tx: float = field(default=0.0, init=False)
+    ty: float = field(default=0.0, init=False)
+    displaced_tx: float = field(default=0.0, init=False)
+    space_tx: float = field(default=0.0, init=False)
+    font_height: float = field(default=0.0, init=False)
+    flip_vertical: bool = field(default=False, init=False)
+    rotated: bool = field(default=False, init=False)
+
+    def __post_init__(self) -> None:
+        if orient(self.transform) in (90, 270):
+            self.transform = mult(
+                [1.0, -self.transform[1], -self.transform[2], 1.0, 0.0, 0.0],
+                self.transform,
+            )
+            self.rotated = True
+        # self.transform[0] AND self.transform[3] < 0 indicates true rotation.
+        # If only self.transform[3] < 0, the y coords are simply inverted.
+        if orient(self.transform) == 180 and self.transform[0] < -1e-6:
+            self.transform = mult([-1.0, 0.0, 0.0, -1.0, 0.0, 0.0], self.transform)
+            self.rotated = True
+        self.displaced_tx = self.displaced_transform()[4]
+        self.tx = self.transform[4]
+        self.ty = self.render_transform()[5]
+        self.space_tx = round(self.word_tx(" "), 3)
+        if self.space_tx < 1e-6:
+            # if the " " char is assigned 0 width (e.g. for fine tuned spacing
+            # with TJ int operators a la crazyones.pdf), calculate space_tx as
+            # a TD_offset of -2 * font.space_width where font.space_width is
+            # the space_width calculated in _cmap.py.
+            self.space_tx = round(self.word_tx("", self.font.space_width * -2), 3)
+        self.font_height = self.font_size * math.sqrt(
+            self.transform[1] ** 2 + self.transform[3] ** 2
+        )
+        # flip_vertical handles PDFs generated by Microsoft Word's "publish" command.
+        self.flip_vertical = self.transform[3] < -1e-6  # inverts y axis
+
+    def font_size_matrix(self) -> List[float]:
+        """Font size matrix"""
+        return [
+            self.font_size * (self.Tz / 100.0),
+            0.0,
+            0.0,
+            self.font_size,
+            0.0,
+            self.Ts,
+        ]
+
+    def displaced_transform(self) -> List[float]:
+        """Effective transform matrix after text has been rendered."""
+        return mult(self.displacement_matrix(), self.transform)
+
+    def render_transform(self) -> List[float]:
+        """Effective transform matrix accounting for font size, Tz, and Ts."""
+        return mult(self.font_size_matrix(), self.transform)
+
+    def displacement_matrix(
+        self, word: Union[str, None] = None, TD_offset: float = 0.0
+    ) -> List[float]:
+        """
+        Text displacement matrix
+
+        Args:
+            word (str, optional): Defaults to None in which case self.txt displacement is
+                returned.
+            TD_offset (float, optional): translation applied by TD operator. Defaults to 0.0.
+        """
+        word = word if word is not None else self.txt
+        return [1.0, 0.0, 0.0, 1.0, self.word_tx(word, TD_offset), 0.0]
+
+    def word_tx(self, word: str, TD_offset: float = 0.0) -> float:
+        """Horizontal text displacement for any word according this text state"""
+        return (
+            (self.font_size * ((self.font.word_width(word) - TD_offset) / 1000.0))
+            + self.Tc
+            + word.count(" ") * self.Tw
+        ) * (self.Tz / 100.0)
+
+    @staticmethod
+    def to_dict(inst: "TextStateParams") -> Dict[str, Any]:
+        """Dataclass to dict for json.dumps serialization"""
+        return {k: getattr(inst, k) for k in inst.__dataclass_fields__ if k != "font"}
diff --git a/.venv/lib/python3.12/site-packages/pypdf/_utils.py b/.venv/lib/python3.12/site-packages/pypdf/_utils.py
new file mode 100644
index 00000000..97565369
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/_utils.py
@@ -0,0 +1,683 @@
+# Copyright (c) 2006, Mathieu Fenniak
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# * The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+"""Utility functions for PDF library."""
+__author__ = "Mathieu Fenniak"
+__author_email__ = "biziqe@mathieu.fenniak.net"
+
+import functools
+import logging
+import re
+import sys
+import warnings
+from dataclasses import dataclass
+from datetime import datetime, timezone
+from io import DEFAULT_BUFFER_SIZE, BytesIO
+from os import SEEK_CUR
+from typing import (
+    IO,
+    Any,
+    Dict,
+    List,
+    Optional,
+    Pattern,
+    Tuple,
+    Union,
+    cast,
+    overload,
+)
+
+if sys.version_info[:2] >= (3, 10):
+    # Python 3.10+: https://www.python.org/dev/peps/pep-0484/
+    from typing import TypeAlias
+else:
+    from typing_extensions import TypeAlias
+
+from .errors import (
+    STREAM_TRUNCATED_PREMATURELY,
+    DeprecationError,
+    PdfStreamError,
+)
+
+TransformationMatrixType: TypeAlias = Tuple[
+    Tuple[float, float, float], Tuple[float, float, float], Tuple[float, float, float]
+]
+CompressedTransformationMatrix: TypeAlias = Tuple[
+    float, float, float, float, float, float
+]
+
+StreamType = IO[Any]
+StrByteType = Union[str, StreamType]
+
+
+def parse_iso8824_date(text: Optional[str]) -> Optional[datetime]:
+    orgtext = text
+    if text is None:
+        return None
+    if text[0].isdigit():
+        text = "D:" + text
+    if text.endswith(("Z", "z")):
+        text += "0000"
+    text = text.replace("z", "+").replace("Z", "+").replace("'", "")
+    i = max(text.find("+"), text.find("-"))
+    if i > 0 and i != len(text) - 5:
+        text += "00"
+    for f in (
+        "D:%Y",
+        "D:%Y%m",
+        "D:%Y%m%d",
+        "D:%Y%m%d%H",
+        "D:%Y%m%d%H%M",
+        "D:%Y%m%d%H%M%S",
+        "D:%Y%m%d%H%M%S%z",
+    ):
+        try:
+            d = datetime.strptime(text, f)  # noqa: DTZ007
+        except ValueError:
+            continue
+        else:
+            if text.endswith("+0000"):
+                d = d.replace(tzinfo=timezone.utc)
+            return d
+    raise ValueError(f"Can not convert date: {orgtext}")
+
+
+def _get_max_pdf_version_header(header1: str, header2: str) -> str:
+    versions = (
+        "%PDF-1.3",
+        "%PDF-1.4",
+        "%PDF-1.5",
+        "%PDF-1.6",
+        "%PDF-1.7",
+        "%PDF-2.0",
+    )
+    pdf_header_indices = []
+    if header1 in versions:
+        pdf_header_indices.append(versions.index(header1))
+    if header2 in versions:
+        pdf_header_indices.append(versions.index(header2))
+    if len(pdf_header_indices) == 0:
+        raise ValueError(f"neither {header1!r} nor {header2!r} are proper headers")
+    return versions[max(pdf_header_indices)]
+
+
+def read_until_whitespace(stream: StreamType, maxchars: Optional[int] = None) -> bytes:
+    """
+    Read non-whitespace characters and return them.
+
+    Stops upon encountering whitespace or when maxchars is reached.
+
+    Args:
+        stream: The data stream from which was read.
+        maxchars: The maximum number of bytes returned; by default unlimited.
+
+    Returns:
+        The data which was read.
+    """
+    txt = b""
+    while True:
+        tok = stream.read(1)
+        if tok.isspace() or not tok:
+            break
+        txt += tok
+        if len(txt) == maxchars:
+            break
+    return txt
+
+
+def read_non_whitespace(stream: StreamType) -> bytes:
+    """
+    Find and read the next non-whitespace character (ignores whitespace).
+
+    Args:
+        stream: The data stream from which was read.
+
+    Returns:
+        The data which was read.
+    """
+    tok = stream.read(1)
+    while tok in WHITESPACES:
+        tok = stream.read(1)
+    return tok
+
+
+def skip_over_whitespace(stream: StreamType) -> bool:
+    """
+    Similar to read_non_whitespace, but return a boolean if more than one
+    whitespace character was read.
+
+    Args:
+        stream: The data stream from which was read.
+
+    Returns:
+        True if more than one whitespace was skipped, otherwise return False.
+    """
+    tok = WHITESPACES[0]
+    cnt = 0
+    while tok in WHITESPACES:
+        tok = stream.read(1)
+        cnt += 1
+    return cnt > 1
+
+
+def check_if_whitespace_only(value: bytes) -> bool:
+    """
+    Check if the given value consists of whitespace characters only.
+
+    Args:
+        value: The bytes to check.
+
+    Returns:
+        True if the value only has whitespace characters, otherwise return False.
+    """
+    for index in range(len(value)):
+        current = value[index : index + 1]
+        if current not in WHITESPACES:
+            return False
+    return True
+
+
+def skip_over_comment(stream: StreamType) -> None:
+    tok = stream.read(1)
+    stream.seek(-1, 1)
+    if tok == b"%":
+        while tok not in (b"\n", b"\r"):
+            tok = stream.read(1)
+
+
+def read_until_regex(stream: StreamType, regex: Pattern[bytes]) -> bytes:
+    """
+    Read until the regular expression pattern matched (ignore the match).
+    Treats EOF on the underlying stream as the end of the token to be matched.
+
+    Args:
+        regex: re.Pattern
+
+    Returns:
+        The read bytes.
+    """
+    name = b""
+    while True:
+        tok = stream.read(16)
+        if not tok:
+            return name
+        m = regex.search(name + tok)
+        if m is not None:
+            stream.seek(m.start() - (len(name) + len(tok)), 1)
+            name = (name + tok)[: m.start()]
+            break
+        name += tok
+    return name
+
+
+def read_block_backwards(stream: StreamType, to_read: int) -> bytes:
+    """
+    Given a stream at position X, read a block of size to_read ending at position X.
+
+    This changes the stream's position to the beginning of where the block was
+    read.
+
+    Args:
+        stream:
+        to_read:
+
+    Returns:
+        The data which was read.
+    """
+    if stream.tell() < to_read:
+        raise PdfStreamError("Could not read malformed PDF file")
+    # Seek to the start of the block we want to read.
+    stream.seek(-to_read, SEEK_CUR)
+    read = stream.read(to_read)
+    # Seek to the start of the block we read after reading it.
+    stream.seek(-to_read, SEEK_CUR)
+    return read
+
+
+def read_previous_line(stream: StreamType) -> bytes:
+    """
+    Given a byte stream with current position X, return the previous line.
+
+    All characters between the first CR/LF byte found before X
+    (or, the start of the file, if no such byte is found) and position X
+    After this call, the stream will be positioned one byte after the
+    first non-CRLF character found beyond the first CR/LF byte before X,
+    or, if no such byte is found, at the beginning of the stream.
+
+    Args:
+        stream: StreamType:
+
+    Returns:
+        The data which was read.
+    """
+    line_content = []
+    found_crlf = False
+    if stream.tell() == 0:
+        raise PdfStreamError(STREAM_TRUNCATED_PREMATURELY)
+    while True:
+        to_read = min(DEFAULT_BUFFER_SIZE, stream.tell())
+        if to_read == 0:
+            break
+        # Read the block. After this, our stream will be one
+        # beyond the initial position.
+        block = read_block_backwards(stream, to_read)
+        idx = len(block) - 1
+        if not found_crlf:
+            # We haven't found our first CR/LF yet.
+            # Read off characters until we hit one.
+            while idx >= 0 and block[idx] not in b"\r\n":
+                idx -= 1
+            if idx >= 0:
+                found_crlf = True
+        if found_crlf:
+            # We found our first CR/LF already (on this block or
+            # a previous one).
+            # Our combined line is the remainder of the block
+            # plus any previously read blocks.
+            line_content.append(block[idx + 1 :])
+            # Continue to read off any more CRLF characters.
+            while idx >= 0 and block[idx] in b"\r\n":
+                idx -= 1
+        else:
+            # Didn't find CR/LF yet - add this block to our
+            # previously read blocks and continue.
+            line_content.append(block)
+        if idx >= 0:
+            # We found the next non-CRLF character.
+            # Set the stream position correctly, then break
+            stream.seek(idx + 1, SEEK_CUR)
+            break
+    # Join all the blocks in the line (which are in reverse order)
+    return b"".join(line_content[::-1])
+
+
+def matrix_multiply(
+    a: TransformationMatrixType, b: TransformationMatrixType
+) -> TransformationMatrixType:
+    return tuple(  # type: ignore[return-value]
+        tuple(sum(float(i) * float(j) for i, j in zip(row, col)) for col in zip(*b))
+        for row in a
+    )
+
+
+def mark_location(stream: StreamType) -> None:
+    """Create text file showing current location in context."""
+    # Mainly for debugging
+    radius = 5000
+    stream.seek(-radius, 1)
+    with open("pypdf_pdfLocation.txt", "wb") as output_fh:
+        output_fh.write(stream.read(radius))
+        output_fh.write(b"HERE")
+        output_fh.write(stream.read(radius))
+    stream.seek(-radius, 1)
+
+
+B_CACHE: Dict[Union[str, bytes], bytes] = {}
+
+
+def b_(s: Union[str, bytes]) -> bytes:
+    if isinstance(s, bytes):
+        return s
+    bc = B_CACHE
+    if s in bc:
+        return bc[s]
+    try:
+        r = s.encode("latin-1")
+        if len(s) < 2:
+            bc[s] = r
+        return r
+    except Exception:
+        r = s.encode("utf-8")
+        if len(s) < 2:
+            bc[s] = r
+        return r
+
+
+def str_(b: Any) -> str:
+    if isinstance(b, bytes):
+        return b.decode("latin-1")
+    else:
+        return str(b)  # will return b.__str__() if defined
+
+
+@overload
+def ord_(b: str) -> int:
+    ...
+
+
+@overload
+def ord_(b: bytes) -> bytes:
+    ...
+
+
+@overload
+def ord_(b: int) -> int:
+    ...
+
+
+def ord_(b: Union[int, str, bytes]) -> Union[int, bytes]:
+    if isinstance(b, str):
+        return ord(b)
+    return b
+
+
+WHITESPACES = (b" ", b"\n", b"\r", b"\t", b"\x00")
+WHITESPACES_AS_BYTES = b"".join(WHITESPACES)
+WHITESPACES_AS_REGEXP = b"[" + WHITESPACES_AS_BYTES + b"]"
+
+
+def paeth_predictor(left: int, up: int, up_left: int) -> int:
+    p = left + up - up_left
+    dist_left = abs(p - left)
+    dist_up = abs(p - up)
+    dist_up_left = abs(p - up_left)
+
+    if dist_left <= dist_up and dist_left <= dist_up_left:
+        return left
+    elif dist_up <= dist_up_left:
+        return up
+    else:
+        return up_left
+
+
+def deprecate(msg: str, stacklevel: int = 3) -> None:
+    warnings.warn(msg, DeprecationWarning, stacklevel=stacklevel)
+
+
+def deprecation(msg: str) -> None:
+    raise DeprecationError(msg)
+
+
+def deprecate_with_replacement(old_name: str, new_name: str, removed_in: str) -> None:
+    """Raise an exception that a feature will be removed, but has a replacement."""
+    deprecate(f"{old_name} is deprecated and will be removed in pypdf {removed_in}. Use {new_name} instead.", 4)
+
+
+def deprecation_with_replacement(old_name: str, new_name: str, removed_in: str) -> None:
+    """Raise an exception that a feature was already removed, but has a replacement."""
+    deprecation(f"{old_name} is deprecated and was removed in pypdf {removed_in}. Use {new_name} instead.")
+
+
+def deprecate_no_replacement(name: str, removed_in: str) -> None:
+    """Raise an exception that a feature will be removed without replacement."""
+    deprecate(f"{name} is deprecated and will be removed in pypdf {removed_in}.", 4)
+
+
+def deprecation_no_replacement(name: str, removed_in: str) -> None:
+    """Raise an exception that a feature was already removed without replacement."""
+    deprecation(f"{name} is deprecated and was removed in pypdf {removed_in}.")
+
+
+def logger_error(msg: str, src: str) -> None:
+    """
+    Use this instead of logger.error directly.
+
+    That allows people to overwrite it more easily.
+
+    See the docs on when to use which:
+    https://pypdf.readthedocs.io/en/latest/user/suppress-warnings.html
+    """
+    logging.getLogger(src).error(msg)
+
+
+def logger_warning(msg: str, src: str) -> None:
+    """
+    Use this instead of logger.warning directly.
+
+    That allows people to overwrite it more easily.
+
+    ## Exception, warnings.warn, logger_warning
+    - Exceptions should be used if the user should write code that deals with
+      an error case, e.g. the PDF being completely broken.
+    - warnings.warn should be used if the user needs to fix their code, e.g.
+      DeprecationWarnings
+    - logger_warning should be used if the user needs to know that an issue was
+      handled by pypdf, e.g. a non-compliant PDF being read in a way that
+      pypdf could apply a robustness fix to still read it. This applies mainly
+      to strict=False mode.
+    """
+    logging.getLogger(src).warning(msg)
+
+
+def rename_kwargs(
+    func_name: str, kwargs: Dict[str, Any], aliases: Dict[str, str], fail: bool = False
+) -> None:
+    """
+    Helper function to deprecate arguments.
+
+    Args:
+        func_name: Name of the function to be deprecated
+        kwargs:
+        aliases:
+        fail:
+    """
+    for old_term, new_term in aliases.items():
+        if old_term in kwargs:
+            if fail:
+                raise DeprecationError(
+                    f"{old_term} is deprecated as an argument. Use {new_term} instead"
+                )
+            if new_term in kwargs:
+                raise TypeError(
+                    f"{func_name} received both {old_term} and {new_term} as "
+                    f"an argument. {old_term} is deprecated. "
+                    f"Use {new_term} instead."
+                )
+            kwargs[new_term] = kwargs.pop(old_term)
+            warnings.warn(
+                message=(
+                    f"{old_term} is deprecated as an argument. Use {new_term} instead"
+                ),
+                category=DeprecationWarning,
+            )
+
+
+def _human_readable_bytes(bytes: int) -> str:
+    if bytes < 10**3:
+        return f"{bytes} Byte"
+    elif bytes < 10**6:
+        return f"{bytes / 10**3:.1f} kB"
+    elif bytes < 10**9:
+        return f"{bytes / 10**6:.1f} MB"
+    else:
+        return f"{bytes / 10**9:.1f} GB"
+
+
+# The following class has been copied from Django:
+# https://github.com/django/django/blob/adae619426b6f50046b3daaa744db52989c9d6db/django/utils/functional.py#L51-L65
+#
+# Original license:
+#
+# ---------------------------------------------------------------------------------
+# Copyright (c) Django Software Foundation and individual contributors.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification,
+# are permitted provided that the following conditions are met:
+#
+#     1. Redistributions of source code must retain the above copyright notice,
+#        this list of conditions and the following disclaimer.
+#
+#     2. Redistributions in binary form must reproduce the above copyright
+#        notice, this list of conditions and the following disclaimer in the
+#        documentation and/or other materials provided with the distribution.
+#
+#     3. Neither the name of Django nor the names of its contributors may be used
+#        to endorse or promote products derived from this software without
+#        specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# ---------------------------------------------------------------------------------
+class classproperty:  # noqa: N801
+    """
+    Decorator that converts a method with a single cls argument into a property
+    that can be accessed directly from the class.
+    """
+
+    def __init__(self, method=None):  # type: ignore  # noqa: ANN001
+        self.fget = method
+
+    def __get__(self, instance, cls=None) -> Any:  # type: ignore  # noqa: ANN001
+        return self.fget(cls)
+
+    def getter(self, method):  # type: ignore  # noqa: ANN001, ANN202
+        self.fget = method
+        return self
+
+
+@dataclass
+class File:
+    from .generic import IndirectObject
+
+    name: str
+    data: bytes
+    image: Optional[Any] = None  # optional ; direct image access
+    indirect_reference: Optional[IndirectObject] = None  # optional ; link to PdfObject
+
+    def __str__(self) -> str:
+        return f"{self.__class__.__name__}(name={self.name}, data: {_human_readable_bytes(len(self.data))})"
+
+    def __repr__(self) -> str:
+        return self.__str__()[:-1] + f", hash: {hash(self.data)})"
+
+
+@dataclass
+class ImageFile(File):
+    from .generic import IndirectObject
+
+    image: Optional[Any] = None  # optional ; direct PIL image access
+    indirect_reference: Optional[IndirectObject] = None  # optional ; link to PdfObject
+
+    def replace(self, new_image: Any, **kwargs: Any) -> None:
+        """
+        Replace the Image with a new PIL image.
+
+        Args:
+            new_image (PIL.Image.Image): The new PIL image to replace the existing image.
+            **kwargs: Additional keyword arguments to pass to `Image.Image.save()`.
+
+        Raises:
+            TypeError: If the image is inline or in a PdfReader.
+            TypeError: If the image does not belong to a PdfWriter.
+            TypeError: If `new_image` is not a PIL Image.
+
+        Note:
+            This method replaces the existing image with a new image.
+            It is not allowed for inline images or images within a PdfReader.
+            The `kwargs` parameter allows passing additional parameters
+            to `Image.Image.save()`, such as quality.
+        """
+        from PIL import Image
+
+        from ._reader import PdfReader
+
+        # to prevent circular import
+        from .filters import _xobj_to_image
+        from .generic import DictionaryObject, PdfObject
+
+        if self.indirect_reference is None:
+            raise TypeError("Can not update an inline image")
+        if not hasattr(self.indirect_reference.pdf, "_id_translated"):
+            raise TypeError("Can not update an image not belonging to a PdfWriter")
+        if not isinstance(new_image, Image.Image):
+            raise TypeError("new_image shall be a PIL Image")
+        b = BytesIO()
+        new_image.save(b, "PDF", **kwargs)
+        reader = PdfReader(b)
+        assert reader.pages[0].images[0].indirect_reference is not None
+        self.indirect_reference.pdf._objects[self.indirect_reference.idnum - 1] = (
+            reader.pages[0].images[0].indirect_reference.get_object()
+        )
+        cast(
+            PdfObject, self.indirect_reference.get_object()
+        ).indirect_reference = self.indirect_reference
+        # change the object attributes
+        extension, byte_stream, img = _xobj_to_image(
+            cast(DictionaryObject, self.indirect_reference.get_object())
+        )
+        assert extension is not None
+        self.name = self.name[: self.name.rfind(".")] + extension
+        self.data = byte_stream
+        self.image = img
+
+
+@functools.total_ordering
+class Version:
+    COMPONENT_PATTERN = re.compile(r"^(\d+)(.*)$")
+
+    def __init__(self, version_str: str) -> None:
+        self.version_str = version_str
+        self.components = self._parse_version(version_str)
+
+    def _parse_version(self, version_str: str) -> List[Tuple[int, str]]:
+        components = version_str.split(".")
+        parsed_components = []
+        for component in components:
+            match = Version.COMPONENT_PATTERN.match(component)
+            if not match:
+                parsed_components.append((0, component))
+                continue
+            integer_prefix = match.group(1)
+            suffix = match.group(2)
+            if integer_prefix is None:
+                integer_prefix = 0
+            parsed_components.append((int(integer_prefix), suffix))
+        return parsed_components
+
+    def __eq__(self, other: object) -> bool:
+        if not isinstance(other, Version):
+            return False
+        return self.components == other.components
+
+    def __lt__(self, other: Any) -> bool:
+        if not isinstance(other, Version):
+            raise ValueError(f"Version cannot be compared against {type(other)}")
+        min_len = min(len(self.components), len(other.components))
+        for i in range(min_len):
+            self_value, self_suffix = self.components[i]
+            other_value, other_suffix = other.components[i]
+
+            if self_value < other_value:
+                return True
+            elif self_value > other_value:
+                return False
+
+            if self_suffix < other_suffix:
+                return True
+            elif self_suffix > other_suffix:
+                return False
+
+        return len(self.components) < len(other.components)
diff --git a/.venv/lib/python3.12/site-packages/pypdf/_version.py b/.venv/lib/python3.12/site-packages/pypdf/_version.py
new file mode 100644
index 00000000..ed48cdab
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/_version.py
@@ -0,0 +1 @@
+__version__ = "4.3.1"
diff --git a/.venv/lib/python3.12/site-packages/pypdf/_writer.py b/.venv/lib/python3.12/site-packages/pypdf/_writer.py
new file mode 100644
index 00000000..00b9d498
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/_writer.py
@@ -0,0 +1,3047 @@
+# Copyright (c) 2006, Mathieu Fenniak
+# Copyright (c) 2007, Ashish Kulkarni <kulkarni.ashish@gmail.com>
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# * The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+import collections
+import decimal
+import enum
+import hashlib
+import re
+import uuid
+from io import BytesIO, FileIO, IOBase
+from pathlib import Path
+from types import TracebackType
+from typing import (
+    IO,
+    Any,
+    Callable,
+    Deque,
+    Dict,
+    Iterable,
+    List,
+    Optional,
+    Pattern,
+    Tuple,
+    Type,
+    Union,
+    cast,
+)
+
+from ._cmap import _default_fonts_space_width, build_char_map_from_dict
+from ._doc_common import PdfDocCommon
+from ._encryption import EncryptAlgorithm, Encryption
+from ._page import PageObject
+from ._page_labels import nums_clear_range, nums_insert, nums_next
+from ._reader import PdfReader
+from ._utils import (
+    StrByteType,
+    StreamType,
+    _get_max_pdf_version_header,
+    b_,
+    deprecate_with_replacement,
+    logger_warning,
+)
+from .constants import AnnotationDictionaryAttributes as AA
+from .constants import CatalogAttributes as CA
+from .constants import (
+    CatalogDictionary,
+    FileSpecificationDictionaryEntries,
+    GoToActionArguments,
+    ImageType,
+    InteractiveFormDictEntries,
+    PageLabelStyle,
+    TypFitArguments,
+    UserAccessPermissions,
+)
+from .constants import Core as CO
+from .constants import FieldDictionaryAttributes as FA
+from .constants import PageAttributes as PG
+from .constants import PagesAttributes as PA
+from .constants import TrailerKeys as TK
+from .errors import PyPdfError
+from .generic import (
+    PAGE_FIT,
+    ArrayObject,
+    BooleanObject,
+    ByteStringObject,
+    ContentStream,
+    DecodedStreamObject,
+    Destination,
+    DictionaryObject,
+    Fit,
+    FloatObject,
+    IndirectObject,
+    NameObject,
+    NullObject,
+    NumberObject,
+    PdfObject,
+    RectangleObject,
+    StreamObject,
+    TextStringObject,
+    TreeObject,
+    ViewerPreferences,
+    create_string_object,
+    hex_to_rgb,
+)
+from .pagerange import PageRange, PageRangeSpec
+from .types import (
+    AnnotationSubtype,
+    BorderArrayType,
+    LayoutType,
+    OutlineItemType,
+    OutlineType,
+    PagemodeType,
+)
+from .xmp import XmpInformation
+
+ALL_DOCUMENT_PERMISSIONS = UserAccessPermissions.all()
+DEFAULT_FONT_HEIGHT_IN_MULTILINE = 12
+
+
+class ObjectDeletionFlag(enum.IntFlag):
+    NONE = 0
+    TEXT = enum.auto()
+    LINKS = enum.auto()
+    ATTACHMENTS = enum.auto()
+    OBJECTS_3D = enum.auto()
+    ALL_ANNOTATIONS = enum.auto()
+    XOBJECT_IMAGES = enum.auto()
+    INLINE_IMAGES = enum.auto()
+    DRAWING_IMAGES = enum.auto()
+    IMAGES = XOBJECT_IMAGES | INLINE_IMAGES | DRAWING_IMAGES
+
+
+def _rolling_checksum(stream: BytesIO, blocksize: int = 65536) -> str:
+    hash = hashlib.md5()
+    for block in iter(lambda: stream.read(blocksize), b""):
+        hash.update(block)
+    return hash.hexdigest()
+
+
+class PdfWriter(PdfDocCommon):
+    """
+    Write a PDF file out, given pages produced by another class or through
+    cloning a PDF file during initialization.
+
+    Typically data is added from a :class:`PdfReader<pypdf.PdfReader>`.
+    """
+
+    def __init__(
+        self,
+        fileobj: Union[None, PdfReader, StrByteType, Path] = "",
+        clone_from: Union[None, PdfReader, StrByteType, Path] = None,
+    ) -> None:
+        self._header = b"%PDF-1.3"
+        self._objects: List[PdfObject] = []
+        """The indirect objects in the PDF."""
+
+        self._idnum_hash: Dict[bytes, IndirectObject] = {}
+        """Maps hash values of indirect objects to their IndirectObject instances."""
+
+        self._id_translated: Dict[int, Dict[int, int]] = {}
+
+        # The root of our page tree node.
+        pages = DictionaryObject()
+        pages.update(
+            {
+                NameObject(PA.TYPE): NameObject("/Pages"),
+                NameObject(PA.COUNT): NumberObject(0),
+                NameObject(PA.KIDS): ArrayObject(),
+            }
+        )
+        self._pages = self._add_object(pages)
+        self.flattened_pages = []
+
+        # info object
+        info = DictionaryObject()
+        info.update({NameObject("/Producer"): create_string_object("pypdf")})
+        self._info_obj: PdfObject = self._add_object(info)
+
+        # root object
+        self._root_object = DictionaryObject()
+        self._root_object.update(
+            {
+                NameObject(PA.TYPE): NameObject(CO.CATALOG),
+                NameObject(CO.PAGES): self._pages,
+            }
+        )
+        self._root = self._add_object(self._root_object)
+
+        def _get_clone_from(
+            fileobj: Union[None, PdfReader, str, Path, IO[Any], BytesIO],
+            clone_from: Union[None, PdfReader, str, Path, IO[Any], BytesIO],
+        ) -> Union[None, PdfReader, str, Path, IO[Any], BytesIO]:
+            if not isinstance(fileobj, (str, Path, IO, BytesIO)) or (
+                fileobj != "" and clone_from is None
+            ):
+                cloning = True
+                if not (
+                    not isinstance(fileobj, (str, Path))
+                    or (
+                        Path(str(fileobj)).exists()
+                        and Path(str(fileobj)).stat().st_size > 0
+                    )
+                ):
+                    cloning = False
+                if isinstance(fileobj, (IO, BytesIO)):
+                    t = fileobj.tell()
+                    fileobj.seek(-1, 2)
+                    if fileobj.tell() == 0:
+                        cloning = False
+                    fileobj.seek(t, 0)
+                if cloning:
+                    clone_from = fileobj
+            return clone_from
+
+        clone_from = _get_clone_from(fileobj, clone_from)
+        # to prevent overwriting
+        self.temp_fileobj = fileobj
+        self.fileobj = ""
+        self.with_as_usage = False
+        if clone_from is not None:
+            if not isinstance(clone_from, PdfReader):
+                clone_from = PdfReader(clone_from)
+            self.clone_document_from_reader(clone_from)
+
+        self._encryption: Optional[Encryption] = None
+        self._encrypt_entry: Optional[DictionaryObject] = None
+        self._ID: Union[ArrayObject, None] = None
+
+    # for commonality
+    @property
+    def is_encrypted(self) -> bool:
+        """
+        Read-only boolean property showing whether this PDF file is encrypted.
+
+        Note that this property, if true, will remain true even after the
+        :meth:`decrypt()<pypdf.PdfReader.decrypt>` method is called.
+        """
+        return False
+
+    @property
+    def root_object(self) -> DictionaryObject:
+        """
+        Provide direct access to PDF Structure.
+
+        Note:
+            Recommended only for read access.
+        """
+        return self._root_object
+
+    @property
+    def _info(self) -> Optional[DictionaryObject]:
+        """
+        Provide access to "/Info". Standardized with PdfReader.
+
+        Returns:
+            /Info Dictionary; None if the entry does not exist
+        """
+        return cast(DictionaryObject, self._info_obj.get_object())
+
+    @_info.setter
+    def _info(self, value: Union[IndirectObject, DictionaryObject]) -> None:
+        obj = cast(DictionaryObject, self._info_obj.get_object())
+        obj.clear()
+        obj.update(cast(DictionaryObject, value.get_object()))
+
+    @property
+    def xmp_metadata(self) -> Optional[XmpInformation]:
+        """XMP (Extensible Metadata Platform) data."""
+        return cast(XmpInformation, self.root_object.xmp_metadata)
+
+    @xmp_metadata.setter
+    def xmp_metadata(self, value: Optional[XmpInformation]) -> None:
+        """XMP (Extensible Metadata Platform) data."""
+        if value is None:
+            if "/Metadata" in self.root_object:
+                del self.root_object["/Metadata"]
+        else:
+            self.root_object[NameObject("/Metadata")] = value
+
+        return self.root_object.xmp_metadata  # type: ignore
+
+    def __enter__(self) -> "PdfWriter":
+        """Store that writer is initialized by 'with'."""
+        t = self.temp_fileobj
+        self.__init__()  # type: ignore
+        self.with_as_usage = True
+        self.fileobj = t  # type: ignore
+        return self
+
+    def __exit__(
+        self,
+        exc_type: Optional[Type[BaseException]],
+        exc: Optional[BaseException],
+        traceback: Optional[TracebackType],
+    ) -> None:
+        """Write data to the fileobj."""
+        if self.fileobj:
+            self.write(self.fileobj)
+
+    def _repr_mimebundle_(
+        self,
+        include: Union[None, Iterable[str]] = None,
+        exclude: Union[None, Iterable[str]] = None,
+    ) -> Dict[str, Any]:
+        """
+        Integration into Jupyter Notebooks.
+
+        This method returns a dictionary that maps a mime-type to its
+        representation.
+
+        See https://ipython.readthedocs.io/en/stable/config/integrating.html
+        """
+        pdf_data = BytesIO()
+        self.write(pdf_data)
+        data = {
+            "application/pdf": pdf_data,
+        }
+
+        if include is not None:
+            # Filter representations based on include list
+            data = {k: v for k, v in data.items() if k in include}
+
+        if exclude is not None:
+            # Remove representations based on exclude list
+            data = {k: v for k, v in data.items() if k not in exclude}
+
+        return data
+
+    @property
+    def pdf_header(self) -> str:
+        """
+        Read/Write property of the PDF header that is written.
+
+        This should be something like ``'%PDF-1.5'``. It is recommended to set
+        the lowest version that supports all features which are used within the
+        PDF file.
+
+        Note: `pdf_header` returns a string but accepts bytes or str for writing
+        """
+        return self._header.decode()
+
+    @pdf_header.setter
+    def pdf_header(self, new_header: Union[str, bytes]) -> None:
+        if isinstance(new_header, str):
+            new_header = new_header.encode()
+        self._header = new_header
+
+    def _add_object(self, obj: PdfObject) -> IndirectObject:
+        if (
+            getattr(obj, "indirect_reference", None) is not None
+            and obj.indirect_reference.pdf == self  # type: ignore
+        ):
+            return obj.indirect_reference  # type: ignore
+        # check for /Contents in Pages (/Contents in annotation are strings)
+        if isinstance(obj, DictionaryObject) and isinstance(
+            obj.get(PG.CONTENTS, None), (ArrayObject, DictionaryObject)
+        ):
+            obj[NameObject(PG.CONTENTS)] = self._add_object(obj[PG.CONTENTS])
+        self._objects.append(obj)
+        obj.indirect_reference = IndirectObject(len(self._objects), 0, self)
+        return obj.indirect_reference
+
+    def get_object(
+        self,
+        indirect_reference: Union[int, IndirectObject],
+    ) -> PdfObject:
+        if isinstance(indirect_reference, int):
+            return self._objects[indirect_reference - 1]
+        if indirect_reference.pdf != self:
+            raise ValueError("pdf must be self")
+        return self._objects[indirect_reference.idnum - 1]
+
+    def _replace_object(
+        self,
+        indirect_reference: Union[int, IndirectObject],
+        obj: PdfObject,
+    ) -> PdfObject:
+        if isinstance(indirect_reference, IndirectObject):
+            if indirect_reference.pdf != self:
+                raise ValueError("pdf must be self")
+            indirect_reference = indirect_reference.idnum
+        gen = self._objects[indirect_reference - 1].indirect_reference.generation  # type: ignore
+        if (
+            getattr(obj, "indirect_reference", None) is not None
+            and obj.indirect_reference.pdf != self  # type: ignore
+        ):
+            obj = obj.clone(self)
+        self._objects[indirect_reference - 1] = obj
+        obj.indirect_reference = IndirectObject(indirect_reference, gen, self)
+        return self._objects[indirect_reference - 1]
+
+    def _add_page(
+        self,
+        page: PageObject,
+        action: Callable[[Any, Union[PageObject, IndirectObject]], None],
+        excluded_keys: Iterable[str] = (),
+    ) -> PageObject:
+        assert cast(str, page[PA.TYPE]) == CO.PAGE
+        page_org = page
+        excluded_keys = list(excluded_keys)
+        excluded_keys += [PA.PARENT, "/StructParents"]
+        # acrobat does not accept to have two indirect ref pointing on the same
+        # page; therefore in order to add easily multiple copies of the same
+        # page, we need to create a new dictionary for the page, however the
+        # objects below (including content) are not duplicated:
+        try:  # delete an already existing page
+            del self._id_translated[id(page_org.indirect_reference.pdf)][  # type: ignore
+                page_org.indirect_reference.idnum  # type: ignore
+            ]
+        except Exception:
+            pass
+        page = cast("PageObject", page_org.clone(self, False, excluded_keys))
+        if page_org.pdf is not None:
+            other = page_org.pdf.pdf_header
+            self.pdf_header = _get_max_pdf_version_header(self.pdf_header, other)
+        page[NameObject(PA.PARENT)] = self._pages
+        pages = cast(DictionaryObject, self.get_object(self._pages))
+        assert page.indirect_reference is not None
+        action(pages[PA.KIDS], page.indirect_reference)
+        action(self.flattened_pages, page)
+        page_count = cast(int, pages[PA.COUNT])
+        pages[NameObject(PA.COUNT)] = NumberObject(page_count + 1)
+        return page
+
+    def set_need_appearances_writer(self, state: bool = True) -> None:
+        """
+        Sets the "NeedAppearances" flag in the PDF writer.
+
+        The "NeedAppearances" flag indicates whether the appearance dictionary
+        for form fields should be automatically generated by the PDF viewer or
+        if the embedded appearance should be used.
+
+        Args:
+            state: The actual value of the NeedAppearances flag.
+
+        Returns:
+            None
+        """
+        # See 12.7.2 and 7.7.2 for more information:
+        # https://opensource.adobe.com/dc-acrobat-sdk-docs/pdfstandards/PDF32000_2008.pdf
+        try:
+            # get the AcroForm tree
+            if CatalogDictionary.ACRO_FORM not in self._root_object:
+                self._root_object[
+                    NameObject(CatalogDictionary.ACRO_FORM)
+                ] = self._add_object(DictionaryObject())
+
+            need_appearances = NameObject(InteractiveFormDictEntries.NeedAppearances)
+            cast(DictionaryObject, self._root_object[CatalogDictionary.ACRO_FORM])[
+                need_appearances
+            ] = BooleanObject(state)
+        except Exception as exc:  # pragma: no cover
+            logger_warning(
+                f"set_need_appearances_writer({state}) catch : {exc}", __name__
+            )
+
+    def create_viewer_preferences(self) -> ViewerPreferences:
+        o = ViewerPreferences()
+        self._root_object[
+            NameObject(CatalogDictionary.VIEWER_PREFERENCES)
+        ] = self._add_object(o)
+        return o
+
+    def add_page(
+        self,
+        page: PageObject,
+        excluded_keys: Iterable[str] = (),
+    ) -> PageObject:
+        """
+        Add a page to this PDF file.
+
+        Recommended for advanced usage including the adequate excluded_keys.
+
+        The page is usually acquired from a :class:`PdfReader<pypdf.PdfReader>`
+        instance.
+
+        Args:
+            page: The page to add to the document. Should be
+                an instance of :class:`PageObject<pypdf._page.PageObject>`
+            excluded_keys:
+
+        Returns:
+            The added PageObject.
+        """
+        return self._add_page(page, list.append, excluded_keys)
+
+    def insert_page(
+        self,
+        page: PageObject,
+        index: int = 0,
+        excluded_keys: Iterable[str] = (),
+    ) -> PageObject:
+        """
+        Insert a page in this PDF file. The page is usually acquired from a
+        :class:`PdfReader<pypdf.PdfReader>` instance.
+
+        Args:
+            page: The page to add to the document.
+            index: Position at which the page will be inserted.
+            excluded_keys:
+
+        Returns:
+            The added PageObject.
+        """
+        return self._add_page(page, lambda kids, p: kids.insert(index, p))
+
+    def _get_page_number_by_indirect(
+        self, indirect_reference: Union[None, int, NullObject, IndirectObject]
+    ) -> Optional[int]:
+        """
+        Generate _page_id2num.
+
+        Args:
+            indirect_reference:
+
+        Returns:
+            The page number or None
+        """
+        # to provide same function as in PdfReader
+        if indirect_reference is None or isinstance(indirect_reference, NullObject):
+            return None
+        if isinstance(indirect_reference, int):
+            indirect_reference = IndirectObject(indirect_reference, 0, self)
+        obj = indirect_reference.get_object()
+        if isinstance(obj, PageObject):
+            return obj.page_number
+        return None
+
+    def add_blank_page(
+        self, width: Optional[float] = None, height: Optional[float] = None
+    ) -> PageObject:
+        """
+        Append a blank page to this PDF file and return it.
+
+        If no page size is specified, use the size of the last page.
+
+        Args:
+            width: The width of the new page expressed in default user
+                space units.
+            height: The height of the new page expressed in default
+                user space units.
+
+        Returns:
+            The newly appended page.
+
+        Raises:
+            PageSizeNotDefinedError: if width and height are not defined
+                and previous page does not exist.
+        """
+        page = PageObject.create_blank_page(self, width, height)
+        return self.add_page(page)
+
+    def insert_blank_page(
+        self,
+        width: Optional[Union[float, decimal.Decimal]] = None,
+        height: Optional[Union[float, decimal.Decimal]] = None,
+        index: int = 0,
+    ) -> PageObject:
+        """
+        Insert a blank page to this PDF file and return it.
+
+        If no page size is specified, use the size of the last page.
+
+        Args:
+            width: The width of the new page expressed in default user
+                space units.
+            height: The height of the new page expressed in default
+                user space units.
+            index: Position to add the page.
+
+        Returns:
+            The newly inserted page.
+
+        Raises:
+            PageSizeNotDefinedError: if width and height are not defined
+                and previous page does not exist.
+        """
+        if width is None or height is None and (self.get_num_pages() - 1) >= index:
+            oldpage = self.pages[index]
+            width = oldpage.mediabox.width
+            height = oldpage.mediabox.height
+        page = PageObject.create_blank_page(self, width, height)
+        self.insert_page(page, index)
+        return page
+
+    @property
+    def open_destination(
+        self,
+    ) -> Union[None, Destination, TextStringObject, ByteStringObject]:
+        return super().open_destination
+
+    @open_destination.setter
+    def open_destination(self, dest: Union[None, str, Destination, PageObject]) -> None:
+        if dest is None:
+            try:
+                del self._root_object["/OpenAction"]
+            except KeyError:
+                pass
+        elif isinstance(dest, str):
+            self._root_object[NameObject("/OpenAction")] = TextStringObject(dest)
+        elif isinstance(dest, Destination):
+            self._root_object[NameObject("/OpenAction")] = dest.dest_array
+        elif isinstance(dest, PageObject):
+            self._root_object[NameObject("/OpenAction")] = Destination(
+                "Opening",
+                dest.indirect_reference
+                if dest.indirect_reference is not None
+                else NullObject(),
+                PAGE_FIT,
+            ).dest_array
+
+    def add_js(self, javascript: str) -> None:
+        """
+        Add JavaScript which will launch upon opening this PDF.
+
+        Args:
+            javascript: Your Javascript.
+
+        >>> output.add_js("this.print({bUI:true,bSilent:false,bShrinkToFit:true});")
+        # Example: This will launch the print window when the PDF is opened.
+        """
+        # Names / JavaScript preferred to be able to add multiple scripts
+        if "/Names" not in self._root_object:
+            self._root_object[NameObject(CA.NAMES)] = DictionaryObject()
+        names = cast(DictionaryObject, self._root_object[CA.NAMES])
+        if "/JavaScript" not in names:
+            names[NameObject("/JavaScript")] = DictionaryObject(
+                {NameObject("/Names"): ArrayObject()}
+            )
+        js_list = cast(
+            ArrayObject, cast(DictionaryObject, names["/JavaScript"])["/Names"]
+        )
+
+        js = DictionaryObject()
+        js.update(
+            {
+                NameObject(PA.TYPE): NameObject("/Action"),
+                NameObject("/S"): NameObject("/JavaScript"),
+                NameObject("/JS"): TextStringObject(f"{javascript}"),
+            }
+        )
+        # We need a name for parameterized javascript in the pdf file,
+        # but it can be anything.
+        js_list.append(create_string_object(str(uuid.uuid4())))
+        js_list.append(self._add_object(js))
+
+    def add_attachment(self, filename: str, data: Union[str, bytes]) -> None:
+        """
+        Embed a file inside the PDF.
+
+        Reference:
+        https://opensource.adobe.com/dc-acrobat-sdk-docs/pdfstandards/PDF32000_2008.pdf
+        Section 7.11.3
+
+        Args:
+            filename: The filename to display.
+            data: The data in the file.
+        """
+        # We need three entries:
+        # * The file's data
+        # * The /Filespec entry
+        # * The file's name, which goes in the Catalog
+
+        # The entry for the file
+        # Sample:
+        # 8 0 obj
+        # <<
+        #  /Length 12
+        #  /Type /EmbeddedFile
+        # >>
+        # stream
+        # Hello world!
+        # endstream
+        # endobj
+
+        file_entry = DecodedStreamObject()
+        file_entry.set_data(b_(data))
+        file_entry.update({NameObject(PA.TYPE): NameObject("/EmbeddedFile")})
+
+        # The Filespec entry
+        # Sample:
+        # 7 0 obj
+        # <<
+        #  /Type /Filespec
+        #  /F (hello.txt)
+        #  /EF << /F 8 0 R >>
+        # >>
+        # endobj
+
+        ef_entry = DictionaryObject()
+        ef_entry.update({NameObject("/F"): self._add_object(file_entry)})
+
+        filespec = DictionaryObject()
+        filespec.update(
+            {
+                NameObject(PA.TYPE): NameObject("/Filespec"),
+                NameObject(FileSpecificationDictionaryEntries.F): create_string_object(
+                    filename
+                ),  # Perhaps also try TextStringObject
+                NameObject(FileSpecificationDictionaryEntries.EF): ef_entry,
+            }
+        )
+
+        # Then create the entry for the root, as it needs
+        # a reference to the Filespec
+        # Sample:
+        # 1 0 obj
+        # <<
+        #  /Type /Catalog
+        #  /Outlines 2 0 R
+        #  /Pages 3 0 R
+        #  /Names << /EmbeddedFiles << /Names [(hello.txt) 7 0 R] >> >>
+        # >>
+        # endobj
+
+        if CA.NAMES not in self._root_object:
+            self._root_object[NameObject(CA.NAMES)] = self._add_object(
+                DictionaryObject()
+            )
+        if "/EmbeddedFiles" not in cast(DictionaryObject, self._root_object[CA.NAMES]):
+            embedded_files_names_dictionary = DictionaryObject(
+                {NameObject(CA.NAMES): ArrayObject()}
+            )
+            cast(DictionaryObject, self._root_object[CA.NAMES])[
+                NameObject("/EmbeddedFiles")
+            ] = self._add_object(embedded_files_names_dictionary)
+        else:
+            embedded_files_names_dictionary = cast(
+                DictionaryObject,
+                cast(DictionaryObject, self._root_object[CA.NAMES])["/EmbeddedFiles"],
+            )
+        cast(ArrayObject, embedded_files_names_dictionary[CA.NAMES]).extend(
+            [create_string_object(filename), filespec]
+        )
+
+    def append_pages_from_reader(
+        self,
+        reader: PdfReader,
+        after_page_append: Optional[Callable[[PageObject], None]] = None,
+    ) -> None:
+        """
+        Copy pages from reader to writer. Includes an optional callback
+        parameter which is invoked after pages are appended to the writer.
+
+        ``append`` should be preferred.
+
+        Args:
+            reader: a PdfReader object from which to copy page
+                annotations to this writer object. The writer's annots
+                will then be updated.
+            after_page_append:
+                Callback function that is invoked after each page is appended to
+                the writer. Signature includes a reference to the appended page
+                (delegates to append_pages_from_reader). The single parameter of
+                the callback is a reference to the page just appended to the
+                document.
+        """
+        # Get page count from writer and reader
+        reader_num_pages = len(reader.pages)
+        # Copy pages from reader to writer
+        for reader_page_number in range(reader_num_pages):
+            reader_page = reader.pages[reader_page_number]
+            writer_page = self.add_page(reader_page)
+            # Trigger callback, pass writer page as parameter
+            if callable(after_page_append):
+                after_page_append(writer_page)
+
+    def _update_field_annotation(
+        self,
+        field: DictionaryObject,
+        anno: DictionaryObject,
+        font_name: str = "",
+        font_size: float = -1,
+    ) -> None:
+        # Calculate rectangle dimensions
+        _rct = cast(RectangleObject, anno[AA.Rect])
+        rct = RectangleObject((0, 0, abs(_rct[2] - _rct[0]), abs(_rct[3] - _rct[1])))
+
+        # Extract font information
+        da = anno.get_inherited(
+            AA.DA,
+            cast(DictionaryObject, self.root_object[CatalogDictionary.ACRO_FORM]).get(
+                AA.DA, None
+            ),
+        )
+        if da is None:
+            da = TextStringObject("/Helv 0 Tf 0 g")
+        else:
+            da = da.get_object()
+        font_properties = da.replace("\n", " ").replace("\r", " ").split(" ")
+        font_properties = [x for x in font_properties if x != ""]
+        if font_name:
+            font_properties[font_properties.index("Tf") - 2] = font_name
+        else:
+            font_name = font_properties[font_properties.index("Tf") - 2]
+        font_height = (
+            font_size
+            if font_size >= 0
+            else float(font_properties[font_properties.index("Tf") - 1])
+        )
+        if font_height == 0:
+            if field.get(FA.Ff, 0) & FA.FfBits.Multiline:
+                font_height = DEFAULT_FONT_HEIGHT_IN_MULTILINE
+            else:
+                font_height = rct.height - 2
+        font_properties[font_properties.index("Tf") - 1] = str(font_height)
+        da = " ".join(font_properties)
+        y_offset = rct.height - 1 - font_height
+
+        # Retrieve font information from local DR ...
+        dr: Any = cast(
+            DictionaryObject,
+            cast(
+                DictionaryObject,
+                anno.get_inherited(
+                    "/DR",
+                    cast(
+                        DictionaryObject, self.root_object[CatalogDictionary.ACRO_FORM]
+                    ).get("/DR", DictionaryObject()),
+                ),
+            ).get_object(),
+        )
+        dr = dr.get("/Font", DictionaryObject()).get_object()
+        # _default_fonts_space_width keys is the list of Standard fonts
+        if font_name not in dr and font_name not in _default_fonts_space_width:
+            # ...or AcroForm dictionary
+            dr = cast(
+                Dict[Any, Any],
+                cast(
+                    DictionaryObject, self.root_object[CatalogDictionary.ACRO_FORM]
+                ).get("/DR", {}),
+            )
+            dr = dr.get_object().get("/Font", DictionaryObject()).get_object()
+        font_res = dr.get(font_name, None)
+        if font_res is not None:
+            font_res = cast(DictionaryObject, font_res.get_object())
+            font_subtype, _, font_encoding, font_map = build_char_map_from_dict(
+                200, font_res
+            )
+            try:  # get rid of width stored in -1 key
+                del font_map[-1]
+            except KeyError:
+                pass
+            font_full_rev: Dict[str, bytes]
+            if isinstance(font_encoding, str):
+                font_full_rev = {
+                    v: k.encode(font_encoding) for k, v in font_map.items()
+                }
+            else:
+                font_full_rev = {v: bytes((k,)) for k, v in font_encoding.items()}
+                font_encoding_rev = {v: bytes((k,)) for k, v in font_encoding.items()}
+                for kk, v in font_map.items():
+                    font_full_rev[v] = font_encoding_rev.get(kk, kk)
+        else:
+            logger_warning(f"Font dictionary for {font_name} not found.", __name__)
+            font_full_rev = {}
+
+        # Retrieve field text and selected values
+        field_flags = field.get(FA.Ff, 0)
+        if field.get(FA.FT, "/Tx") == "/Ch" and field_flags & FA.FfBits.Combo == 0:
+            txt = "\n".join(anno.get_inherited(FA.Opt, []))
+            sel = field.get("/V", [])
+            if not isinstance(sel, list):
+                sel = [sel]
+        else:  # /Tx
+            txt = field.get("/V", "")
+            sel = []
+        # Escape parentheses (pdf 1.7 reference, table 3.2  Literal Strings)
+        txt = txt.replace("\\", "\\\\").replace("(", r"\(").replace(")", r"\)")
+        # Generate appearance stream
+        ap_stream = f"q\n/Tx BMC \nq\n1 1 {rct.width - 1} {rct.height - 1} re\nW\nBT\n{da}\n".encode()
+        for line_number, line in enumerate(txt.replace("\n", "\r").split("\r")):
+            if line in sel:
+                # may be improved but cannot find how to get fill working => replaced with lined box
+                ap_stream += (
+                    f"1 {y_offset - (line_number * font_height * 1.4) - 1} {rct.width - 2} {font_height + 2} re\n"
+                    f"0.5 0.5 0.5 rg s\n{da}\n"
+                ).encode()
+            if line_number == 0:
+                ap_stream += f"2 {y_offset} Td\n".encode()
+            else:
+                # Td is a relative translation
+                ap_stream += f"0 {- font_height * 1.4} Td\n".encode()
+            enc_line: List[bytes] = [
+                font_full_rev.get(c, c.encode("utf-16-be")) for c in line
+            ]
+            if any(len(c) >= 2 for c in enc_line):
+                ap_stream += b"<" + (b"".join(enc_line)).hex().encode() + b"> Tj\n"
+            else:
+                ap_stream += b"(" + b"".join(enc_line) + b") Tj\n"
+        ap_stream += b"ET\nQ\nEMC\nQ\n"
+
+        # Create appearance dictionary
+        dct = DecodedStreamObject.initialize_from_dictionary(
+            {
+                NameObject("/Type"): NameObject("/XObject"),
+                NameObject("/Subtype"): NameObject("/Form"),
+                NameObject("/BBox"): rct,
+                "__streamdata__": ByteStringObject(ap_stream),
+                "/Length": 0,
+            }
+        )
+        if AA.AP in anno:
+            for k, v in cast(DictionaryObject, anno[AA.AP]).get("/N", {}).items():
+                if k not in {"/BBox", "/Length", "/Subtype", "/Type", "/Filter"}:
+                    dct[k] = v
+
+        # Update Resources with font information if necessary
+        if font_res is not None:
+            dct[NameObject("/Resources")] = DictionaryObject(
+                {
+                    NameObject("/Font"): DictionaryObject(
+                        {
+                            NameObject(font_name): getattr(
+                                font_res, "indirect_reference", font_res
+                            )
+                        }
+                    )
+                }
+            )
+        if AA.AP not in anno:
+            anno[NameObject(AA.AP)] = DictionaryObject(
+                {NameObject("/N"): self._add_object(dct)}
+            )
+        elif "/N" not in cast(DictionaryObject, anno[AA.AP]):
+            cast(DictionaryObject, anno[NameObject(AA.AP)])[
+                NameObject("/N")
+            ] = self._add_object(dct)
+        else:  # [/AP][/N] exists
+            n = anno[AA.AP]["/N"].indirect_reference.idnum  # type: ignore
+            self._objects[n - 1] = dct
+            dct.indirect_reference = IndirectObject(n, 0, self)
+
+    FFBITS_NUL = FA.FfBits(0)
+
+    def update_page_form_field_values(
+        self,
+        page: Union[PageObject, List[PageObject], None],
+        fields: Dict[str, Any],
+        flags: FA.FfBits = FFBITS_NUL,
+        auto_regenerate: Optional[bool] = True,
+    ) -> None:
+        """
+        Update the form field values for a given page from a fields dictionary.
+
+        Copy field texts and values from fields to page.
+        If the field links to a parent object, add the information to the parent.
+
+        Args:
+            page: `PageObject` - references **PDF writer's page** where the
+                annotations and field data will be updated.
+                `List[Pageobject]` - provides list of pages to be processed.
+                `None` - all pages.
+            fields: a Python dictionary of:
+
+                * field names (/T) as keys and text values (/V) as value
+                * field names (/T) as keys and list of text values (/V) for multiple choice list
+                * field names (/T) as keys and tuple of:
+                    * text values (/V)
+                    * font id (e.g. /F1, the font id must exist)
+                    * font size (0 for autosize)
+
+            flags: A set of flags from :class:`~pypdf.constants.FieldDictionaryAttributes.FfBits`.
+
+            auto_regenerate: Set/unset the need_appearances flag;
+                the flag is unchanged if auto_regenerate is None.
+        """
+        if CatalogDictionary.ACRO_FORM not in self._root_object:
+            raise PyPdfError("No /AcroForm dictionary in PdfWriter Object")
+        af = cast(DictionaryObject, self._root_object[CatalogDictionary.ACRO_FORM])
+        if InteractiveFormDictEntries.Fields not in af:
+            raise PyPdfError("No /Fields dictionary in Pdf in PdfWriter Object")
+        if isinstance(auto_regenerate, bool):
+            self.set_need_appearances_writer(auto_regenerate)
+        # Iterate through pages, update field values
+        if page is None:
+            page = list(self.pages)
+        if isinstance(page, list):
+            for p in page:
+                if PG.ANNOTS in p:  # just to prevent warnings
+                    self.update_page_form_field_values(p, fields, flags, None)
+            return None
+        if PG.ANNOTS not in page:
+            logger_warning("No fields to update on this page", __name__)
+            return
+        for writer_annot in page[PG.ANNOTS]:  # type: ignore
+            writer_annot = cast(DictionaryObject, writer_annot.get_object())
+            if writer_annot.get("/Subtype", "") != "/Widget":
+                continue
+            if "/FT" in writer_annot and "/T" in writer_annot:
+                writer_parent_annot = writer_annot
+            else:
+                writer_parent_annot = writer_annot.get(
+                    PG.PARENT, DictionaryObject()
+                ).get_object()
+
+            for field, value in fields.items():
+                if not (
+                    self._get_qualified_field_name(writer_parent_annot) == field
+                    or writer_parent_annot.get("/T", None) == field
+                ):
+                    continue
+                if (
+                    writer_parent_annot.get("/FT", None) == "/Ch"
+                    and "/I" in writer_parent_annot
+                ):
+                    del writer_parent_annot["/I"]
+                if flags:
+                    writer_annot[NameObject(FA.Ff)] = NumberObject(flags)
+                if isinstance(value, list):
+                    lst = ArrayObject(TextStringObject(v) for v in value)
+                    writer_parent_annot[NameObject(FA.V)] = lst
+                elif isinstance(value, tuple):
+                    writer_annot[NameObject(FA.V)] = TextStringObject(
+                        value[0],
+                    )
+                else:
+                    writer_parent_annot[NameObject(FA.V)] = TextStringObject(value)
+                if writer_parent_annot.get(FA.FT) in ("/Btn"):
+                    # case of Checkbox button (no /FT found in Radio widgets
+                    v = NameObject(value)
+                    if v not in writer_annot[NameObject(AA.AP)][NameObject("/N")]:
+                        v = NameObject("/Off")
+                    # other cases will be updated through the for loop
+                    writer_annot[NameObject(AA.AS)] = v
+                elif (
+                    writer_parent_annot.get(FA.FT) == "/Tx"
+                    or writer_parent_annot.get(FA.FT) == "/Ch"
+                ):
+                    # textbox
+                    if isinstance(value, tuple):
+                        self._update_field_annotation(
+                            writer_parent_annot, writer_annot, value[1], value[2]
+                        )
+                    else:
+                        self._update_field_annotation(writer_parent_annot, writer_annot)
+                elif (
+                    writer_annot.get(FA.FT) == "/Sig"
+                ):  # deprecated  # not implemented yet
+                    # signature
+                    logger_warning("Signature forms not implemented yet", __name__)
+
+    def reattach_fields(
+        self, page: Optional[PageObject] = None
+    ) -> List[DictionaryObject]:
+        """
+        Parse annotations within the page looking for orphan fields and
+        reattach then into the Fields Structure.
+
+        Args:
+            page: page to analyze.
+                  If none is provided, all pages will be analyzed.
+
+        Returns:
+            list of reattached fields.
+        """
+        lst = []
+        if page is None:
+            for p in self.pages:
+                lst += self.reattach_fields(p)
+            return lst
+
+        try:
+            af = cast(DictionaryObject, self._root_object[CatalogDictionary.ACRO_FORM])
+        except KeyError:
+            af = DictionaryObject()
+            self._root_object[NameObject(CatalogDictionary.ACRO_FORM)] = af
+        try:
+            fields = cast(ArrayObject, af[InteractiveFormDictEntries.Fields])
+        except KeyError:
+            fields = ArrayObject()
+            af[NameObject(InteractiveFormDictEntries.Fields)] = fields
+
+        if "/Annots" not in page:
+            return lst
+        annots = cast(ArrayObject, page["/Annots"])
+        for idx in range(len(annots)):
+            ano = annots[idx]
+            indirect = isinstance(ano, IndirectObject)
+            ano = cast(DictionaryObject, ano.get_object())
+            if ano.get("/Subtype", "") == "/Widget" and "/FT" in ano:
+                if (
+                    "indirect_reference" in ano.__dict__
+                    and ano.indirect_reference in fields
+                ):
+                    continue
+                if not indirect:
+                    annots[idx] = self._add_object(ano)
+                fields.append(ano.indirect_reference)
+                lst.append(ano)
+        return lst
+
+    def clone_reader_document_root(self, reader: PdfReader) -> None:
+        """
+        Copy the reader document root to the writer and all sub-elements,
+        including pages, threads, outlines,... For partial insertion, ``append``
+        should be considered.
+
+        Args:
+            reader: PdfReader from which the document root should be copied.
+        """
+        self._objects.clear()
+        self._root_object = reader.root_object.clone(self)
+        self._root = self._root_object.indirect_reference  # type: ignore[assignment]
+        self._pages = self._root_object.raw_get("/Pages")
+        self._flatten()
+        assert self.flattened_pages is not None
+        for p in self.flattened_pages:
+            p[NameObject("/Parent")] = self._pages
+            self._objects[cast(IndirectObject, p.indirect_reference).idnum - 1] = p
+        cast(DictionaryObject, self._pages.get_object())[
+            NameObject("/Kids")
+        ] = ArrayObject([p.indirect_reference for p in self.flattened_pages])
+
+    def clone_document_from_reader(
+        self,
+        reader: PdfReader,
+        after_page_append: Optional[Callable[[PageObject], None]] = None,
+    ) -> None:
+        """
+        Create a copy (clone) of a document from a PDF file reader cloning
+        section '/Root' and '/Info' and '/ID' of the pdf.
+
+        Args:
+            reader: PDF file reader instance from which the clone
+                should be created.
+            after_page_append:
+                Callback function that is invoked after each page is appended to
+                the writer. Signature includes a reference to the appended page
+                (delegates to append_pages_from_reader). The single parameter of
+                the callback is a reference to the page just appended to the
+                document.
+        """
+        self.clone_reader_document_root(reader)
+        self._info_obj = self._add_object(DictionaryObject())
+        if TK.INFO in reader.trailer:
+            self._info = reader._info  # actually copy fields
+        try:
+            self._ID = cast(ArrayObject, reader._ID).clone(self)
+        except AttributeError:
+            pass
+        if callable(after_page_append):
+            for page in cast(
+                ArrayObject, cast(DictionaryObject, self._pages.get_object())["/Kids"]
+            ):
+                after_page_append(page.get_object())
+
+    def _compute_document_identifier(self) -> ByteStringObject:
+        stream = BytesIO()
+        self._write_pdf_structure(stream)
+        stream.seek(0)
+        return ByteStringObject(_rolling_checksum(stream).encode("utf8"))
+
+    def generate_file_identifiers(self) -> None:
+        """
+        Generate an identifier for the PDF that will be written.
+
+        The only point of this is ensuring uniqueness. Reproducibility is not
+        required.
+        When a file is first written, both identifiers shall be set to the same value.
+        If both identifiers match when a file reference is resolved, it is very
+        likely that the correct and unchanged file has been found. If only the first
+        identifier matches, a different version of the correct file has been found.
+        see 14.4 "File Identifiers".
+        """
+        if self._ID:
+            id1 = self._ID[0]
+            id2 = self._compute_document_identifier()
+        else:
+            id1 = self._compute_document_identifier()
+            id2 = id1
+        self._ID = ArrayObject((id1, id2))
+
+    def encrypt(
+        self,
+        user_password: str,
+        owner_password: Optional[str] = None,
+        use_128bit: bool = True,
+        permissions_flag: UserAccessPermissions = ALL_DOCUMENT_PERMISSIONS,
+        *,
+        algorithm: Optional[str] = None,
+    ) -> None:
+        """
+        Encrypt this PDF file with the PDF Standard encryption handler.
+
+        Args:
+            user_password: The password which allows for opening
+                and reading the PDF file with the restrictions provided.
+            owner_password: The password which allows for
+                opening the PDF files without any restrictions. By default,
+                the owner password is the same as the user password.
+            use_128bit: flag as to whether to use 128bit
+                encryption. When false, 40bit encryption will be used.
+                By default, this flag is on.
+            permissions_flag: permissions as described in
+                Table 3.20 of the PDF 1.7 specification. A bit value of 1 means
+                the permission is granted.
+                Hence an integer value of -1 will set all flags.
+                Bit position 3 is for printing, 4 is for modifying content,
+                5 and 6 control annotations, 9 for form fields,
+                10 for extraction of text and graphics.
+            algorithm: encrypt algorithm. Values may be one of "RC4-40", "RC4-128",
+                "AES-128", "AES-256-R5", "AES-256". If it is valid,
+                `use_128bit` will be ignored.
+        """
+        if owner_password is None:
+            owner_password = user_password
+
+        if algorithm is not None:
+            try:
+                alg = getattr(EncryptAlgorithm, algorithm.replace("-", "_"))
+            except AttributeError:
+                raise ValueError(f"algorithm '{algorithm}' NOT supported")
+        else:
+            alg = EncryptAlgorithm.RC4_128
+            if not use_128bit:
+                alg = EncryptAlgorithm.RC4_40
+        self.generate_file_identifiers()
+        assert self._ID
+        self._encryption = Encryption.make(alg, permissions_flag, self._ID[0])
+        # in case call `encrypt` again
+        entry = self._encryption.write_entry(user_password, owner_password)
+        if self._encrypt_entry:
+            # replace old encrypt_entry
+            assert self._encrypt_entry.indirect_reference is not None
+            entry.indirect_reference = self._encrypt_entry.indirect_reference
+            self._objects[entry.indirect_reference.idnum - 1] = entry
+        else:
+            self._add_object(entry)
+        self._encrypt_entry = entry
+
+    def write_stream(self, stream: StreamType) -> None:
+        if hasattr(stream, "mode") and "b" not in stream.mode:
+            logger_warning(
+                f"File <{stream.name}> to write to is not in binary mode. "
+                "It may not be written to correctly.",
+                __name__,
+            )
+
+        if not self._root:
+            self._root = self._add_object(self._root_object)
+
+        self._sweep_indirect_references(self._root)
+
+        object_positions = self._write_pdf_structure(stream)
+        xref_location = self._write_xref_table(stream, object_positions)
+        self._write_trailer(stream, xref_location)
+
+    def write(self, stream: Union[Path, StrByteType]) -> Tuple[bool, IO[Any]]:
+        """
+        Write the collection of pages added to this object out as a PDF file.
+
+        Args:
+            stream: An object to write the file to. The object can support
+                the write method and the tell method, similar to a file object, or
+                be a file path, just like the fileobj, just named it stream to keep
+                existing workflow.
+
+        Returns:
+            A tuple (bool, IO).
+        """
+        my_file = False
+
+        if stream == "":
+            raise ValueError(f"Output(stream={stream}) is empty.")
+
+        if isinstance(stream, (str, Path)):
+            stream = FileIO(stream, "wb")
+            self.with_as_usage = True  #
+            my_file = True
+
+        self.write_stream(stream)
+
+        if self.with_as_usage:
+            stream.close()
+
+        return my_file, stream
+
+    def _write_pdf_structure(self, stream: StreamType) -> List[int]:
+        object_positions = []
+        stream.write(self.pdf_header.encode() + b"\n")
+        stream.write(b"%\xE2\xE3\xCF\xD3\n")
+
+        for i, obj in enumerate(self._objects):
+            if obj is not None:
+                idnum = i + 1
+                object_positions.append(stream.tell())
+                stream.write(f"{idnum} 0 obj\n".encode())
+                if self._encryption and obj != self._encrypt_entry:
+                    obj = self._encryption.encrypt_object(obj, idnum, 0)
+                obj.write_to_stream(stream)
+                stream.write(b"\nendobj\n")
+        return object_positions
+
+    def _write_xref_table(self, stream: StreamType, object_positions: List[int]) -> int:
+        xref_location = stream.tell()
+        stream.write(b"xref\n")
+        stream.write(f"0 {len(self._objects) + 1}\n".encode())
+        stream.write(f"{0:0>10} {65535:0>5} f \n".encode())
+        for offset in object_positions:
+            stream.write(f"{offset:0>10} {0:0>5} n \n".encode())
+        return xref_location
+
+    def _write_trailer(self, stream: StreamType, xref_location: int) -> None:
+        """
+        Write the PDF trailer to the stream.
+
+        To quote the PDF specification:
+            [The] trailer [gives] the location of the cross-reference table and
+            of certain special objects within the body of the file.
+        """
+        stream.write(b"trailer\n")
+        trailer = DictionaryObject()
+        trailer.update(
+            {
+                NameObject(TK.SIZE): NumberObject(len(self._objects) + 1),
+                NameObject(TK.ROOT): self._root,
+                NameObject(TK.INFO): self._info_obj,
+            }
+        )
+        if self._ID:
+            trailer[NameObject(TK.ID)] = self._ID
+        if self._encrypt_entry:
+            trailer[NameObject(TK.ENCRYPT)] = self._encrypt_entry.indirect_reference
+        trailer.write_to_stream(stream)
+        stream.write(f"\nstartxref\n{xref_location}\n%%EOF\n".encode())  # eof
+
+    def add_metadata(self, infos: Dict[str, Any]) -> None:
+        """
+        Add custom metadata to the output.
+
+        Args:
+            infos: a Python dictionary where each key is a field
+                and each value is your new metadata.
+        """
+        args = {}
+        if isinstance(infos, PdfObject):
+            infos = cast(DictionaryObject, infos.get_object())
+        for key, value in list(infos.items()):
+            if isinstance(value, PdfObject):
+                value = value.get_object()
+            args[NameObject(key)] = create_string_object(str(value))
+        assert isinstance(self._info, DictionaryObject)
+        self._info.update(args)
+
+    def _sweep_indirect_references(
+        self,
+        root: Union[
+            ArrayObject,
+            BooleanObject,
+            DictionaryObject,
+            FloatObject,
+            IndirectObject,
+            NameObject,
+            PdfObject,
+            NumberObject,
+            TextStringObject,
+            NullObject,
+        ],
+    ) -> None:
+        """
+        Resolving any circular references to Page objects.
+
+        Circular references to Page objects can arise when objects such as
+        annotations refer to their associated page. If these references are not
+        properly handled, the PDF file will contain multiple copies of the same
+        Page object. To address this problem, Page objects store their original
+        object reference number. This method adds the reference number of any
+        circularly referenced Page objects to an external reference map. This
+        ensures that self-referencing trees reference the correct new object
+        location, rather than copying in a new copy of the Page object.
+
+        Args:
+            root: The root of the PDF object tree to sweep.
+        """
+        stack: Deque[
+            Tuple[
+                Any,
+                Optional[Any],
+                Any,
+                List[PdfObject],
+            ]
+        ] = collections.deque()
+        discovered = []
+        parent = None
+        grant_parents: List[PdfObject] = []
+        key_or_id = None
+
+        # Start from root
+        stack.append((root, parent, key_or_id, grant_parents))
+
+        while len(stack):
+            data, parent, key_or_id, grant_parents = stack.pop()
+
+            # Build stack for a processing depth-first
+            if isinstance(data, (ArrayObject, DictionaryObject)):
+                for key, value in data.items():
+                    stack.append(
+                        (
+                            value,
+                            data,
+                            key,
+                            grant_parents + [parent] if parent is not None else [],
+                        )
+                    )
+            elif isinstance(data, IndirectObject) and data.pdf != self:
+                data = self._resolve_indirect_object(data)
+
+                if str(data) not in discovered:
+                    discovered.append(str(data))
+                    stack.append((data.get_object(), None, None, []))
+
+            # Check if data has a parent and if it is a dict or
+            # an array update the value
+            if isinstance(parent, (DictionaryObject, ArrayObject)):
+                if isinstance(data, StreamObject):
+                    # a dictionary value is a stream; streams must be indirect
+                    # objects, so we need to change this value.
+                    data = self._resolve_indirect_object(self._add_object(data))
+
+                update_hashes = []
+
+                # Data changed and thus the hash value changed
+                if parent[key_or_id] != data:
+                    update_hashes = [parent.hash_value()] + [
+                        grant_parent.hash_value() for grant_parent in grant_parents
+                    ]
+                    parent[key_or_id] = data
+
+                # Update old hash value to new hash value
+                for old_hash in update_hashes:
+                    indirect_reference = self._idnum_hash.pop(old_hash, None)
+
+                    if indirect_reference is not None:
+                        indirect_reference_obj = indirect_reference.get_object()
+
+                        if indirect_reference_obj is not None:
+                            self._idnum_hash[
+                                indirect_reference_obj.hash_value()
+                            ] = indirect_reference
+
+    def _resolve_indirect_object(self, data: IndirectObject) -> IndirectObject:
+        """
+        Resolves an indirect object to an indirect object in this PDF file.
+
+        If the input indirect object already belongs to this PDF file, it is
+        returned directly. Otherwise, the object is retrieved from the input
+        object's PDF file using the object's ID number and generation number. If
+        the object cannot be found, a warning is logged and a `NullObject` is
+        returned.
+
+        If the object is not already in this PDF file, it is added to the file's
+        list of objects and assigned a new ID number and generation number of 0.
+        The hash value of the object is then added to the `_idnum_hash`
+        dictionary, with the corresponding `IndirectObject` reference as the
+        value.
+
+        Args:
+            data: The `IndirectObject` to resolve.
+
+        Returns:
+            The resolved `IndirectObject` in this PDF file.
+
+        Raises:
+            ValueError: If the input stream is closed.
+        """
+        if hasattr(data.pdf, "stream") and data.pdf.stream.closed:
+            raise ValueError(f"I/O operation on closed file: {data.pdf.stream.name}")
+
+        if data.pdf == self:
+            return data
+
+        # Get real object indirect object
+        real_obj = data.pdf.get_object(data)
+
+        if real_obj is None:
+            logger_warning(
+                f"Unable to resolve [{data.__class__.__name__}: {data}], "
+                "returning NullObject instead",
+                __name__,
+            )
+            real_obj = NullObject()
+
+        hash_value = real_obj.hash_value()
+
+        # Check if object is handled
+        if hash_value in self._idnum_hash:
+            return self._idnum_hash[hash_value]
+
+        if data.pdf == self:
+            self._idnum_hash[hash_value] = IndirectObject(data.idnum, 0, self)
+        # This is new object in this pdf
+        else:
+            self._idnum_hash[hash_value] = self._add_object(real_obj)
+
+        return self._idnum_hash[hash_value]
+
+    def get_reference(self, obj: PdfObject) -> IndirectObject:
+        idnum = self._objects.index(obj) + 1
+        ref = IndirectObject(idnum, 0, self)
+        assert ref.get_object() == obj
+        return ref
+
+    def get_outline_root(self) -> TreeObject:
+        if CO.OUTLINES in self._root_object:
+            # Table 3.25 Entries in the catalog dictionary
+            outline = cast(TreeObject, self._root_object[CO.OUTLINES])
+            if not isinstance(outline, TreeObject):
+                t = TreeObject(outline)
+                self._replace_object(outline.indirect_reference.idnum, t)
+                outline = t
+            idnum = self._objects.index(outline) + 1
+            outline_ref = IndirectObject(idnum, 0, self)
+            assert outline_ref.get_object() == outline
+        else:
+            outline = TreeObject()
+            outline.update({})
+            outline_ref = self._add_object(outline)
+            self._root_object[NameObject(CO.OUTLINES)] = outline_ref
+
+        return outline
+
+    def get_threads_root(self) -> ArrayObject:
+        """
+        The list of threads.
+
+        See §12.4.3 of the PDF 1.7 or PDF 2.0 specification.
+
+        Returns:
+            An array (possibly empty) of Dictionaries with ``/F`` and
+            ``/I`` properties.
+        """
+        if CO.THREADS in self._root_object:
+            # Table 3.25 Entries in the catalog dictionary
+            threads = cast(ArrayObject, self._root_object[CO.THREADS])
+        else:
+            threads = ArrayObject()
+            self._root_object[NameObject(CO.THREADS)] = threads
+        return threads
+
+    @property
+    def threads(self) -> ArrayObject:
+        """
+        Read-only property for the list of threads.
+
+        See §8.3.2 from PDF 1.7 spec.
+
+        Each element is a dictionaries with ``/F`` and ``/I`` keys.
+        """
+        return self.get_threads_root()
+
+    def add_outline_item_destination(
+        self,
+        page_destination: Union[IndirectObject, PageObject, TreeObject],
+        parent: Union[None, TreeObject, IndirectObject] = None,
+        before: Union[None, TreeObject, IndirectObject] = None,
+        is_open: bool = True,
+    ) -> IndirectObject:
+        page_destination = cast(PageObject, page_destination.get_object())
+        if isinstance(page_destination, PageObject):
+            return self.add_outline_item_destination(
+                Destination(
+                    f"page #{page_destination.page_number}",
+                    cast(IndirectObject, page_destination.indirect_reference),
+                    Fit.fit(),
+                )
+            )
+
+        if parent is None:
+            parent = self.get_outline_root()
+
+        page_destination[NameObject("/%is_open%")] = BooleanObject(is_open)
+        parent = cast(TreeObject, parent.get_object())
+        page_destination_ref = self._add_object(page_destination)
+        if before is not None:
+            before = before.indirect_reference
+        parent.insert_child(
+            page_destination_ref,
+            before,
+            self,
+            page_destination.inc_parent_counter_outline
+            if is_open
+            else (lambda x, y: 0),
+        )
+        if "/Count" not in page_destination:
+            page_destination[NameObject("/Count")] = NumberObject(0)
+
+        return page_destination_ref
+
+    def add_outline_item_dict(
+        self,
+        outline_item: OutlineItemType,
+        parent: Union[None, TreeObject, IndirectObject] = None,
+        before: Union[None, TreeObject, IndirectObject] = None,
+        is_open: bool = True,
+    ) -> IndirectObject:
+        outline_item_object = TreeObject()
+        outline_item_object.update(outline_item)
+
+        if "/A" in outline_item:
+            action = DictionaryObject()
+            a_dict = cast(DictionaryObject, outline_item["/A"])
+            for k, v in list(a_dict.items()):
+                action[NameObject(str(k))] = v
+            action_ref = self._add_object(action)
+            outline_item_object[NameObject("/A")] = action_ref
+
+        return self.add_outline_item_destination(
+            outline_item_object, parent, before, is_open
+        )
+
+    def add_outline_item(
+        self,
+        title: str,
+        page_number: Union[None, PageObject, IndirectObject, int],
+        parent: Union[None, TreeObject, IndirectObject] = None,
+        before: Union[None, TreeObject, IndirectObject] = None,
+        color: Optional[Union[Tuple[float, float, float], str]] = None,
+        bold: bool = False,
+        italic: bool = False,
+        fit: Fit = PAGE_FIT,
+        is_open: bool = True,
+    ) -> IndirectObject:
+        """
+        Add an outline item (commonly referred to as a "Bookmark") to the PDF file.
+
+        Args:
+            title: Title to use for this outline item.
+            page_number: Page number this outline item will point to.
+            parent: A reference to a parent outline item to create nested
+                outline items.
+            before:
+            color: Color of the outline item's font as a red, green, blue tuple
+                from 0.0 to 1.0 or as a Hex String (#RRGGBB)
+            bold: Outline item font is bold
+            italic: Outline item font is italic
+            fit: The fit of the destination page.
+
+        Returns:
+            The added outline item as an indirect object.
+        """
+        page_ref: Union[None, NullObject, IndirectObject, NumberObject]
+        if isinstance(italic, Fit):  # it means that we are on the old params
+            if fit is not None and page_number is None:
+                page_number = fit  # type: ignore
+            return self.add_outline_item(
+                title, page_number, parent, None, before, color, bold, italic, is_open=is_open  # type: ignore
+            )
+        if page_number is None:
+            action_ref = None
+        else:
+            if isinstance(page_number, IndirectObject):
+                page_ref = page_number
+            elif isinstance(page_number, PageObject):
+                page_ref = page_number.indirect_reference
+            elif isinstance(page_number, int):
+                try:
+                    page_ref = self.pages[page_number].indirect_reference
+                except IndexError:
+                    page_ref = NumberObject(page_number)
+            if page_ref is None:
+                logger_warning(
+                    f"can not find reference of page {page_number}",
+                    __name__,
+                )
+                page_ref = NullObject()
+            dest = Destination(
+                NameObject("/" + title + " outline item"),
+                page_ref,
+                fit,
+            )
+
+            action_ref = self._add_object(
+                DictionaryObject(
+                    {
+                        NameObject(GoToActionArguments.D): dest.dest_array,
+                        NameObject(GoToActionArguments.S): NameObject("/GoTo"),
+                    }
+                )
+            )
+        outline_item = self._add_object(
+            _create_outline_item(action_ref, title, color, italic, bold)
+        )
+
+        if parent is None:
+            parent = self.get_outline_root()
+        return self.add_outline_item_destination(outline_item, parent, before, is_open)
+
+    def add_outline(self) -> None:
+        raise NotImplementedError(
+            "This method is not yet implemented. Use :meth:`add_outline_item` instead."
+        )
+
+    def add_named_destination_array(
+        self, title: TextStringObject, destination: Union[IndirectObject, ArrayObject]
+    ) -> None:
+        named_dest = self.get_named_dest_root()
+        i = 0
+        while i < len(named_dest):
+            if title < named_dest[i]:
+                named_dest.insert(i, destination)
+                named_dest.insert(i, TextStringObject(title))
+                return
+            else:
+                i += 2
+        named_dest.extend([TextStringObject(title), destination])
+        return
+
+    def add_named_destination_object(
+        self,
+        page_destination: PdfObject,
+    ) -> IndirectObject:
+        page_destination_ref = self._add_object(page_destination.dest_array)  # type: ignore
+        self.add_named_destination_array(
+            cast("TextStringObject", page_destination["/Title"]), page_destination_ref  # type: ignore
+        )
+
+        return page_destination_ref
+
+    def add_named_destination(
+        self,
+        title: str,
+        page_number: int,
+    ) -> IndirectObject:
+        page_ref = self.get_object(self._pages)[PA.KIDS][page_number]  # type: ignore
+        dest = DictionaryObject()
+        dest.update(
+            {
+                NameObject(GoToActionArguments.D): ArrayObject(
+                    [page_ref, NameObject(TypFitArguments.FIT_H), NumberObject(826)]
+                ),
+                NameObject(GoToActionArguments.S): NameObject("/GoTo"),
+            }
+        )
+
+        dest_ref = self._add_object(dest)
+        if not isinstance(title, TextStringObject):
+            title = TextStringObject(str(title))
+
+        self.add_named_destination_array(title, dest_ref)
+        return dest_ref
+
+    def remove_links(self) -> None:
+        """Remove links and annotations from this output."""
+        for page in self.pages:
+            self.remove_objects_from_page(page, ObjectDeletionFlag.ALL_ANNOTATIONS)
+
+    def remove_annotations(
+        self, subtypes: Optional[Union[AnnotationSubtype, Iterable[AnnotationSubtype]]]
+    ) -> None:
+        """
+        Remove annotations by annotation subtype.
+
+        Args:
+            subtypes: subtype or list of subtypes to be removed.
+                Examples are: "/Link", "/FileAttachment", "/Sound",
+                "/Movie", "/Screen", ...
+                If you want to remove all annotations, use subtypes=None.
+        """
+        for page in self.pages:
+            self._remove_annots_from_page(page, subtypes)
+
+    def _remove_annots_from_page(
+        self,
+        page: Union[IndirectObject, PageObject, DictionaryObject],
+        subtypes: Optional[Iterable[str]],
+    ) -> None:
+        page = cast(DictionaryObject, page.get_object())
+        if PG.ANNOTS in page:
+            i = 0
+            while i < len(cast(ArrayObject, page[PG.ANNOTS])):
+                an = cast(ArrayObject, page[PG.ANNOTS])[i]
+                obj = cast(DictionaryObject, an.get_object())
+                if subtypes is None or cast(str, obj["/Subtype"]) in subtypes:
+                    if isinstance(an, IndirectObject):
+                        self._objects[an.idnum - 1] = NullObject()  # to reduce PDF size
+                    del page[PG.ANNOTS][i]  # type:ignore
+                else:
+                    i += 1
+
+    def remove_objects_from_page(
+        self,
+        page: Union[PageObject, DictionaryObject],
+        to_delete: Union[ObjectDeletionFlag, Iterable[ObjectDeletionFlag]],
+    ) -> None:
+        """
+        Remove objects specified by ``to_delete`` from the given page.
+
+        Args:
+            page: Page object to clean up.
+            to_delete: Objects to be deleted; can be a ``ObjectDeletionFlag``
+                or a list of ObjectDeletionFlag
+        """
+        if isinstance(to_delete, (list, tuple)):
+            for to_d in to_delete:
+                self.remove_objects_from_page(page, to_d)
+            return
+        assert isinstance(to_delete, ObjectDeletionFlag)
+
+        if to_delete & ObjectDeletionFlag.LINKS:
+            return self._remove_annots_from_page(page, ("/Link",))
+        if to_delete & ObjectDeletionFlag.ATTACHMENTS:
+            return self._remove_annots_from_page(
+                page, ("/FileAttachment", "/Sound", "/Movie", "/Screen")
+            )
+        if to_delete & ObjectDeletionFlag.OBJECTS_3D:
+            return self._remove_annots_from_page(page, ("/3D",))
+        if to_delete & ObjectDeletionFlag.ALL_ANNOTATIONS:
+            return self._remove_annots_from_page(page, None)
+
+        jump_operators = []
+        if to_delete & ObjectDeletionFlag.DRAWING_IMAGES:
+            jump_operators = (
+                [b"w", b"J", b"j", b"M", b"d", b"i"]
+                + [b"W", b"W*"]
+                + [b"b", b"b*", b"B", b"B*", b"S", b"s", b"f", b"f*", b"F", b"n"]
+                + [b"m", b"l", b"c", b"v", b"y", b"h", b"re"]
+                + [b"sh"]
+            )
+        if to_delete & ObjectDeletionFlag.TEXT:
+            jump_operators = [b"Tj", b"TJ", b"'", b'"']
+
+        def clean(content: ContentStream, images: List[str], forms: List[str]) -> None:
+            nonlocal jump_operators, to_delete
+            i = 0
+            while i < len(content.operations):
+                operands, operator = content.operations[i]
+                if (
+                    (
+                        operator == b"INLINE IMAGE"
+                        and (to_delete & ObjectDeletionFlag.INLINE_IMAGES)
+                    )
+                    or (operator in jump_operators)
+                    or (
+                        operator == b"Do"
+                        and (to_delete & ObjectDeletionFlag.XOBJECT_IMAGES)
+                        and (operands[0] in images)
+                    )
+                ):
+                    del content.operations[i]
+                else:
+                    i += 1
+            content.get_data()  # this ensures ._data is rebuilt from the .operations
+
+        def clean_forms(
+            elt: DictionaryObject, stack: List[DictionaryObject]
+        ) -> Tuple[List[str], List[str]]:
+            nonlocal to_delete
+            # elt in recursive call is a new ContentStream object, so we have to check the indirect_reference
+            if (elt in stack) or (
+                hasattr(elt, "indirect_reference")
+                and any(
+                    elt.indirect_reference == getattr(x, "indirect_reference", -1)
+                    for x in stack
+                )
+            ):
+                # to prevent infinite looping
+                return [], []  # pragma: no cover
+            try:
+                d = cast(
+                    Dict[Any, Any],
+                    cast(DictionaryObject, elt["/Resources"])["/XObject"],
+                )
+            except KeyError:
+                d = {}
+            images = []
+            forms = []
+            for k, v in d.items():
+                o = v.get_object()
+                try:
+                    content: Any = None
+                    if (
+                        to_delete & ObjectDeletionFlag.XOBJECT_IMAGES
+                        and o["/Subtype"] == "/Image"
+                    ):
+                        content = NullObject()  # to delete the image keeping the entry
+                        images.append(k)
+                    if o["/Subtype"] == "/Form":
+                        forms.append(k)
+                        if isinstance(o, ContentStream):
+                            content = o
+                        else:
+                            content = ContentStream(o, self)
+                            content.update(
+                                {
+                                    k1: v1
+                                    for k1, v1 in o.items()
+                                    if k1 not in ["/Length", "/Filter", "/DecodeParms"]
+                                }
+                            )
+                            try:
+                                content.indirect_reference = o.indirect_reference
+                            except AttributeError:  # pragma: no cover
+                                pass
+                        stack.append(elt)
+                        clean_forms(content, stack)  # clean subforms
+                    if content is not None:
+                        if isinstance(v, IndirectObject):
+                            self._objects[v.idnum - 1] = content
+                        else:
+                            # should only occur with pdf not respecting pdf spec
+                            # where streams must be indirected.
+                            d[k] = self._add_object(content)  # pragma: no cover
+                except (TypeError, KeyError):
+                    pass
+            for im in images:
+                del d[im]  # for clean-up
+            if isinstance(elt, StreamObject):  # for /Form
+                if not isinstance(elt, ContentStream):  # pragma: no cover
+                    e = ContentStream(elt, self)
+                    e.update(elt.items())
+                    elt = e
+                clean(elt, images, forms)  # clean the content
+            return images, forms
+
+        if not isinstance(page, PageObject):
+            page = PageObject(self, page.indirect_reference)  # pragma: no cover
+        if "/Contents" in page:
+            content = cast(ContentStream, page.get_contents())
+
+            images, forms = clean_forms(page, [])
+
+            clean(content, images, forms)
+            page.replace_contents(content)
+
+    def remove_images(
+        self,
+        to_delete: ImageType = ImageType.ALL,
+    ) -> None:
+        """
+        Remove images from this output.
+
+        Args:
+            to_delete : The type of images to be deleted
+                (default = all images types)
+        """
+        if isinstance(to_delete, bool):
+            to_delete = ImageType.ALL
+        i = (
+            (
+                ObjectDeletionFlag.XOBJECT_IMAGES
+                if to_delete & ImageType.XOBJECT_IMAGES
+                else ObjectDeletionFlag.NONE
+            )
+            | (
+                ObjectDeletionFlag.INLINE_IMAGES
+                if to_delete & ImageType.INLINE_IMAGES
+                else ObjectDeletionFlag.NONE
+            )
+            | (
+                ObjectDeletionFlag.DRAWING_IMAGES
+                if to_delete & ImageType.DRAWING_IMAGES
+                else ObjectDeletionFlag.NONE
+            )
+        )
+        for page in self.pages:
+            self.remove_objects_from_page(page, i)
+
+    def remove_text(self) -> None:
+        """Remove text from this output."""
+        for page in self.pages:
+            self.remove_objects_from_page(page, ObjectDeletionFlag.TEXT)
+
+    def add_uri(
+        self,
+        page_number: int,
+        uri: str,
+        rect: RectangleObject,
+        border: Optional[ArrayObject] = None,
+    ) -> None:
+        """
+        Add an URI from a rectangular area to the specified page.
+
+        Args:
+            page_number: index of the page on which to place the URI action.
+            uri: URI of resource to link to.
+            rect: :class:`RectangleObject<pypdf.generic.RectangleObject>` or
+                array of four integers specifying the clickable rectangular area
+                ``[xLL, yLL, xUR, yUR]``, or string in the form
+                ``"[ xLL yLL xUR yUR ]"``.
+            border: if provided, an array describing border-drawing
+                properties. See the PDF spec for details. No border will be
+                drawn if this argument is omitted.
+        """
+        page_link = self.get_object(self._pages)[PA.KIDS][page_number]  # type: ignore
+        page_ref = cast(Dict[str, Any], self.get_object(page_link))
+
+        border_arr: BorderArrayType
+        if border is not None:
+            border_arr = [NumberObject(n) for n in border[:3]]
+            if len(border) == 4:
+                dash_pattern = ArrayObject([NumberObject(n) for n in border[3]])
+                border_arr.append(dash_pattern)
+        else:
+            border_arr = [NumberObject(2), NumberObject(2), NumberObject(2)]
+
+        if isinstance(rect, str):
+            rect = NumberObject(rect)
+        elif isinstance(rect, RectangleObject):
+            pass
+        else:
+            rect = RectangleObject(rect)
+
+        lnk2 = DictionaryObject()
+        lnk2.update(
+            {
+                NameObject("/S"): NameObject("/URI"),
+                NameObject("/URI"): TextStringObject(uri),
+            }
+        )
+        lnk = DictionaryObject()
+        lnk.update(
+            {
+                NameObject(AA.Type): NameObject("/Annot"),
+                NameObject(AA.Subtype): NameObject("/Link"),
+                NameObject(AA.P): page_link,
+                NameObject(AA.Rect): rect,
+                NameObject("/H"): NameObject("/I"),
+                NameObject(AA.Border): ArrayObject(border_arr),
+                NameObject("/A"): lnk2,
+            }
+        )
+        lnk_ref = self._add_object(lnk)
+
+        if PG.ANNOTS in page_ref:
+            page_ref[PG.ANNOTS].append(lnk_ref)
+        else:
+            page_ref[NameObject(PG.ANNOTS)] = ArrayObject([lnk_ref])
+
+    _valid_layouts = (
+        "/NoLayout",
+        "/SinglePage",
+        "/OneColumn",
+        "/TwoColumnLeft",
+        "/TwoColumnRight",
+        "/TwoPageLeft",
+        "/TwoPageRight",
+    )
+
+    def _get_page_layout(self) -> Optional[LayoutType]:
+        try:
+            return cast(LayoutType, self._root_object["/PageLayout"])
+        except KeyError:
+            return None
+
+    def _set_page_layout(self, layout: Union[NameObject, LayoutType]) -> None:
+        """
+        Set the page layout.
+
+        Args:
+            layout: The page layout to be used.
+
+        .. list-table:: Valid ``layout`` arguments
+           :widths: 50 200
+
+           * - /NoLayout
+             - Layout explicitly not specified
+           * - /SinglePage
+             - Show one page at a time
+           * - /OneColumn
+             - Show one column at a time
+           * - /TwoColumnLeft
+             - Show pages in two columns, odd-numbered pages on the left
+           * - /TwoColumnRight
+             - Show pages in two columns, odd-numbered pages on the right
+           * - /TwoPageLeft
+             - Show two pages at a time, odd-numbered pages on the left
+           * - /TwoPageRight
+             - Show two pages at a time, odd-numbered pages on the right
+        """
+        if not isinstance(layout, NameObject):
+            if layout not in self._valid_layouts:
+                logger_warning(
+                    f"Layout should be one of: {'', ''.join(self._valid_layouts)}",
+                    __name__,
+                )
+            layout = NameObject(layout)
+        self._root_object.update({NameObject("/PageLayout"): layout})
+
+    def set_page_layout(self, layout: LayoutType) -> None:
+        """
+        Set the page layout.
+
+        Args:
+            layout: The page layout to be used
+
+        .. list-table:: Valid ``layout`` arguments
+           :widths: 50 200
+
+           * - /NoLayout
+             - Layout explicitly not specified
+           * - /SinglePage
+             - Show one page at a time
+           * - /OneColumn
+             - Show one column at a time
+           * - /TwoColumnLeft
+             - Show pages in two columns, odd-numbered pages on the left
+           * - /TwoColumnRight
+             - Show pages in two columns, odd-numbered pages on the right
+           * - /TwoPageLeft
+             - Show two pages at a time, odd-numbered pages on the left
+           * - /TwoPageRight
+             - Show two pages at a time, odd-numbered pages on the right
+        """
+        self._set_page_layout(layout)
+
+    @property
+    def page_layout(self) -> Optional[LayoutType]:
+        """
+        Page layout property.
+
+        .. list-table:: Valid ``layout`` values
+           :widths: 50 200
+
+           * - /NoLayout
+             - Layout explicitly not specified
+           * - /SinglePage
+             - Show one page at a time
+           * - /OneColumn
+             - Show one column at a time
+           * - /TwoColumnLeft
+             - Show pages in two columns, odd-numbered pages on the left
+           * - /TwoColumnRight
+             - Show pages in two columns, odd-numbered pages on the right
+           * - /TwoPageLeft
+             - Show two pages at a time, odd-numbered pages on the left
+           * - /TwoPageRight
+             - Show two pages at a time, odd-numbered pages on the right
+        """
+        return self._get_page_layout()
+
+    @page_layout.setter
+    def page_layout(self, layout: LayoutType) -> None:
+        self._set_page_layout(layout)
+
+    _valid_modes = (
+        "/UseNone",
+        "/UseOutlines",
+        "/UseThumbs",
+        "/FullScreen",
+        "/UseOC",
+        "/UseAttachments",
+    )
+
+    def _get_page_mode(self) -> Optional[PagemodeType]:
+        try:
+            return cast(PagemodeType, self._root_object["/PageMode"])
+        except KeyError:
+            return None
+
+    @property
+    def page_mode(self) -> Optional[PagemodeType]:
+        """
+        Page mode property.
+
+        .. list-table:: Valid ``mode`` values
+           :widths: 50 200
+
+           * - /UseNone
+             - Do not show outline or thumbnails panels
+           * - /UseOutlines
+             - Show outline (aka bookmarks) panel
+           * - /UseThumbs
+             - Show page thumbnails panel
+           * - /FullScreen
+             - Fullscreen view
+           * - /UseOC
+             - Show Optional Content Group (OCG) panel
+           * - /UseAttachments
+             - Show attachments panel
+        """
+        return self._get_page_mode()
+
+    @page_mode.setter
+    def page_mode(self, mode: PagemodeType) -> None:
+        if isinstance(mode, NameObject):
+            mode_name: NameObject = mode
+        else:
+            if mode not in self._valid_modes:
+                logger_warning(
+                    f"Mode should be one of: {', '.join(self._valid_modes)}", __name__
+                )
+            mode_name = NameObject(mode)
+        self._root_object.update({NameObject("/PageMode"): mode_name})
+
+    def add_annotation(
+        self,
+        page_number: Union[int, PageObject],
+        annotation: Dict[str, Any],
+    ) -> DictionaryObject:
+        """
+        Add a single annotation to the page.
+        The added annotation must be a new annotation.
+        It cannot be recycled.
+
+        Args:
+            page_number: PageObject or page index.
+            annotation: Annotation to be added (created with annotation).
+
+        Returns:
+            The inserted object.
+            This can be used for popup creation, for example.
+        """
+        page = page_number
+        if isinstance(page, int):
+            page = self.pages[page]
+        elif not isinstance(page, PageObject):
+            raise TypeError("page: invalid type")
+
+        to_add = cast(DictionaryObject, _pdf_objectify(annotation))
+        to_add[NameObject("/P")] = page.indirect_reference
+
+        if page.annotations is None:
+            page[NameObject("/Annots")] = ArrayObject()
+        assert page.annotations is not None
+
+        # Internal link annotations need the correct object type for the
+        # destination
+        if to_add.get("/Subtype") == "/Link" and "/Dest" in to_add:
+            tmp = cast(Dict[Any, Any], to_add[NameObject("/Dest")])
+            dest = Destination(
+                NameObject("/LinkName"),
+                tmp["target_page_index"],
+                Fit(
+                    fit_type=tmp["fit"], fit_args=dict(tmp)["fit_args"]
+                ),  # I have no clue why this dict-hack is necessary
+            )
+            to_add[NameObject("/Dest")] = dest.dest_array
+
+        page.annotations.append(self._add_object(to_add))
+
+        if to_add.get("/Subtype") == "/Popup" and NameObject("/Parent") in to_add:
+            cast(DictionaryObject, to_add["/Parent"].get_object())[
+                NameObject("/Popup")
+            ] = to_add.indirect_reference
+
+        return to_add
+
+    def clean_page(self, page: Union[PageObject, IndirectObject]) -> PageObject:
+        """
+        Perform some clean up in the page.
+        Currently: convert NameObject named destination to TextStringObject
+        (required for names/dests list)
+
+        Args:
+            page:
+
+        Returns:
+            The cleaned PageObject
+        """
+        page = cast("PageObject", page.get_object())
+        for a in page.get("/Annots", []):
+            a_obj = a.get_object()
+            d = a_obj.get("/Dest", None)
+            act = a_obj.get("/A", None)
+            if isinstance(d, NameObject):
+                a_obj[NameObject("/Dest")] = TextStringObject(d)
+            elif act is not None:
+                act = act.get_object()
+                d = act.get("/D", None)
+                if isinstance(d, NameObject):
+                    act[NameObject("/D")] = TextStringObject(d)
+        return page
+
+    def _create_stream(
+        self, fileobj: Union[Path, StrByteType, PdfReader]
+    ) -> Tuple[IOBase, Optional[Encryption]]:
+        # If the fileobj parameter is a string, assume it is a path
+        # and create a file object at that location. If it is a file,
+        # copy the file's contents into a BytesIO stream object; if
+        # it is a PdfReader, copy that reader's stream into a
+        # BytesIO stream.
+        # If fileobj is none of the above types, it is not modified
+        encryption_obj = None
+        stream: IOBase
+        if isinstance(fileobj, (str, Path)):
+            with FileIO(fileobj, "rb") as f:
+                stream = BytesIO(f.read())
+        elif isinstance(fileobj, PdfReader):
+            if fileobj._encryption:
+                encryption_obj = fileobj._encryption
+            orig_tell = fileobj.stream.tell()
+            fileobj.stream.seek(0)
+            stream = BytesIO(fileobj.stream.read())
+
+            # reset the stream to its original location
+            fileobj.stream.seek(orig_tell)
+        elif hasattr(fileobj, "seek") and hasattr(fileobj, "read"):
+            fileobj.seek(0)
+            filecontent = fileobj.read()
+            stream = BytesIO(filecontent)
+        else:
+            raise NotImplementedError(
+                "PdfMerger.merge requires an object that PdfReader can parse. "
+                "Typically, that is a Path or a string representing a Path, "
+                "a file object, or an object implementing .seek and .read. "
+                "Passing a PdfReader directly works as well."
+            )
+        return stream, encryption_obj
+
+    def append(
+        self,
+        fileobj: Union[StrByteType, PdfReader, Path],
+        outline_item: Union[
+            str, None, PageRange, Tuple[int, int], Tuple[int, int, int], List[int]
+        ] = None,
+        pages: Union[
+            None,
+            PageRange,
+            Tuple[int, int],
+            Tuple[int, int, int],
+            List[int],
+            List[PageObject],
+        ] = None,
+        import_outline: bool = True,
+        excluded_fields: Optional[Union[List[str], Tuple[str, ...]]] = None,
+    ) -> None:
+        """
+        Identical to the :meth:`merge()<merge>` method, but assumes you want to
+        concatenate all pages onto the end of the file instead of specifying a
+        position.
+
+        Args:
+            fileobj: A File Object or an object that supports the standard
+                read and seek methods similar to a File Object. Could also be a
+                string representing a path to a PDF file.
+            outline_item: Optionally, you may specify a string to build an
+                outline (aka 'bookmark') to identify the beginning of the
+                included file.
+            pages: Can be a :class:`PageRange<pypdf.pagerange.PageRange>`
+                or a ``(start, stop[, step])`` tuple
+                or a list of pages to be processed
+                to merge only the specified range of pages from the source
+                document into the output document.
+            import_outline: You may prevent the source document's
+                outline (collection of outline items, previously referred to as
+                'bookmarks') from being imported by specifying this as ``False``.
+            excluded_fields: Provide the list of fields/keys to be ignored
+                if ``/Annots`` is part of the list, the annotation will be ignored
+                if ``/B`` is part of the list, the articles will be ignored
+        """
+        if excluded_fields is None:
+            excluded_fields = ()
+        if isinstance(outline_item, (tuple, list, PageRange)):
+            if isinstance(pages, bool):
+                if not isinstance(import_outline, bool):
+                    excluded_fields = import_outline
+                import_outline = pages
+            pages = outline_item
+            self.merge(
+                None,
+                fileobj,
+                None,
+                pages,
+                import_outline,
+                excluded_fields,
+            )
+        else:  # if isinstance(outline_item,str):
+            self.merge(
+                None,
+                fileobj,
+                outline_item,
+                pages,
+                import_outline,
+                excluded_fields,
+            )
+
+    def merge(
+        self,
+        position: Optional[int],
+        fileobj: Union[Path, StrByteType, PdfReader],
+        outline_item: Optional[str] = None,
+        pages: Optional[Union[PageRangeSpec, List[PageObject]]] = None,
+        import_outline: bool = True,
+        excluded_fields: Optional[Union[List[str], Tuple[str, ...]]] = (),
+    ) -> None:
+        """
+        Merge the pages from the given file into the output file at the
+        specified page number.
+
+        Args:
+            position: The *page number* to insert this file. File will
+                be inserted after the given number.
+            fileobj: A File Object or an object that supports the standard
+                read and seek methods similar to a File Object. Could also be a
+                string representing a path to a PDF file.
+            outline_item: Optionally, you may specify a string to build an outline
+                (aka 'bookmark') to identify the
+                beginning of the included file.
+            pages: can be a :class:`PageRange<pypdf.pagerange.PageRange>`
+                or a ``(start, stop[, step])`` tuple
+                or a list of pages to be processed
+                to merge only the specified range of pages from the source
+                document into the output document.
+            import_outline: You may prevent the source document's
+                outline (collection of outline items, previously referred to as
+                'bookmarks') from being imported by specifying this as ``False``.
+            excluded_fields: provide the list of fields/keys to be ignored
+                if ``/Annots`` is part of the list, the annotation will be ignored
+                if ``/B`` is part of the list, the articles will be ignored
+
+        Raises:
+            TypeError: The pages attribute is not configured properly
+        """
+        if isinstance(fileobj, PdfDocCommon):
+            reader = fileobj
+        else:
+            stream, encryption_obj = self._create_stream(fileobj)
+            # Create a new PdfReader instance using the stream
+            # (either file or BytesIO or StringIO) created above
+            reader = PdfReader(stream, strict=False)  # type: ignore[arg-type]
+
+        if excluded_fields is None:
+            excluded_fields = ()
+        # Find the range of pages to merge.
+        if pages is None:
+            pages = list(range(len(reader.pages)))
+        elif isinstance(pages, PageRange):
+            pages = list(range(*pages.indices(len(reader.pages))))
+        elif isinstance(pages, list):
+            pass  # keep unchanged
+        elif isinstance(pages, tuple) and len(pages) <= 3:
+            pages = list(range(*pages))
+        elif not isinstance(pages, tuple):
+            raise TypeError(
+                '"pages" must be a tuple of (start, stop[, step]) or a list'
+            )
+
+        srcpages = {}
+        for page in pages:
+            if isinstance(page, PageObject):
+                pg = page
+            else:
+                pg = reader.pages[page]
+            assert pg.indirect_reference is not None
+            if position is None:
+                # numbers in the exclude list identifies that the exclusion is
+                # only applicable to 1st level of cloning
+                srcpages[pg.indirect_reference.idnum] = self.add_page(
+                    pg, list(excluded_fields) + [1, "/B", 1, "/Annots"]  # type: ignore
+                )
+            else:
+                srcpages[pg.indirect_reference.idnum] = self.insert_page(
+                    pg, position, list(excluded_fields) + [1, "/B", 1, "/Annots"]  # type: ignore
+                )
+                position += 1
+            srcpages[pg.indirect_reference.idnum].original_page = pg
+
+        reader._namedDests = (
+            reader.named_destinations
+        )  # need for the outline processing below
+        for dest in reader._namedDests.values():
+            arr = dest.dest_array
+            if "/Names" in self._root_object and dest["/Title"] in cast(
+                List[Any],
+                cast(
+                    DictionaryObject,
+                    cast(DictionaryObject, self._root_object["/Names"])["/Dests"],
+                )["/Names"],
+            ):
+                # already exists : should not duplicate it
+                pass
+            elif isinstance(dest["/Page"], NullObject):
+                pass
+            elif isinstance(dest["/Page"], int):
+                # the page reference is a page number normally not a PDF Reference
+                # page numbers as int are normally accepted only in external goto
+                p = reader.pages[dest["/Page"]]
+                assert p.indirect_reference is not None
+                try:
+                    arr[NumberObject(0)] = NumberObject(
+                        srcpages[p.indirect_reference.idnum].page_number
+                    )
+                    self.add_named_destination_array(dest["/Title"], arr)
+                except KeyError:
+                    pass
+            elif dest["/Page"].indirect_reference.idnum in srcpages:
+                arr[NumberObject(0)] = srcpages[
+                    dest["/Page"].indirect_reference.idnum
+                ].indirect_reference
+                self.add_named_destination_array(dest["/Title"], arr)
+
+        outline_item_typ: TreeObject
+        if outline_item is not None:
+            outline_item_typ = cast(
+                "TreeObject",
+                self.add_outline_item(
+                    TextStringObject(outline_item),
+                    next(iter(srcpages.values())).indirect_reference,
+                    fit=PAGE_FIT,
+                ).get_object(),
+            )
+        else:
+            outline_item_typ = self.get_outline_root()
+
+        _ro = reader.root_object
+        if import_outline and CO.OUTLINES in _ro:
+            outline = self._get_filtered_outline(
+                _ro.get(CO.OUTLINES, None), srcpages, reader
+            )
+            self._insert_filtered_outline(
+                outline, outline_item_typ, None
+            )  # TODO : use before parameter
+
+        if "/Annots" not in excluded_fields:
+            for pag in srcpages.values():
+                lst = self._insert_filtered_annotations(
+                    pag.original_page.get("/Annots", ()), pag, srcpages, reader
+                )
+                if len(lst) > 0:
+                    pag[NameObject("/Annots")] = lst
+                self.clean_page(pag)
+
+        if "/AcroForm" in _ro and _ro["/AcroForm"] is not None:
+            if "/AcroForm" not in self._root_object:
+                self._root_object[NameObject("/AcroForm")] = self._add_object(
+                    cast(
+                        DictionaryObject,
+                        reader.root_object["/AcroForm"],
+                    ).clone(self, False, ("/Fields",))
+                )
+                arr = ArrayObject()
+            else:
+                arr = cast(
+                    ArrayObject,
+                    cast(DictionaryObject, self._root_object["/AcroForm"])["/Fields"],
+                )
+            trslat = self._id_translated[id(reader)]
+            try:
+                for f in reader.root_object["/AcroForm"]["/Fields"]:  # type: ignore
+                    try:
+                        ind = IndirectObject(trslat[f.idnum], 0, self)
+                        if ind not in arr:
+                            arr.append(ind)
+                    except KeyError:
+                        # for trslat[] which mean the field has not be copied
+                        # through the page
+                        pass
+            except KeyError:  # for /Acroform or /Fields are not existing
+                arr = self._add_object(ArrayObject())
+            cast(DictionaryObject, self._root_object["/AcroForm"])[
+                NameObject("/Fields")
+            ] = arr
+
+        if "/B" not in excluded_fields:
+            self.add_filtered_articles("", srcpages, reader)
+
+    def _add_articles_thread(
+        self,
+        thread: DictionaryObject,  # thread entry from the reader's array of threads
+        pages: Dict[int, PageObject],
+        reader: PdfReader,
+    ) -> IndirectObject:
+        """
+        Clone the thread with only the applicable articles.
+
+        Args:
+            thread:
+            pages:
+            reader:
+
+        Returns:
+            The added thread as an indirect reference
+        """
+        nthread = thread.clone(
+            self, force_duplicate=True, ignore_fields=("/F",)
+        )  # use of clone to keep link between reader and writer
+        self.threads.append(nthread.indirect_reference)
+        first_article = cast("DictionaryObject", thread["/F"])
+        current_article: Optional[DictionaryObject] = first_article
+        new_article: Optional[DictionaryObject] = None
+        while current_article is not None:
+            pag = self._get_cloned_page(
+                cast("PageObject", current_article["/P"]), pages, reader
+            )
+            if pag is not None:
+                if new_article is None:
+                    new_article = cast(
+                        "DictionaryObject",
+                        self._add_object(DictionaryObject()).get_object(),
+                    )
+                    new_first = new_article
+                    nthread[NameObject("/F")] = new_article.indirect_reference
+                else:
+                    new_article2 = cast(
+                        "DictionaryObject",
+                        self._add_object(
+                            DictionaryObject(
+                                {NameObject("/V"): new_article.indirect_reference}
+                            )
+                        ).get_object(),
+                    )
+                    new_article[NameObject("/N")] = new_article2.indirect_reference
+                    new_article = new_article2
+                new_article[NameObject("/P")] = pag
+                new_article[NameObject("/T")] = nthread.indirect_reference
+                new_article[NameObject("/R")] = current_article["/R"]
+                pag_obj = cast("PageObject", pag.get_object())
+                if "/B" not in pag_obj:
+                    pag_obj[NameObject("/B")] = ArrayObject()
+                cast("ArrayObject", pag_obj["/B"]).append(
+                    new_article.indirect_reference
+                )
+            current_article = cast("DictionaryObject", current_article["/N"])
+            if current_article == first_article:
+                new_article[NameObject("/N")] = new_first.indirect_reference  # type: ignore
+                new_first[NameObject("/V")] = new_article.indirect_reference  # type: ignore
+                current_article = None
+        assert nthread.indirect_reference is not None
+        return nthread.indirect_reference
+
+    def add_filtered_articles(
+        self,
+        fltr: Union[
+            Pattern[Any], str
+        ],  # thread entry from the reader's array of threads
+        pages: Dict[int, PageObject],
+        reader: PdfReader,
+    ) -> None:
+        """
+        Add articles matching the defined criteria.
+
+        Args:
+            fltr:
+            pages:
+            reader:
+        """
+        if isinstance(fltr, str):
+            fltr = re.compile(fltr)
+        elif not isinstance(fltr, Pattern):
+            fltr = re.compile("")
+        for p in pages.values():
+            pp = p.original_page
+            for a in pp.get("/B", ()):
+                thr = a.get_object().get("/T")
+                if thr is None:
+                    continue
+                else:
+                    thr = thr.get_object()
+                if thr.indirect_reference.idnum not in self._id_translated[
+                    id(reader)
+                ] and fltr.search((thr["/I"] if "/I" in thr else {}).get("/Title", "")):
+                    self._add_articles_thread(thr, pages, reader)
+
+    def _get_cloned_page(
+        self,
+        page: Union[None, int, IndirectObject, PageObject, NullObject],
+        pages: Dict[int, PageObject],
+        reader: PdfReader,
+    ) -> Optional[IndirectObject]:
+        if isinstance(page, NullObject):
+            return None
+        if isinstance(page, int):
+            _i = reader.pages[page].indirect_reference
+        elif isinstance(page, DictionaryObject) and page.get("/Type", "") == "/Page":
+            _i = page.indirect_reference
+        elif isinstance(page, IndirectObject):
+            _i = page
+        try:
+            return pages[_i.idnum].indirect_reference  # type: ignore
+        except Exception:
+            return None
+
+    def _insert_filtered_annotations(
+        self,
+        annots: Union[IndirectObject, List[DictionaryObject]],
+        page: PageObject,
+        pages: Dict[int, PageObject],
+        reader: PdfReader,
+    ) -> List[Destination]:
+        outlist = ArrayObject()
+        if isinstance(annots, IndirectObject):
+            annots = cast("List[Any]", annots.get_object())
+        for an in annots:
+            ano = cast("DictionaryObject", an.get_object())
+            if (
+                ano["/Subtype"] != "/Link"
+                or "/A" not in ano
+                or cast("DictionaryObject", ano["/A"])["/S"] != "/GoTo"
+                or "/Dest" in ano
+            ):
+                if "/Dest" not in ano:
+                    outlist.append(self._add_object(ano.clone(self)))
+                else:
+                    d = ano["/Dest"]
+                    if isinstance(d, str):
+                        # it is a named dest
+                        if str(d) in self.get_named_dest_root():
+                            outlist.append(ano.clone(self).indirect_reference)
+                    else:
+                        d = cast("ArrayObject", d)
+                        p = self._get_cloned_page(d[0], pages, reader)
+                        if p is not None:
+                            anc = ano.clone(self, ignore_fields=("/Dest",))
+                            anc[NameObject("/Dest")] = ArrayObject([p] + d[1:])
+                            outlist.append(self._add_object(anc))
+            else:
+                d = cast("DictionaryObject", ano["/A"])["/D"]
+                if isinstance(d, str):
+                    # it is a named dest
+                    if str(d) in self.get_named_dest_root():
+                        outlist.append(ano.clone(self).indirect_reference)
+                else:
+                    d = cast("ArrayObject", d)
+                    p = self._get_cloned_page(d[0], pages, reader)
+                    if p is not None:
+                        anc = ano.clone(self, ignore_fields=("/D",))
+                        cast("DictionaryObject", anc["/A"])[
+                            NameObject("/D")
+                        ] = ArrayObject([p] + d[1:])
+                        outlist.append(self._add_object(anc))
+        return outlist
+
+    def _get_filtered_outline(
+        self,
+        node: Any,
+        pages: Dict[int, PageObject],
+        reader: PdfReader,
+    ) -> List[Destination]:
+        """
+        Extract outline item entries that are part of the specified page set.
+
+        Args:
+            node:
+            pages:
+            reader:
+
+        Returns:
+            A list of destination objects.
+        """
+        new_outline = []
+        if node is None:
+            node = NullObject()
+        node = node.get_object()
+        if node is None or isinstance(node, NullObject):
+            node = DictionaryObject()
+        if node.get("/Type", "") == "/Outlines" or "/Title" not in node:
+            node = node.get("/First", None)
+            if node is not None:
+                node = node.get_object()
+                new_outline += self._get_filtered_outline(node, pages, reader)
+        else:
+            v: Union[None, IndirectObject, NullObject]
+            while node is not None:
+                node = node.get_object()
+                o = cast("Destination", reader._build_outline_item(node))
+                v = self._get_cloned_page(cast("PageObject", o["/Page"]), pages, reader)
+                if v is None:
+                    v = NullObject()
+                o[NameObject("/Page")] = v
+                if "/First" in node:
+                    o._filtered_children = self._get_filtered_outline(
+                        node["/First"], pages, reader
+                    )
+                else:
+                    o._filtered_children = []
+                if (
+                    not isinstance(o["/Page"], NullObject)
+                    or len(o._filtered_children) > 0
+                ):
+                    new_outline.append(o)
+                node = node.get("/Next", None)
+        return new_outline
+
+    def _clone_outline(self, dest: Destination) -> TreeObject:
+        n_ol = TreeObject()
+        self._add_object(n_ol)
+        n_ol[NameObject("/Title")] = TextStringObject(dest["/Title"])
+        if not isinstance(dest["/Page"], NullObject):
+            if dest.node is not None and "/A" in dest.node:
+                n_ol[NameObject("/A")] = dest.node["/A"].clone(self)
+            else:
+                n_ol[NameObject("/Dest")] = dest.dest_array
+        # TODO: /SE
+        if dest.node is not None:
+            n_ol[NameObject("/F")] = NumberObject(dest.node.get("/F", 0))
+            n_ol[NameObject("/C")] = ArrayObject(
+                dest.node.get(
+                    "/C", [FloatObject(0.0), FloatObject(0.0), FloatObject(0.0)]
+                )
+            )
+        return n_ol
+
+    def _insert_filtered_outline(
+        self,
+        outlines: List[Destination],
+        parent: Union[TreeObject, IndirectObject],
+        before: Union[None, TreeObject, IndirectObject] = None,
+    ) -> None:
+        for dest in outlines:
+            # TODO  : can be improved to keep A and SE entries (ignored for the moment)
+            # with np=self.add_outline_item_destination(dest,parent,before)
+            if dest.get("/Type", "") == "/Outlines" or "/Title" not in dest:
+                np = parent
+            else:
+                np = self._clone_outline(dest)
+                cast(TreeObject, parent.get_object()).insert_child(np, before, self)
+            self._insert_filtered_outline(dest._filtered_children, np, None)
+
+    def close(self) -> None:
+        """Implemented for API harmonization."""
+        return
+
+    def find_outline_item(
+        self,
+        outline_item: Dict[str, Any],
+        root: Optional[OutlineType] = None,
+    ) -> Optional[List[int]]:
+        if root is None:
+            o = self.get_outline_root()
+        else:
+            o = cast("TreeObject", root)
+
+        i = 0
+        while o is not None:
+            if (
+                o.indirect_reference == outline_item
+                or o.get("/Title", None) == outline_item
+            ):
+                return [i]
+            elif "/First" in o:
+                res = self.find_outline_item(
+                    outline_item, cast(OutlineType, o["/First"])
+                )
+                if res:
+                    return ([i] if "/Title" in o else []) + res
+            if "/Next" in o:
+                i += 1
+                o = cast(TreeObject, o["/Next"])
+            else:
+                return None
+
+    def find_bookmark(
+        self,
+        outline_item: Dict[str, Any],
+        root: Optional[OutlineType] = None,
+    ) -> Optional[List[int]]:  # deprecated
+        """
+        .. deprecated:: 2.9.0
+            Use :meth:`find_outline_item` instead.
+        """
+        deprecate_with_replacement("find_bookmark", "find_outline_item", "5.0.0")
+        return self.find_outline_item(outline_item, root)
+
+    def reset_translation(
+        self, reader: Union[None, PdfReader, IndirectObject] = None
+    ) -> None:
+        """
+        Reset the translation table between reader and the writer object.
+
+        Late cloning will create new independent objects.
+
+        Args:
+            reader: PdfReader or IndirectObject referencing a PdfReader object.
+                if set to None or omitted, all tables will be reset.
+        """
+        if reader is None:
+            self._id_translated = {}
+        elif isinstance(reader, PdfReader):
+            try:
+                del self._id_translated[id(reader)]
+            except Exception:
+                pass
+        elif isinstance(reader, IndirectObject):
+            try:
+                del self._id_translated[id(reader.pdf)]
+            except Exception:
+                pass
+        else:
+            raise Exception("invalid parameter {reader}")
+
+    def set_page_label(
+        self,
+        page_index_from: int,
+        page_index_to: int,
+        style: Optional[PageLabelStyle] = None,
+        prefix: Optional[str] = None,
+        start: Optional[int] = 0,
+    ) -> None:
+        """
+        Set a page label to a range of pages.
+
+        Page indexes must be given starting from 0.
+        Labels must have a style, a prefix or both.
+        If to a range is not assigned any page label a decimal label starting from 1 is applied.
+
+        Args:
+            page_index_from: page index of the beginning of the range starting from 0
+            page_index_to: page index of the beginning of the range starting from 0
+            style: The numbering style to be used for the numeric portion of each page label:
+
+                       * ``/D`` Decimal arabic numerals
+                       * ``/R`` Uppercase roman numerals
+                       * ``/r`` Lowercase roman numerals
+                       * ``/A`` Uppercase letters (A to Z for the first 26 pages,
+                         AA to ZZ for the next 26, and so on)
+                       * ``/a`` Lowercase letters (a to z for the first 26 pages,
+                         aa to zz for the next 26, and so on)
+
+            prefix: The label prefix for page labels in this range.
+            start:  The value of the numeric portion for the first page label
+                    in the range.
+                    Subsequent pages are numbered sequentially from this value,
+                    which must be greater than or equal to 1.
+                    Default value: 1.
+        """
+        if style is None and prefix is None:
+            raise ValueError("at least one between style and prefix must be given")
+        if page_index_from < 0:
+            raise ValueError("page_index_from must be equal or greater then 0")
+        if page_index_to < page_index_from:
+            raise ValueError(
+                "page_index_to must be equal or greater then page_index_from"
+            )
+        if page_index_to >= len(self.pages):
+            raise ValueError("page_index_to exceeds number of pages")
+        if start is not None and start != 0 and start < 1:
+            raise ValueError("if given, start must be equal or greater than one")
+
+        self._set_page_label(page_index_from, page_index_to, style, prefix, start)
+
+    def _set_page_label(
+        self,
+        page_index_from: int,
+        page_index_to: int,
+        style: Optional[PageLabelStyle] = None,
+        prefix: Optional[str] = None,
+        start: Optional[int] = 0,
+    ) -> None:
+        """
+        Set a page label to a range of pages.
+
+        Page indexes must be given
+        starting from 0. Labels must have a style, a prefix or both. If to a
+        range is not assigned any page label a decimal label starting from 1 is
+        applied.
+
+        Args:
+            page_index_from: page index of the beginning of the range starting from 0
+            page_index_to: page index of the beginning of the range starting from 0
+            style:  The numbering style to be used for the numeric portion of each page label:
+                        /D Decimal arabic numerals
+                        /R Uppercase roman numerals
+                        /r Lowercase roman numerals
+                        /A Uppercase letters (A to Z for the first 26 pages,
+                           AA to ZZ for the next 26, and so on)
+                        /a Lowercase letters (a to z for the first 26 pages,
+                           aa to zz for the next 26, and so on)
+            prefix: The label prefix for page labels in this range.
+            start:  The value of the numeric portion for the first page label
+                    in the range.
+                    Subsequent pages are numbered sequentially from this value,
+                    which must be greater than or equal to 1. Default value: 1.
+        """
+        default_page_label = DictionaryObject()
+        default_page_label[NameObject("/S")] = NameObject("/D")
+
+        new_page_label = DictionaryObject()
+        if style is not None:
+            new_page_label[NameObject("/S")] = NameObject(style)
+        if prefix is not None:
+            new_page_label[NameObject("/P")] = TextStringObject(prefix)
+        if start != 0:
+            new_page_label[NameObject("/St")] = NumberObject(start)
+
+        if NameObject(CatalogDictionary.PAGE_LABELS) not in self._root_object:
+            nums = ArrayObject()
+            nums_insert(NumberObject(0), default_page_label, nums)
+            page_labels = TreeObject()
+            page_labels[NameObject("/Nums")] = nums
+            self._root_object[NameObject(CatalogDictionary.PAGE_LABELS)] = page_labels
+
+        page_labels = cast(
+            TreeObject, self._root_object[NameObject(CatalogDictionary.PAGE_LABELS)]
+        )
+        nums = cast(ArrayObject, page_labels[NameObject("/Nums")])
+
+        nums_insert(NumberObject(page_index_from), new_page_label, nums)
+        nums_clear_range(NumberObject(page_index_from), page_index_to, nums)
+        next_label_pos, *_ = nums_next(NumberObject(page_index_from), nums)
+        if next_label_pos != page_index_to + 1 and page_index_to + 1 < len(self.pages):
+            nums_insert(NumberObject(page_index_to + 1), default_page_label, nums)
+
+        page_labels[NameObject("/Nums")] = nums
+        self._root_object[NameObject(CatalogDictionary.PAGE_LABELS)] = page_labels
+
+
+def _pdf_objectify(obj: Union[Dict[str, Any], str, int, List[Any]]) -> PdfObject:
+    if isinstance(obj, PdfObject):
+        return obj
+    if isinstance(obj, dict):
+        to_add = DictionaryObject()
+        for key, value in obj.items():
+            name_key = NameObject(key)
+            casted_value = _pdf_objectify(value)
+            to_add[name_key] = casted_value
+        return to_add
+    elif isinstance(obj, list):
+        return ArrayObject(_pdf_objectify(el) for el in obj)
+    elif isinstance(obj, str):
+        if obj.startswith("/"):
+            return NameObject(obj)
+        else:
+            return TextStringObject(obj)
+    elif isinstance(obj, (int, float)):
+        return FloatObject(obj)
+    else:
+        raise NotImplementedError(
+            f"type(obj)={type(obj)} could not be casted to PdfObject"
+        )
+
+
+def _create_outline_item(
+    action_ref: Union[None, IndirectObject],
+    title: str,
+    color: Union[Tuple[float, float, float], str, None],
+    italic: bool,
+    bold: bool,
+) -> TreeObject:
+    outline_item = TreeObject()
+    if action_ref is not None:
+        outline_item[NameObject("/A")] = action_ref
+    outline_item.update(
+        {
+            NameObject("/Title"): create_string_object(title),
+        }
+    )
+    if color:
+        if isinstance(color, str):
+            color = hex_to_rgb(color)
+        outline_item.update(
+            {NameObject("/C"): ArrayObject([FloatObject(c) for c in color])}
+        )
+    if italic or bold:
+        format_flag = 0
+        if italic:
+            format_flag += 1
+        if bold:
+            format_flag += 2
+        outline_item.update({NameObject("/F"): NumberObject(format_flag)})
+    return outline_item
diff --git a/.venv/lib/python3.12/site-packages/pypdf/_xobj_image_helpers.py b/.venv/lib/python3.12/site-packages/pypdf/_xobj_image_helpers.py
new file mode 100644
index 00000000..45b0c145
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/_xobj_image_helpers.py
@@ -0,0 +1,307 @@
+"""Code in here is only used by pypdf.filters._xobj_to_image"""
+
+import sys
+from io import BytesIO
+from typing import Any, List, Tuple, Union, cast
+
+from ._utils import check_if_whitespace_only, logger_warning
+from .constants import ColorSpaces
+from .errors import PdfReadError
+from .generic import (
+    ArrayObject,
+    DecodedStreamObject,
+    EncodedStreamObject,
+    IndirectObject,
+    NullObject,
+)
+
+if sys.version_info[:2] >= (3, 8):
+    from typing import Literal
+else:
+    # PEP 586 introduced typing.Literal with Python 3.8
+    # For older Python versions, the backport typing_extensions is necessary:
+    from typing_extensions import Literal
+
+if sys.version_info[:2] >= (3, 10):
+    from typing import TypeAlias
+else:
+    from typing_extensions import TypeAlias
+
+
+try:
+    from PIL import Image, UnidentifiedImageError  # noqa: F401
+except ImportError:
+    raise ImportError(
+        "pillow is required to do image extraction. "
+        "It can be installed via 'pip install pypdf[image]'"
+    )
+
+mode_str_type: TypeAlias = Literal[
+    "", "1", "RGB", "2bits", "4bits", "P", "L", "RGBA", "CMYK"
+]
+
+MAX_IMAGE_MODE_NESTING_DEPTH: int = 10
+
+
+def _get_imagemode(
+    color_space: Union[str, List[Any], Any],
+    color_components: int,
+    prev_mode: mode_str_type,
+    depth: int = 0,
+) -> Tuple[mode_str_type, bool]:
+    """
+    Returns
+        Image mode not taking into account mask(transparency)
+        ColorInversion is required (like for some DeviceCMYK)
+    """
+    if depth > MAX_IMAGE_MODE_NESTING_DEPTH:
+        raise PdfReadError(
+            "Color spaces nested too deep. If required, consider increasing MAX_IMAGE_MODE_NESTING_DEPTH."
+        )
+    if isinstance(color_space, NullObject):
+        return "", False
+    if isinstance(color_space, str):
+        pass
+    elif not isinstance(color_space, list):
+        raise PdfReadError(
+            "Cannot interpret colorspace", color_space
+        )  # pragma: no cover
+    elif color_space[0].startswith("/Cal"):  # /CalRGB and /CalGray
+        color_space = "/Device" + color_space[0][4:]
+    elif color_space[0] == "/ICCBased":
+        icc_profile = color_space[1].get_object()
+        color_components = cast(int, icc_profile["/N"])
+        color_space = icc_profile.get("/Alternate", "")
+    elif color_space[0] == "/Indexed":
+        color_space = color_space[1].get_object()
+        mode2, invert_color = _get_imagemode(
+            color_space, color_components, prev_mode, depth + 1
+        )
+        if mode2 in ("RGB", "CMYK"):
+            mode2 = "P"
+        return mode2, invert_color
+    elif color_space[0] == "/Separation":
+        color_space = color_space[2]
+        if isinstance(color_space, IndirectObject):
+            color_space = color_space.get_object()
+        mode2, invert_color = _get_imagemode(
+            color_space, color_components, prev_mode, depth + 1
+        )
+        return mode2, True
+    elif color_space[0] == "/DeviceN":
+        original_color_space = color_space
+        color_components = len(color_space[1])
+        color_space = color_space[2]
+        if isinstance(color_space, IndirectObject):  # pragma: no cover
+            color_space = color_space.get_object()
+        if color_space == "/DeviceCMYK" and color_components == 1:
+            if original_color_space[1][0] != "/Black":
+                logger_warning(
+                    f"Color {original_color_space[1][0]} converted to Gray. Please share PDF with pypdf dev team",
+                    __name__,
+                )
+            return "L", True
+        mode2, invert_color = _get_imagemode(
+            color_space, color_components, prev_mode, depth + 1
+        )
+        return mode2, invert_color
+
+    mode_map = {
+        "1bit": "1",  # pos [0] will be used for 1 bit
+        "/DeviceGray": "L",  # must be in pos [1]
+        "palette": "P",  # must be in pos [2] for color_components align.
+        "/DeviceRGB": "RGB",  # must be in pos [3]
+        "/DeviceCMYK": "CMYK",  # must be in pos [4]
+        "2bit": "2bits",  # 2 bits images
+        "4bit": "4bits",  # 4 bits
+    }
+    mode: mode_str_type = (
+        mode_map.get(color_space)  # type: ignore
+        or list(mode_map.values())[color_components]
+        or prev_mode
+    )
+    return mode, mode == "CMYK"
+
+
+def bits2byte(data: bytes, size: Tuple[int, int], bits: int) -> bytes:
+    mask = (1 << bits) - 1
+    nbuff = bytearray(size[0] * size[1])
+    by = 0
+    bit = 8 - bits
+    for y in range(size[1]):
+        if (bit != 0) and (bit != 8 - bits):
+            by += 1
+            bit = 8 - bits
+        for x in range(size[0]):
+            nbuff[y * size[0] + x] = (data[by] >> bit) & mask
+            bit -= bits
+            if bit < 0:
+                by += 1
+                bit = 8 - bits
+    return bytes(nbuff)
+
+
+def _extended_image_frombytes(
+    mode: str, size: Tuple[int, int], data: bytes
+) -> Image.Image:
+    try:
+        img = Image.frombytes(mode, size, data)
+    except ValueError as exc:
+        nb_pix = size[0] * size[1]
+        if len(data) % nb_pix != 0:
+            raise exc
+        k = nb_pix * len(mode) / len(data)
+        data = b"".join([bytes((x,) * int(k)) for x in data])
+        img = Image.frombytes(mode, size, data)
+    return img
+
+
+def _handle_flate(
+    size: Tuple[int, int],
+    data: bytes,
+    mode: mode_str_type,
+    color_space: str,
+    colors: int,
+    obj_as_text: str,
+) -> Tuple[Image.Image, str, str, bool]:
+    """
+    Process image encoded in flateEncode
+    Returns img, image_format, extension, color inversion
+    """
+    extension = ".png"  # mime_type = "image/png"
+    image_format = "PNG"
+    lookup: Any
+    base: Any
+    hival: Any
+    if isinstance(color_space, ArrayObject) and color_space[0] == "/Indexed":
+        color_space, base, hival, lookup = (value.get_object() for value in color_space)
+    if mode == "2bits":
+        mode = "P"
+        data = bits2byte(data, size, 2)
+    elif mode == "4bits":
+        mode = "P"
+        data = bits2byte(data, size, 4)
+    img = _extended_image_frombytes(mode, size, data)
+    if color_space == "/Indexed":
+        from .generic import TextStringObject
+
+        if isinstance(lookup, (EncodedStreamObject, DecodedStreamObject)):
+            lookup = lookup.get_data()
+        if isinstance(lookup, TextStringObject):
+            lookup = lookup.original_bytes
+        if isinstance(lookup, str):
+            lookup = lookup.encode()
+        try:
+            nb, conv, mode = {  # type: ignore
+                "1": (0, "", ""),
+                "L": (1, "P", "L"),
+                "P": (0, "", ""),
+                "RGB": (3, "P", "RGB"),
+                "CMYK": (4, "P", "CMYK"),
+            }[_get_imagemode(base, 0, "")[0]]
+        except KeyError:  # pragma: no cover
+            logger_warning(
+                f"Base {base} not coded please share the pdf file with pypdf dev team",
+                __name__,
+            )
+            lookup = None
+        else:
+            if img.mode == "1":
+                # Two values ("high" and "low").
+                expected_count = 2 * nb
+                if len(lookup) != expected_count:
+                    if len(lookup) < expected_count:
+                        raise PdfReadError(
+                            f"Not enough lookup values: Expected {expected_count}, got {len(lookup)}."
+                        )
+                    if not check_if_whitespace_only(lookup[expected_count:]):
+                        raise PdfReadError(
+                            f"Too many lookup values: Expected {expected_count}, got {len(lookup)}."
+                        )
+                    lookup = lookup[:expected_count]
+                colors_arr = [lookup[:nb], lookup[nb:]]
+                arr = b"".join(
+                    [
+                        b"".join(
+                            [
+                                colors_arr[1 if img.getpixel((x, y)) > 127 else 0]
+                                for x in range(img.size[0])
+                            ]
+                        )
+                        for y in range(img.size[1])
+                    ]
+                )
+                img = Image.frombytes(mode, img.size, arr)
+            else:
+                img = img.convert(conv)
+                if len(lookup) != (hival + 1) * nb:
+                    logger_warning(f"Invalid Lookup Table in {obj_as_text}", __name__)
+                    lookup = None
+                elif mode == "L":
+                    # gray lookup does not work : it is converted to a similar RGB lookup
+                    lookup = b"".join([bytes([b, b, b]) for b in lookup])
+                    mode = "RGB"
+                # TODO : cf https://github.com/py-pdf/pypdf/pull/2039
+                # this is a work around until PIL is able to process CMYK images
+                elif mode == "CMYK":
+                    _rgb = []
+                    for _c, _m, _y, _k in (
+                        lookup[n : n + 4] for n in range(0, 4 * (len(lookup) // 4), 4)
+                    ):
+                        _r = int(255 * (1 - _c / 255) * (1 - _k / 255))
+                        _g = int(255 * (1 - _m / 255) * (1 - _k / 255))
+                        _b = int(255 * (1 - _y / 255) * (1 - _k / 255))
+                        _rgb.append(bytes((_r, _g, _b)))
+                    lookup = b"".join(_rgb)
+                    mode = "RGB"
+                if lookup is not None:
+                    img.putpalette(lookup, rawmode=mode)
+            img = img.convert("L" if base == ColorSpaces.DEVICE_GRAY else "RGB")
+    elif not isinstance(color_space, NullObject) and color_space[0] == "/ICCBased":
+        # see Table 66 - Additional Entries Specific to an ICC Profile
+        # Stream Dictionary
+        mode2 = _get_imagemode(color_space, colors, mode)[0]
+        if mode != mode2:
+            img = Image.frombytes(mode2, size, data)  # reloaded as mode may have change
+    if mode == "CMYK":
+        extension = ".tif"
+        image_format = "TIFF"
+    return img, image_format, extension, False
+
+
+def _handle_jpx(
+    size: Tuple[int, int],
+    data: bytes,
+    mode: mode_str_type,
+    color_space: str,
+    colors: int,
+) -> Tuple[Image.Image, str, str, bool]:
+    """
+    Process image encoded in flateEncode
+    Returns img, image_format, extension, inversion
+    """
+    extension = ".jp2"  # mime_type = "image/x-jp2"
+    img1 = Image.open(BytesIO(data), formats=("JPEG2000",))
+    mode, invert_color = _get_imagemode(color_space, colors, mode)
+    if mode == "":
+        mode = cast(mode_str_type, img1.mode)
+        invert_color = mode in ("CMYK",)
+    if img1.mode == "RGBA" and mode == "RGB":
+        mode = "RGBA"
+    # we need to convert to the good mode
+    if img1.mode == mode or {img1.mode, mode} == {"L", "P"}:  # compare (unordered) sets
+        # L,P are indexed modes which should not be changed.
+        img = img1
+    elif {img1.mode, mode} == {"RGBA", "CMYK"}:
+        # RGBA / CMYK are 4bytes encoding where
+        # the encoding should be corrected
+        img = Image.frombytes(mode, img1.size, img1.tobytes())
+    else:  # pragma: no cover
+        img = img1.convert(mode)
+    # for CMYK conversion :
+    # https://stcom/questions/38855022/conversion-from-cmyk-to-rgb-with-pillow-is-different-from-that-of-photoshop
+    # not implemented for the moment as I need to get properly the ICC
+    if img.mode == "CMYK":
+        img = img.convert("RGB")
+    image_format = "JPEG2000"
+    return img, image_format, extension, invert_color
diff --git a/.venv/lib/python3.12/site-packages/pypdf/annotations/__init__.py b/.venv/lib/python3.12/site-packages/pypdf/annotations/__init__.py
new file mode 100644
index 00000000..3ddf9856
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/annotations/__init__.py
@@ -0,0 +1,45 @@
+"""
+PDF specifies several annotation types which pypdf makes available here.
+
+The names of the annotations and their attributes do not reflect the names in
+the specification in all cases. For example, the PDF standard defines a
+'Square' annotation that does not actually need to be square. For this reason,
+pypdf calls it 'Rectangle'.
+
+At their core, all annotation types are DictionaryObjects. That means if pypdf
+does not implement a feature, users can easily extend the given functionality.
+"""
+
+
+from ._base import NO_FLAGS, AnnotationDictionary
+from ._markup_annotations import (
+    Ellipse,
+    FreeText,
+    Highlight,
+    Line,
+    MarkupAnnotation,
+    Polygon,
+    PolyLine,
+    Rectangle,
+    Text,
+)
+from ._non_markup_annotations import Link, Popup
+
+__all__ = [
+    "NO_FLAGS",
+    # Export abstract base classes so that they are shown in the docs
+    "AnnotationDictionary",
+    "MarkupAnnotation",
+    # markup annotations
+    "Ellipse",
+    "FreeText",
+    "Highlight",
+    "Line",
+    "Link",
+    "Polygon",
+    "PolyLine",
+    "Rectangle",
+    "Text",
+    # Non-markup annotations
+    "Popup",
+]
diff --git a/.venv/lib/python3.12/site-packages/pypdf/annotations/_base.py b/.venv/lib/python3.12/site-packages/pypdf/annotations/_base.py
new file mode 100644
index 00000000..f235acf3
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/annotations/_base.py
@@ -0,0 +1,27 @@
+from abc import ABC
+
+from ..constants import AnnotationFlag
+from ..generic import NameObject, NumberObject
+from ..generic._data_structures import DictionaryObject
+
+
+class AnnotationDictionary(DictionaryObject, ABC):
+    def __init__(self) -> None:
+        from ..generic._base import NameObject
+
+        # "rect" should not be added here as PolyLine can automatically set it
+        self[NameObject("/Type")] = NameObject("/Annot")
+        # The flags was NOT added to the constructor on purpose: We expect that
+        #   most users don't want to change the default. If they want, they
+        #   can use the property. The default is 0.
+
+    @property
+    def flags(self) -> AnnotationFlag:
+        return self.get(NameObject("/F"), AnnotationFlag(0))
+
+    @flags.setter
+    def flags(self, value: AnnotationFlag) -> None:
+        self[NameObject("/F")] = NumberObject(value)
+
+
+NO_FLAGS = AnnotationFlag(0)
diff --git a/.venv/lib/python3.12/site-packages/pypdf/annotations/_markup_annotations.py b/.venv/lib/python3.12/site-packages/pypdf/annotations/_markup_annotations.py
new file mode 100644
index 00000000..4db8dfdb
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/annotations/_markup_annotations.py
@@ -0,0 +1,308 @@
+import sys
+from abc import ABC
+from typing import Any, List, Optional, Tuple, Union
+
+from .._utils import deprecate_with_replacement
+from ..constants import AnnotationFlag
+from ..generic import ArrayObject, DictionaryObject
+from ..generic._base import (
+    BooleanObject,
+    FloatObject,
+    NameObject,
+    NumberObject,
+    TextStringObject,
+)
+from ..generic._rectangle import RectangleObject
+from ..generic._utils import hex_to_rgb
+from ._base import NO_FLAGS, AnnotationDictionary
+
+if sys.version_info[:2] >= (3, 10):
+    from typing import TypeAlias
+else:
+    # PEP 613 introduced typing.TypeAlias with Python 3.10
+    # For older Python versions, the backport typing_extensions is necessary:
+    from typing_extensions import TypeAlias
+
+
+Vertex: TypeAlias = Tuple[float, float]
+
+
+def _get_bounding_rectangle(vertices: List[Vertex]) -> RectangleObject:
+    x_min, y_min = vertices[0][0], vertices[0][1]
+    x_max, y_max = vertices[0][0], vertices[0][1]
+    for x, y in vertices:
+        x_min = min(x_min, x)
+        y_min = min(y_min, y)
+        x_max = max(x_max, x)
+        y_max = max(y_max, y)
+    rect = RectangleObject((x_min, y_min, x_max, y_max))
+    return rect
+
+
+class MarkupAnnotation(AnnotationDictionary, ABC):
+    """
+    Base class for all markup annotations.
+
+    Args:
+        title_bar: Text to be displayed in the title bar of the annotation;
+            by convention this is the name of the author
+    """
+
+    def __init__(self, *, title_bar: Optional[str] = None):
+        if title_bar is not None:
+            self[NameObject("T")] = TextStringObject(title_bar)
+
+
+class Text(MarkupAnnotation):
+    """
+    A text annotation.
+
+    Args:
+        rect: array of four integers ``[xLL, yLL, xUR, yUR]``
+            specifying the clickable rectangular area
+        text: The text that is added to the document
+        open:
+        flags:
+    """
+
+    def __init__(
+        self,
+        *,
+        rect: Union[RectangleObject, Tuple[float, float, float, float]],
+        text: str,
+        open: bool = False,
+        flags: int = NO_FLAGS,
+        **kwargs: Any,
+    ):
+        super().__init__(**kwargs)
+        self[NameObject("/Subtype")] = NameObject("/Text")
+        self[NameObject("/Rect")] = RectangleObject(rect)
+        self[NameObject("/Contents")] = TextStringObject(text)
+        self[NameObject("/Open")] = BooleanObject(open)
+        self[NameObject("/Flags")] = NumberObject(flags)
+
+
+class FreeText(MarkupAnnotation):
+    """A FreeText annotation"""
+
+    def __init__(
+        self,
+        *,
+        text: str,
+        rect: Union[RectangleObject, Tuple[float, float, float, float]],
+        font: str = "Helvetica",
+        bold: bool = False,
+        italic: bool = False,
+        font_size: str = "14pt",
+        font_color: str = "000000",
+        border_color: Optional[str] = "000000",
+        background_color: Optional[str] = "ffffff",
+        **kwargs: Any,
+    ):
+        super().__init__(**kwargs)
+        self[NameObject("/Subtype")] = NameObject("/FreeText")
+        self[NameObject("/Rect")] = RectangleObject(rect)
+
+        font_str = "font: "
+        if bold is True:
+            font_str = f"{font_str}bold "
+        if italic is True:
+            font_str = f"{font_str}italic "
+        font_str = f"{font_str}{font} {font_size}"
+        font_str = f"{font_str};text-align:left;color:#{font_color}"
+
+        default_appearance_string = ""
+        if border_color:
+            for st in hex_to_rgb(border_color):
+                default_appearance_string = f"{default_appearance_string}{st} "
+            default_appearance_string = f"{default_appearance_string}rg"
+
+        self.update(
+            {
+                NameObject("/Subtype"): NameObject("/FreeText"),
+                NameObject("/Rect"): RectangleObject(rect),
+                NameObject("/Contents"): TextStringObject(text),
+                # font size color
+                NameObject("/DS"): TextStringObject(font_str),
+                NameObject("/DA"): TextStringObject(default_appearance_string),
+            }
+        )
+        if border_color is None:
+            # Border Style
+            self[NameObject("/BS")] = DictionaryObject(
+                {
+                    # width of 0 means no border
+                    NameObject("/W"): NumberObject(0)
+                }
+            )
+        if background_color is not None:
+            self[NameObject("/C")] = ArrayObject(
+                [FloatObject(n) for n in hex_to_rgb(background_color)]
+            )
+
+
+class Line(MarkupAnnotation):
+    def __init__(
+        self,
+        p1: Vertex,
+        p2: Vertex,
+        rect: Union[RectangleObject, Tuple[float, float, float, float]],
+        text: str = "",
+        **kwargs: Any,
+    ):
+        super().__init__(**kwargs)
+        self.update(
+            {
+                NameObject("/Subtype"): NameObject("/Line"),
+                NameObject("/Rect"): RectangleObject(rect),
+                NameObject("/L"): ArrayObject(
+                    [
+                        FloatObject(p1[0]),
+                        FloatObject(p1[1]),
+                        FloatObject(p2[0]),
+                        FloatObject(p2[1]),
+                    ]
+                ),
+                NameObject("/LE"): ArrayObject(
+                    [
+                        NameObject("/None"),
+                        NameObject("/None"),
+                    ]
+                ),
+                NameObject("/IC"): ArrayObject(
+                    [
+                        FloatObject(0.5),
+                        FloatObject(0.5),
+                        FloatObject(0.5),
+                    ]
+                ),
+                NameObject("/Contents"): TextStringObject(text),
+            }
+        )
+
+
+class PolyLine(MarkupAnnotation):
+    def __init__(
+        self,
+        vertices: List[Vertex],
+        **kwargs: Any,
+    ):
+        super().__init__(**kwargs)
+        if len(vertices) == 0:
+            raise ValueError("A polygon needs at least 1 vertex with two coordinates")
+        coord_list = []
+        for x, y in vertices:
+            coord_list.append(NumberObject(x))
+            coord_list.append(NumberObject(y))
+        self.update(
+            {
+                NameObject("/Subtype"): NameObject("/PolyLine"),
+                NameObject("/Vertices"): ArrayObject(coord_list),
+                NameObject("/Rect"): RectangleObject(_get_bounding_rectangle(vertices)),
+            }
+        )
+
+
+class Rectangle(MarkupAnnotation):
+    def __init__(
+        self,
+        rect: Union[RectangleObject, Tuple[float, float, float, float]],
+        *,
+        interior_color: Optional[str] = None,
+        **kwargs: Any,
+    ):
+        if "interiour_color" in kwargs:
+            deprecate_with_replacement("interiour_color", "interior_color", "6.0.0")
+            interior_color = kwargs["interiour_color"]
+            del kwargs["interiour_color"]
+        super().__init__(**kwargs)
+        self.update(
+            {
+                NameObject("/Type"): NameObject("/Annot"),
+                NameObject("/Subtype"): NameObject("/Square"),
+                NameObject("/Rect"): RectangleObject(rect),
+            }
+        )
+
+        if interior_color:
+            self[NameObject("/IC")] = ArrayObject(
+                [FloatObject(n) for n in hex_to_rgb(interior_color)]
+            )
+
+
+class Highlight(MarkupAnnotation):
+    def __init__(
+        self,
+        *,
+        rect: Union[RectangleObject, Tuple[float, float, float, float]],
+        quad_points: ArrayObject,
+        highlight_color: str = "ff0000",
+        printing: bool = False,
+        **kwargs: Any,
+    ):
+        super().__init__(**kwargs)
+        self.update(
+            {
+                NameObject("/Subtype"): NameObject("/Highlight"),
+                NameObject("/Rect"): RectangleObject(rect),
+                NameObject("/QuadPoints"): quad_points,
+                NameObject("/C"): ArrayObject(
+                    [FloatObject(n) for n in hex_to_rgb(highlight_color)]
+                ),
+            }
+        )
+        if printing:
+            self.flags = AnnotationFlag.PRINT
+
+
+class Ellipse(MarkupAnnotation):
+    def __init__(
+        self,
+        rect: Union[RectangleObject, Tuple[float, float, float, float]],
+        *,
+        interior_color: Optional[str] = None,
+        **kwargs: Any,
+    ):
+        if "interiour_color" in kwargs:
+            deprecate_with_replacement("interiour_color", "interior_color", "6.0.0")
+            interior_color = kwargs["interiour_color"]
+            del kwargs["interiour_color"]
+        super().__init__(**kwargs)
+
+        self.update(
+            {
+                NameObject("/Type"): NameObject("/Annot"),
+                NameObject("/Subtype"): NameObject("/Circle"),
+                NameObject("/Rect"): RectangleObject(rect),
+            }
+        )
+
+        if interior_color:
+            self[NameObject("/IC")] = ArrayObject(
+                [FloatObject(n) for n in hex_to_rgb(interior_color)]
+            )
+
+
+class Polygon(MarkupAnnotation):
+    def __init__(
+        self,
+        vertices: List[Tuple[float, float]],
+        **kwargs: Any,
+    ):
+        super().__init__(**kwargs)
+        if len(vertices) == 0:
+            raise ValueError("A polygon needs at least 1 vertex with two coordinates")
+
+        coord_list = []
+        for x, y in vertices:
+            coord_list.append(NumberObject(x))
+            coord_list.append(NumberObject(y))
+        self.update(
+            {
+                NameObject("/Type"): NameObject("/Annot"),
+                NameObject("/Subtype"): NameObject("/Polygon"),
+                NameObject("/Vertices"): ArrayObject(coord_list),
+                NameObject("/IT"): NameObject("/PolygonCloud"),
+                NameObject("/Rect"): RectangleObject(_get_bounding_rectangle(vertices)),
+            }
+        )
diff --git a/.venv/lib/python3.12/site-packages/pypdf/annotations/_non_markup_annotations.py b/.venv/lib/python3.12/site-packages/pypdf/annotations/_non_markup_annotations.py
new file mode 100644
index 00000000..dcdb3b0f
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/annotations/_non_markup_annotations.py
@@ -0,0 +1,109 @@
+from typing import TYPE_CHECKING, Any, Optional, Tuple, Union
+
+from ..constants import AnnotationFlag
+from ..generic._base import (
+    BooleanObject,
+    NameObject,
+    NumberObject,
+    TextStringObject,
+)
+from ..generic._data_structures import ArrayObject, DictionaryObject
+from ..generic._fit import DEFAULT_FIT, Fit
+from ..generic._rectangle import RectangleObject
+from ._base import AnnotationDictionary
+
+DEFAULT_ANNOTATION_FLAG = AnnotationFlag(0)
+
+
+class Link(AnnotationDictionary):
+    def __init__(
+        self,
+        *,
+        rect: Union[RectangleObject, Tuple[float, float, float, float]],
+        border: Optional[ArrayObject] = None,
+        url: Optional[str] = None,
+        target_page_index: Optional[int] = None,
+        fit: Fit = DEFAULT_FIT,
+        **kwargs: Any,
+    ):
+        super().__init__(**kwargs)
+        if TYPE_CHECKING:
+            from ..types import BorderArrayType
+
+        is_external = url is not None
+        is_internal = target_page_index is not None
+        if not is_external and not is_internal:
+            raise ValueError(
+                "Either 'url' or 'target_page_index' have to be provided. Both were None."
+            )
+        if is_external and is_internal:
+            raise ValueError(
+                "Either 'url' or 'target_page_index' have to be provided. "
+                f"url={url}, target_page_index={target_page_index}"
+            )
+
+        border_arr: BorderArrayType
+        if border is not None:
+            border_arr = [NumberObject(n) for n in border[:3]]
+            if len(border) == 4:
+                dash_pattern = ArrayObject([NumberObject(n) for n in border[3]])
+                border_arr.append(dash_pattern)
+        else:
+            border_arr = [NumberObject(0)] * 3
+
+        self.update(
+            {
+                NameObject("/Type"): NameObject("/Annot"),
+                NameObject("/Subtype"): NameObject("/Link"),
+                NameObject("/Rect"): RectangleObject(rect),
+                NameObject("/Border"): ArrayObject(border_arr),
+            }
+        )
+        if is_external:
+            self[NameObject("/A")] = DictionaryObject(
+                {
+                    NameObject("/S"): NameObject("/URI"),
+                    NameObject("/Type"): NameObject("/Action"),
+                    NameObject("/URI"): TextStringObject(url),
+                }
+            )
+        if is_internal:
+            # This needs to be updated later!
+            dest_deferred = DictionaryObject(
+                {
+                    "target_page_index": NumberObject(target_page_index),
+                    "fit": NameObject(fit.fit_type),
+                    "fit_args": fit.fit_args,
+                }
+            )
+            self[NameObject("/Dest")] = dest_deferred
+
+
+class Popup(AnnotationDictionary):
+    def __init__(
+        self,
+        *,
+        rect: Union[RectangleObject, Tuple[float, float, float, float]],
+        parent: Optional[DictionaryObject] = None,
+        open: bool = False,
+        **kwargs: Any,
+    ):
+        super().__init__(**kwargs)
+        self.update(
+            {
+                NameObject("/Subtype"): NameObject("/Popup"),
+                NameObject("/Rect"): RectangleObject(rect),
+                NameObject("/Open"): BooleanObject(open),
+            }
+        )
+        if parent:
+            # This needs to be an indirect object
+            try:
+                self[NameObject("/Parent")] = parent.indirect_reference
+            except AttributeError:
+                from .._utils import logger_warning
+
+                logger_warning(
+                    "Unregistered Parent object : No Parent field set",
+                    __name__,
+                )
diff --git a/.venv/lib/python3.12/site-packages/pypdf/constants.py b/.venv/lib/python3.12/site-packages/pypdf/constants.py
new file mode 100644
index 00000000..745774e2
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/constants.py
@@ -0,0 +1,762 @@
+"""
+PDF Specification Archive
+https://pdfa.org/resource/pdf-specification-archive/
+
+Portable Document Format Reference Manual, 1993. ISBN 0-201-62628-4
+https://opensource.adobe.com/dc-acrobat-sdk-docs/pdfstandards/pdfreference1.0.pdf
+
+ISO 32000-1:2008 (PDF 1.7)
+https://opensource.adobe.com/dc-acrobat-sdk-docs/pdfstandards/PDF32000_2008.pdf
+
+ISO 32000-2:2020 (PDF 2.0)
+"""
+
+from enum import IntFlag, auto
+from typing import Dict, Tuple
+
+from ._utils import classproperty, deprecate_with_replacement
+
+
+class Core:
+    """Keywords that don't quite belong anywhere else."""
+
+    OUTLINES = "/Outlines"
+    THREADS = "/Threads"
+    PAGE = "/Page"
+    PAGES = "/Pages"
+    CATALOG = "/Catalog"
+
+
+class TrailerKeys:
+    ROOT = "/Root"
+    ENCRYPT = "/Encrypt"
+    ID = "/ID"
+    INFO = "/Info"
+    SIZE = "/Size"
+
+
+class CatalogAttributes:
+    NAMES = "/Names"
+    DESTS = "/Dests"
+
+
+class EncryptionDictAttributes:
+    """
+    Additional encryption dictionary entries for the standard security handler.
+
+    Table 3.19, Page 122.
+    Table 21 of the 2.0 manual.
+    """
+
+    R = "/R"  # number, required; revision of the standard security handler
+    O = "/O"  # 32-byte string, required  # noqa
+    U = "/U"  # 32-byte string, required
+    P = "/P"  # integer flag, required; permitted operations
+    ENCRYPT_METADATA = "/EncryptMetadata"  # boolean flag, optional
+
+
+class UserAccessPermissions(IntFlag):
+    """
+    Table 3.20 User access permissions.
+    Table 22 of the 2.0 manual.
+    """
+
+    R1 = 1
+    R2 = 2
+    PRINT = 4
+    MODIFY = 8
+    EXTRACT = 16
+    ADD_OR_MODIFY = 32
+    R7 = 64
+    R8 = 128
+    FILL_FORM_FIELDS = 256
+    EXTRACT_TEXT_AND_GRAPHICS = 512
+    ASSEMBLE_DOC = 1024
+    PRINT_TO_REPRESENTATION = 2048
+    R13 = 2**12
+    R14 = 2**13
+    R15 = 2**14
+    R16 = 2**15
+    R17 = 2**16
+    R18 = 2**17
+    R19 = 2**18
+    R20 = 2**19
+    R21 = 2**20
+    R22 = 2**21
+    R23 = 2**22
+    R24 = 2**23
+    R25 = 2**24
+    R26 = 2**25
+    R27 = 2**26
+    R28 = 2**27
+    R29 = 2**28
+    R30 = 2**29
+    R31 = 2**30
+    R32 = 2**31
+
+    @classmethod
+    def _is_reserved(cls, name: str) -> bool:
+        """Check if the given name corresponds to a reserved flag entry."""
+        return name.startswith("R") and name[1:].isdigit()
+
+    @classmethod
+    def _is_active(cls, name: str) -> bool:
+        """Check if the given reserved name defaults to 1 = active."""
+        return name not in {"R1", "R2"}
+
+    def to_dict(self) -> Dict[str, bool]:
+        """Convert the given flag value to a corresponding verbose name mapping."""
+        result: Dict[str, bool] = {}
+        for name, flag in UserAccessPermissions.__members__.items():
+            if UserAccessPermissions._is_reserved(name):
+                continue
+            result[name.lower()] = (self & flag) == flag
+        return result
+
+    @classmethod
+    def from_dict(cls, value: Dict[str, bool]) -> "UserAccessPermissions":
+        """Convert the verbose name mapping to the corresponding flag value."""
+        value_copy = value.copy()
+        result = cls(0)
+        for name, flag in cls.__members__.items():
+            if cls._is_reserved(name):
+                # Reserved names have a required value. Use it.
+                if cls._is_active(name):
+                    result |= flag
+                continue
+            is_active = value_copy.pop(name.lower(), False)
+            if is_active:
+                result |= flag
+        if value_copy:
+            raise ValueError(f"Unknown dictionary keys: {value_copy!r}")
+        return result
+
+    @classmethod
+    def all(cls) -> "UserAccessPermissions":
+        return cls((2**32 - 1) - cls.R1 - cls.R2)
+
+
+class Resources:
+    """
+    Table 3.30 Entries in a resource dictionary.
+    Used to be Ressources (a misspelling).
+
+    Table 34 in the 2.0 reference.
+    """
+
+    EXT_G_STATE = "/ExtGState"  # dictionary, optional
+    COLOR_SPACE = "/ColorSpace"  # dictionary, optional
+    PATTERN = "/Pattern"  # dictionary, optional
+    SHADING = "/Shading"  # dictionary, optional
+    XOBJECT = "/XObject"  # dictionary, optional
+    FONT = "/Font"  # dictionary, optional
+    PROC_SET = "/ProcSet"  # array, optional
+    PROPERTIES = "/Properties"  # dictionary, optional
+
+
+class Ressources:  # deprecated
+    """
+    Use :class: `Resources` instead.
+
+    .. deprecated:: 5.0.0
+    """
+
+    @classproperty
+    def EXT_G_STATE(cls) -> str:  # noqa: N805
+        deprecate_with_replacement("Ressources", "Resources", "5.0.0")
+        return "/ExtGState"  # dictionary, optional
+
+    @classproperty
+    def COLOR_SPACE(cls) -> str:  # noqa: N805
+        deprecate_with_replacement("Ressources", "Resources", "5.0.0")
+        return "/ColorSpace"  # dictionary, optional
+
+    @classproperty
+    def PATTERN(cls) -> str:  # noqa: N805
+        deprecate_with_replacement("Ressources", "Resources", "5.0.0")
+        return "/Pattern"  # dictionary, optional
+
+    @classproperty
+    def SHADING(cls) -> str:  # noqa: N805
+        deprecate_with_replacement("Ressources", "Resources", "5.0.0")
+        return "/Shading"  # dictionary, optional
+
+    @classproperty
+    def XOBJECT(cls) -> str:  # noqa: N805
+        deprecate_with_replacement("Ressources", "Resources", "5.0.0")
+        return "/XObject"  # dictionary, optional
+
+    @classproperty
+    def FONT(cls) -> str:  # noqa: N805
+        deprecate_with_replacement("Ressources", "Resources", "5.0.0")
+        return "/Font"  # dictionary, optional
+
+    @classproperty
+    def PROC_SET(cls) -> str:  # noqa: N805
+        deprecate_with_replacement("Ressources", "Resources", "5.0.0")
+        return "/ProcSet"  # array, optional
+
+    @classproperty
+    def PROPERTIES(cls) -> str:  # noqa: N805
+        deprecate_with_replacement("Ressources", "Resources", "5.0.0")
+        return "/Properties"  # dictionary, optional
+
+
+class PagesAttributes:
+    """§7.7.3.2 of the 1.7 and 2.0 reference."""
+
+    TYPE = "/Type"  # name, required; must be /Pages
+    PARENT = "/Parent"  # dictionary, required; indirect reference to pages object
+    KIDS = "/Kids"  # array, required; List of indirect references
+    COUNT = "/Count"  # integer, required; the number of leaf nodes (page objects)
+                      # that are descendants of this node within the page tree
+
+
+class PageAttributes:
+    """§7.7.3.3 of the 1.7 and 2.0 reference."""
+
+    TYPE = "/Type"  # name, required; must be /Page
+    PARENT = "/Parent"  # dictionary, required; a pages object
+    LAST_MODIFIED = "/LastModified"  # date, optional; date and time of last modification
+    RESOURCES = "/Resources"  # dictionary, required if there are any
+    MEDIABOX = "/MediaBox"  # rectangle, required; rectangle specifying page size
+    CROPBOX = "/CropBox"  # rectangle, optional
+    BLEEDBOX = "/BleedBox"  # rectangle, optional
+    TRIMBOX = "/TrimBox"  # rectangle, optional
+    ARTBOX = "/ArtBox"  # rectangle, optional
+    BOX_COLOR_INFO = "/BoxColorInfo"  # dictionary, optional
+    CONTENTS = "/Contents"  # stream or array, optional
+    ROTATE = "/Rotate"  # integer, optional; page rotation in degrees
+    GROUP = "/Group"  # dictionary, optional; page group
+    THUMB = "/Thumb"  # stream, optional; indirect reference to image of the page
+    B = "/B"  # array, optional
+    DUR = "/Dur"  # number, optional
+    TRANS = "/Trans"  # dictionary, optional
+    ANNOTS = "/Annots"  # array, optional; an array of annotations
+    AA = "/AA"  # dictionary, optional
+    METADATA = "/Metadata"  # stream, optional
+    PIECE_INFO = "/PieceInfo"  # dictionary, optional
+    STRUCT_PARENTS = "/StructParents"  # integer, optional
+    ID = "/ID"  # byte string, optional
+    PZ = "/PZ"  # number, optional
+    SEPARATION_INFO = "/SeparationInfo"  # dictionary, optional
+    TABS = "/Tabs"  # name, optional
+    TEMPLATE_INSTANTIATED = "/TemplateInstantiated"  # name, optional
+    PRES_STEPS = "/PresSteps"  # dictionary, optional
+    USER_UNIT = "/UserUnit"  # number, optional
+    VP = "/VP"  # dictionary, optional
+    AF = "/AF"  # array of dictionaries, optional
+    OUTPUT_INTENTS = "/OutputIntents"  # array, optional
+    D_PART = "/DPart"  # dictionary, required, if this page is within the range of a DPart, not permitted otherwise
+
+
+class FileSpecificationDictionaryEntries:
+    """Table 3.41 Entries in a file specification dictionary."""
+
+    Type = "/Type"
+    FS = "/FS"  # The name of the file system to be used to interpret this file specification
+    F = "/F"  # A file specification string of the form described in Section 3.10.1
+    UF = "/UF"  # A unicode string of the file as described in Section 3.10.1
+    DOS = "/DOS"
+    Mac = "/Mac"
+    Unix = "/Unix"
+    ID = "/ID"
+    V = "/V"
+    EF = "/EF"  # dictionary, containing a subset of the keys F , UF , DOS , Mac , and Unix
+    RF = "/RF"  # dictionary, containing arrays of /EmbeddedFile
+    DESC = "/Desc"  # description of the file
+    Cl = "/Cl"
+
+
+class StreamAttributes:
+    """
+    Table 4.2.
+    Table 5 in the 2.0 reference.
+    """
+
+    LENGTH = "/Length"  # integer, required
+    FILTER = "/Filter"  # name or array of names, optional
+    DECODE_PARMS = "/DecodeParms"  # variable, optional -- 'decodeParams is wrong
+
+
+class FilterTypes:
+    """§7.4 of the 1.7 and 2.0 references."""
+
+    ASCII_HEX_DECODE = "/ASCIIHexDecode"  # abbreviation: AHx
+    ASCII_85_DECODE = "/ASCII85Decode"  # abbreviation: A85
+    LZW_DECODE = "/LZWDecode"  # abbreviation: LZW
+    FLATE_DECODE = "/FlateDecode"  # abbreviation: Fl, PDF 1.2
+    RUN_LENGTH_DECODE = "/RunLengthDecode"  # abbreviation: RL
+    CCITT_FAX_DECODE = "/CCITTFaxDecode"  # abbreviation: CCF
+    DCT_DECODE = "/DCTDecode"  # abbreviation: DCT
+    JPX_DECODE = "/JPXDecode"
+
+
+class FilterTypeAbbreviations:
+    """§8.9.7 of the 1.7 and 2.0 references."""
+
+    AHx = "/AHx"
+    A85 = "/A85"
+    LZW = "/LZW"
+    FL = "/Fl"  # FlateDecode
+    RL = "/RL"
+    CCF = "/CCF"
+    DCT = "/DCT"
+
+
+class LzwFilterParameters:
+    """
+    Table 4.4.
+    Table 8 in the 2.0 reference.
+    """
+
+    PREDICTOR = "/Predictor"  # integer
+    COLORS = "/Colors"  # integer
+    BITS_PER_COMPONENT = "/BitsPerComponent"  # integer
+    COLUMNS = "/Columns"  # integer
+    EARLY_CHANGE = "/EarlyChange"  # integer
+
+
+class CcittFaxDecodeParameters:
+    """
+    Table 4.5.
+    Table 11 in the 2.0 reference.
+    """
+
+    K = "/K"  # integer
+    END_OF_LINE = "/EndOfLine"  # boolean
+    ENCODED_BYTE_ALIGN = "/EncodedByteAlign"  # boolean
+    COLUMNS = "/Columns"  # integer
+    ROWS = "/Rows"  # integer
+    END_OF_BLOCK = "/EndOfBlock"  # boolean
+    BLACK_IS_1 = "/BlackIs1"  # boolean
+    DAMAGED_ROWS_BEFORE_ERROR = "/DamagedRowsBeforeError"  # integer
+
+
+class ImageAttributes:
+    """§11.6.5 of the 1.7 and 2.0 references."""
+
+    TYPE = "/Type"  # name, required; must be /XObject
+    SUBTYPE = "/Subtype"  # name, required; must be /Image
+    NAME = "/Name"  # name, required
+    WIDTH = "/Width"  # integer, required
+    HEIGHT = "/Height"  # integer, required
+    BITS_PER_COMPONENT = "/BitsPerComponent"  # integer, required
+    COLOR_SPACE = "/ColorSpace"  # name, required
+    DECODE = "/Decode"  # array, optional
+    INTENT = "/Intent"  # string, optional
+    INTERPOLATE = "/Interpolate"  # boolean, optional
+    IMAGE_MASK = "/ImageMask"  # boolean, optional
+    MASK = "/Mask"  # 1-bit image mask stream
+    S_MASK = "/SMask"  # dictionary or name, optional
+
+
+class ColorSpaces:
+    DEVICE_RGB = "/DeviceRGB"
+    DEVICE_CMYK = "/DeviceCMYK"
+    DEVICE_GRAY = "/DeviceGray"
+
+
+class TypArguments:
+    """Table 8.2 of the PDF 1.7 reference."""
+
+    LEFT = "/Left"
+    RIGHT = "/Right"
+    BOTTOM = "/Bottom"
+    TOP = "/Top"
+
+
+class TypFitArguments:
+    """Table 8.2 of the PDF 1.7 reference."""
+
+    FIT = "/Fit"
+    FIT_V = "/FitV"
+    FIT_BV = "/FitBV"
+    FIT_B = "/FitB"
+    FIT_H = "/FitH"
+    FIT_BH = "/FitBH"
+    FIT_R = "/FitR"
+    XYZ = "/XYZ"
+
+
+class GoToActionArguments:
+    S = "/S"  # name, required: type of action
+    D = "/D"  # name / byte string /array, required: Destination to jump to
+
+
+class AnnotationDictionaryAttributes:
+    """Table 8.15 Entries common to all annotation dictionaries."""
+
+    Type = "/Type"
+    Subtype = "/Subtype"
+    Rect = "/Rect"
+    Contents = "/Contents"
+    P = "/P"
+    NM = "/NM"
+    M = "/M"
+    F = "/F"
+    AP = "/AP"
+    AS = "/AS"
+    DA = "/DA"
+    Border = "/Border"
+    C = "/C"
+    StructParent = "/StructParent"
+    OC = "/OC"
+
+
+class InteractiveFormDictEntries:
+    Fields = "/Fields"
+    NeedAppearances = "/NeedAppearances"
+    SigFlags = "/SigFlags"
+    CO = "/CO"
+    DR = "/DR"
+    DA = "/DA"
+    Q = "/Q"
+    XFA = "/XFA"
+
+
+class FieldDictionaryAttributes:
+    """
+    Entries common to all field dictionaries (Table 8.69 PDF 1.7 reference)
+    (*very partially documented here*).
+
+    FFBits provides the constants used for `/Ff` from Table 8.70/8.75/8.77/8.79
+    """
+
+    FT = "/FT"  # name, required for terminal fields
+    Parent = "/Parent"  # dictionary, required for children
+    Kids = "/Kids"  # array, sometimes required
+    T = "/T"  # text string, optional
+    TU = "/TU"  # text string, optional
+    TM = "/TM"  # text string, optional
+    Ff = "/Ff"  # integer, optional
+    V = "/V"  # text string or array, optional
+    DV = "/DV"  # text string, optional
+    AA = "/AA"  # dictionary, optional
+    Opt = "/Opt"
+
+    class FfBits(IntFlag):
+        """
+        Ease building /Ff flags
+        Some entries may be specific to:
+
+        * Text(Tx) (Table 8.75 PDF 1.7 reference)
+        * Buttons(Btn) (Table 8.77 PDF 1.7 reference)
+        * List(Ch) (Table 8.79 PDF 1.7 reference)
+        """
+
+        ReadOnly = 1 << 0
+        """common to Tx/Btn/Ch in Table 8.70"""
+        Required = 1 << 1
+        """common to Tx/Btn/Ch in Table 8.70"""
+        NoExport = 1 << 2
+        """common to Tx/Btn/Ch in Table 8.70"""
+
+        Multiline = 1 << 12
+        """Tx"""
+        Password = 1 << 13
+        """Tx"""
+
+        NoToggleToOff = 1 << 14
+        """Btn"""
+        Radio = 1 << 15
+        """Btn"""
+        Pushbutton = 1 << 16
+        """Btn"""
+
+        Combo = 1 << 17
+        """Ch"""
+        Edit = 1 << 18
+        """Ch"""
+        Sort = 1 << 19
+        """Ch"""
+
+        FileSelect = 1 << 20
+        """Tx"""
+
+        MultiSelect = 1 << 21
+        """Tx"""
+
+        DoNotSpellCheck = 1 << 22
+        """Tx/Ch"""
+        DoNotScroll = 1 << 23
+        """Tx"""
+        Comb = 1 << 24
+        """Tx"""
+
+        RadiosInUnison = 1 << 25
+        """Btn"""
+
+        RichText = 1 << 25
+        """Tx"""
+
+        CommitOnSelChange = 1 << 26
+        """Ch"""
+
+    @classmethod
+    def attributes(cls) -> Tuple[str, ...]:
+        """
+        Get a tuple of all the attributes present in a Field Dictionary.
+
+        This method returns a tuple of all the attribute constants defined in
+        the FieldDictionaryAttributes class. These attributes correspond to the
+        entries that are common to all field dictionaries as specified in the
+        PDF 1.7 reference.
+
+        Returns:
+            A tuple containing all the attribute constants.
+        """
+        return (
+            cls.TM,
+            cls.T,
+            cls.FT,
+            cls.Parent,
+            cls.TU,
+            cls.Ff,
+            cls.V,
+            cls.DV,
+            cls.Kids,
+            cls.AA,
+        )
+
+    @classmethod
+    def attributes_dict(cls) -> Dict[str, str]:
+        """
+        Get a dictionary of attribute keys and their human-readable names.
+
+        This method returns a dictionary where the keys are the attribute
+        constants defined in the FieldDictionaryAttributes class and the values
+        are their corresponding human-readable names. These attributes
+        correspond to the entries that are common to all field dictionaries as
+        specified in the PDF 1.7 reference.
+
+        Returns:
+            A dictionary containing attribute keys and their names.
+        """
+        return {
+            cls.FT: "Field Type",
+            cls.Parent: "Parent",
+            cls.T: "Field Name",
+            cls.TU: "Alternate Field Name",
+            cls.TM: "Mapping Name",
+            cls.Ff: "Field Flags",
+            cls.V: "Value",
+            cls.DV: "Default Value",
+        }
+
+
+class CheckboxRadioButtonAttributes:
+    """Table 8.76 Field flags common to all field types."""
+
+    Opt = "/Opt"  # Options, Optional
+
+    @classmethod
+    def attributes(cls) -> Tuple[str, ...]:
+        """
+        Get a tuple of all the attributes present in a Field Dictionary.
+
+        This method returns a tuple of all the attribute constants defined in
+        the CheckboxRadioButtonAttributes class. These attributes correspond to
+        the entries that are common to all field dictionaries as specified in
+        the PDF 1.7 reference.
+
+        Returns:
+            A tuple containing all the attribute constants.
+        """
+        return (cls.Opt,)
+
+    @classmethod
+    def attributes_dict(cls) -> Dict[str, str]:
+        """
+        Get a dictionary of attribute keys and their human-readable names.
+
+        This method returns a dictionary where the keys are the attribute
+        constants defined in the CheckboxRadioButtonAttributes class and the
+        values are their corresponding human-readable names. These attributes
+        correspond to the entries that are common to all field dictionaries as
+        specified in the PDF 1.7 reference.
+
+        Returns:
+            A dictionary containing attribute keys and their names.
+        """
+        return {
+            cls.Opt: "Options",
+        }
+
+
+class FieldFlag(IntFlag):
+    """Table 8.70 Field flags common to all field types."""
+
+    READ_ONLY = 1
+    REQUIRED = 2
+    NO_EXPORT = 4
+
+
+class DocumentInformationAttributes:
+    """Table 10.2 Entries in the document information dictionary."""
+
+    TITLE = "/Title"  # text string, optional
+    AUTHOR = "/Author"  # text string, optional
+    SUBJECT = "/Subject"  # text string, optional
+    KEYWORDS = "/Keywords"  # text string, optional
+    CREATOR = "/Creator"  # text string, optional
+    PRODUCER = "/Producer"  # text string, optional
+    CREATION_DATE = "/CreationDate"  # date, optional
+    MOD_DATE = "/ModDate"  # date, optional
+    TRAPPED = "/Trapped"  # name, optional
+
+
+class PageLayouts:
+    """
+    Page 84, PDF 1.4 reference.
+    Page 115, PDF 2.0 reference.
+    """
+
+    SINGLE_PAGE = "/SinglePage"
+    ONE_COLUMN = "/OneColumn"
+    TWO_COLUMN_LEFT = "/TwoColumnLeft"
+    TWO_COLUMN_RIGHT = "/TwoColumnRight"
+    TWO_PAGE_LEFT = "/TwoPageLeft"  # (PDF 1.5)
+    TWO_PAGE_RIGHT = "/TwoPageRight"  # (PDF 1.5)
+
+
+class GraphicsStateParameters:
+    """Table 58 – Entries in a Graphics State Parameter Dictionary"""
+
+    TYPE = "/Type"  # name, optional
+    LW = "/LW"  # number, optional
+    LC = "/LC"  # integer, optional
+    LJ = "/LJ"  # integer, optional
+    ML = "/ML"  # number, optional
+    D = "/D"  # array, optional
+    RI = "/RI"  # name, optional
+    OP = "/OP"
+    op = "/op"
+    OPM = "/OPM"
+    FONT = "/Font"  # array, optional
+    BG = "/BG"
+    BG2 = "/BG2"
+    UCR = "/UCR"
+    UCR2 = "/UCR2"
+    TR = "/TR"
+    TR2 = "/TR2"
+    HT = "/HT"
+    FL = "/FL"
+    SM = "/SM"
+    SA = "/SA"
+    BM = "/BM"
+    S_MASK = "/SMask"  # dictionary or name, optional
+    CA = "/CA"
+    ca = "/ca"
+    AIS = "/AIS"
+    TK = "/TK"
+
+
+class CatalogDictionary:
+    """§7.7.2 of the 1.7 and 2.0 references."""
+
+    TYPE = "/Type"  # name, required; must be /Catalog
+    VERSION = "/Version"  # name
+    EXTENSIONS = "/Extensions"  # dictionary, optional; ISO 32000-1
+    PAGES = "/Pages"  # dictionary, required
+    PAGE_LABELS = "/PageLabels"  # number tree, optional
+    NAMES = "/Names"  # dictionary, optional
+    DESTS = "/Dests"  # dictionary, optional
+    VIEWER_PREFERENCES = "/ViewerPreferences"  # dictionary, optional
+    PAGE_LAYOUT = "/PageLayout"  # name, optional
+    PAGE_MODE = "/PageMode"  # name, optional
+    OUTLINES = "/Outlines"  # dictionary, optional
+    THREADS = "/Threads"  # array, optional
+    OPEN_ACTION = "/OpenAction"  # array or dictionary or name, optional
+    AA = "/AA"  # dictionary, optional
+    URI = "/URI"  # dictionary, optional
+    ACRO_FORM = "/AcroForm"  # dictionary, optional
+    METADATA = "/Metadata"  # stream, optional
+    STRUCT_TREE_ROOT = "/StructTreeRoot"  # dictionary, optional
+    MARK_INFO = "/MarkInfo"  # dictionary, optional
+    LANG = "/Lang"  # text string, optional
+    SPIDER_INFO = "/SpiderInfo"  # dictionary, optional
+    OUTPUT_INTENTS = "/OutputIntents"  # array, optional
+    PIECE_INFO = "/PieceInfo"  # dictionary, optional
+    OC_PROPERTIES = "/OCProperties"  # dictionary, optional
+    PERMS = "/Perms"  # dictionary, optional
+    LEGAL = "/Legal"  # dictionary, optional
+    REQUIREMENTS = "/Requirements"  # array, optional
+    COLLECTION = "/Collection"  # dictionary, optional
+    NEEDS_RENDERING = "/NeedsRendering"  # boolean, optional
+    DSS = "/DSS"  # dictionary, optional
+    AF = "/AF"  # array of dictionaries, optional
+    D_PART_ROOT = "/DPartRoot"  # dictionary, optional
+
+
+class OutlineFontFlag(IntFlag):
+    """A class used as an enumerable flag for formatting an outline font."""
+
+    italic = 1
+    bold = 2
+
+
+class PageLabelStyle:
+    """
+    Table 8.10 in the 1.7 reference.
+    Table 161 in the 2.0 reference.
+    """
+
+    DECIMAL = "/D"  # Decimal Arabic numerals
+    UPPERCASE_ROMAN = "/R"  # Uppercase Roman numerals
+    LOWERCASE_ROMAN = "/r"  # Lowercase Roman numerals
+    UPPERCASE_LETTER = "/A"  # Uppercase letters
+    LOWERCASE_LETTER = "/a"  # Lowercase letters
+
+
+class AnnotationFlag(IntFlag):
+    """See §12.5.3 "Annotation Flags"."""
+
+    INVISIBLE = 1
+    HIDDEN = 2
+    PRINT = 4
+    NO_ZOOM = 8
+    NO_ROTATE = 16
+    NO_VIEW = 32
+    READ_ONLY = 64
+    LOCKED = 128
+    TOGGLE_NO_VIEW = 256
+    LOCKED_CONTENTS = 512
+
+
+PDF_KEYS = (
+    AnnotationDictionaryAttributes,
+    CatalogAttributes,
+    CatalogDictionary,
+    CcittFaxDecodeParameters,
+    CheckboxRadioButtonAttributes,
+    ColorSpaces,
+    Core,
+    DocumentInformationAttributes,
+    EncryptionDictAttributes,
+    FieldDictionaryAttributes,
+    FilterTypeAbbreviations,
+    FilterTypes,
+    GoToActionArguments,
+    GraphicsStateParameters,
+    ImageAttributes,
+    FileSpecificationDictionaryEntries,
+    LzwFilterParameters,
+    PageAttributes,
+    PageLayouts,
+    PagesAttributes,
+    Resources,
+    StreamAttributes,
+    TrailerKeys,
+    TypArguments,
+    TypFitArguments,
+)
+
+
+class ImageType(IntFlag):
+    NONE = 0
+    XOBJECT_IMAGES = auto()
+    INLINE_IMAGES = auto()
+    DRAWING_IMAGES = auto()
+    ALL = XOBJECT_IMAGES | INLINE_IMAGES | DRAWING_IMAGES
+    IMAGES = ALL  # for consistency with ObjectDeletionFlag
diff --git a/.venv/lib/python3.12/site-packages/pypdf/errors.py b/.venv/lib/python3.12/site-packages/pypdf/errors.py
new file mode 100644
index 00000000..c962dec6
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/errors.py
@@ -0,0 +1,62 @@
+"""
+All errors/exceptions pypdf raises and all of the warnings it uses.
+
+Please note that broken PDF files might cause other Exceptions.
+"""
+
+
+class DeprecationError(Exception):
+    """Raised when a deprecated feature is used."""
+
+
+class DependencyError(Exception):
+    """
+    Raised when a required dependency (a library or module that PyPDF depends on)
+    is not available or cannot be imported.
+    """
+
+
+class PyPdfError(Exception):
+    """Base class for all exceptions raised by PyPDF."""
+
+
+class PdfReadError(PyPdfError):
+    """Raised when there is an issue reading a PDF file."""
+
+
+class PageSizeNotDefinedError(PyPdfError):
+    """Raised when the page size of a PDF document is not defined."""
+
+
+class PdfReadWarning(UserWarning):
+    """Issued when there is a potential issue reading a PDF file, but it can still be read."""
+
+
+class PdfStreamError(PdfReadError):
+    """Raised when there is an issue reading the stream of data in a PDF file."""
+
+
+class ParseError(PyPdfError):
+    """
+    Raised when there is an issue parsing (analyzing and understanding the
+    structure and meaning of) a PDF file.
+    """
+
+
+class FileNotDecryptedError(PdfReadError):
+    """
+    Raised when a PDF file that has been encrypted
+    (meaning it requires a password to be accessed) has not been successfully
+    decrypted.
+    """
+
+
+class WrongPasswordError(FileNotDecryptedError):
+    """Raised when the wrong password is used to try to decrypt an encrypted PDF file."""
+
+
+class EmptyFileError(PdfReadError):
+    """Raised when a PDF file is empty or has no content."""
+
+
+STREAM_TRUNCATED_PREMATURELY = "Stream has ended unexpectedly"
diff --git a/.venv/lib/python3.12/site-packages/pypdf/filters.py b/.venv/lib/python3.12/site-packages/pypdf/filters.py
new file mode 100644
index 00000000..5e6a10f7
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/filters.py
@@ -0,0 +1,910 @@
+# Copyright (c) 2006, Mathieu Fenniak
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# * The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+
+"""
+Implementation of stream filters for PDF.
+
+See TABLE H.1 Abbreviations for standard filter names
+"""
+__author__ = "Mathieu Fenniak"
+__author_email__ = "biziqe@mathieu.fenniak.net"
+
+import math
+import struct
+import zlib
+from base64 import a85decode
+from io import BytesIO
+from typing import Any, Dict, List, Optional, Tuple, Union, cast
+
+from ._utils import (
+    WHITESPACES_AS_BYTES,
+    b_,
+    deprecate_with_replacement,
+    deprecation_no_replacement,
+    logger_warning,
+    ord_,
+)
+from .constants import CcittFaxDecodeParameters as CCITT
+from .constants import ColorSpaces
+from .constants import FilterTypeAbbreviations as FTA
+from .constants import FilterTypes as FT
+from .constants import ImageAttributes as IA
+from .constants import LzwFilterParameters as LZW
+from .constants import StreamAttributes as SA
+from .errors import DeprecationError, PdfReadError, PdfStreamError
+from .generic import (
+    ArrayObject,
+    DictionaryObject,
+    IndirectObject,
+    NullObject,
+)
+
+
+def decompress(data: bytes) -> bytes:
+    """
+    Decompress the given data using zlib.
+
+    This function attempts to decompress the input data using zlib. If the
+    decompression fails due to a zlib error, it falls back to using a
+    decompression object with a larger window size.
+
+    Args:
+        data: The input data to be decompressed.
+
+    Returns:
+        The decompressed data.
+    """
+    try:
+        return zlib.decompress(data)
+    except zlib.error:
+        try:
+            # For larger files, use Decompress object to enable buffered reading
+            return zlib.decompressobj().decompress(data)
+        except zlib.error:
+            # If still failed, then try with increased window size
+            d = zlib.decompressobj(zlib.MAX_WBITS | 32)
+            result_str = b""
+            for b in [data[i : i + 1] for i in range(len(data))]:
+                try:
+                    result_str += d.decompress(b)
+                except zlib.error:
+                    pass
+            return result_str
+
+
+class FlateDecode:
+    @staticmethod
+    def decode(
+        data: bytes,
+        decode_parms: Optional[DictionaryObject] = None,
+        **kwargs: Any,
+    ) -> bytes:
+        """
+        Decode data which is flate-encoded.
+
+        Args:
+          data: flate-encoded data.
+          decode_parms: a dictionary of values, understanding the
+            "/Predictor":<int> key only
+
+        Returns:
+          The flate-decoded data.
+
+        Raises:
+          PdfReadError:
+        """
+        if "decodeParms" in kwargs:  # deprecated
+            deprecate_with_replacement("decodeParms", "parameters", "4.0.0")
+            decode_parms = kwargs["decodeParms"]
+        if isinstance(decode_parms, ArrayObject):
+            raise DeprecationError("decode_parms as ArrayObject is depreciated")
+
+        str_data = decompress(data)
+        predictor = 1
+
+        if decode_parms:
+            try:
+                predictor = decode_parms.get("/Predictor", 1)
+            except (AttributeError, TypeError):  # Type Error is NullObject
+                pass  # Usually an array with a null object was read
+        # predictor 1 == no predictor
+        if predictor != 1:
+            # /Columns, the number of samples in each row, has a default value of 1;
+            # §7.4.4.3, ISO 32000.
+            DEFAULT_BITS_PER_COMPONENT = 8
+            try:
+                columns = cast(int, decode_parms[LZW.COLUMNS].get_object())  # type: ignore
+            except (TypeError, KeyError):
+                columns = 1
+            try:
+                colors = cast(int, decode_parms[LZW.COLORS].get_object())  # type: ignore
+            except (TypeError, KeyError):
+                colors = 1
+            try:
+                bits_per_component = cast(
+                    int,
+                    decode_parms[LZW.BITS_PER_COMPONENT].get_object(),  # type: ignore
+                )
+            except (TypeError, KeyError):
+                bits_per_component = DEFAULT_BITS_PER_COMPONENT
+
+            # PNG predictor can vary by row and so is the lead byte on each row
+            rowlength = (
+                math.ceil(columns * colors * bits_per_component / 8) + 1
+            )  # number of bytes
+
+            # TIFF prediction:
+            if predictor == 2:
+                rowlength -= 1  # remove the predictor byte
+                bpp = rowlength // columns
+                str_data = bytearray(str_data)
+                for i in range(len(str_data)):
+                    if i % rowlength >= bpp:
+                        str_data[i] = (str_data[i] + str_data[i - bpp]) % 256
+                str_data = bytes(str_data)
+            # PNG prediction:
+            elif 10 <= predictor <= 15:
+                str_data = FlateDecode._decode_png_prediction(
+                    str_data, columns, rowlength
+                )
+            else:
+                # unsupported predictor
+                raise PdfReadError(f"Unsupported flatedecode predictor {predictor!r}")
+        return str_data
+
+    @staticmethod
+    def _decode_png_prediction(data: bytes, columns: int, rowlength: int) -> bytes:
+        # PNG prediction can vary from row to row
+        if len(data) % rowlength != 0:
+            raise PdfReadError("Image data is not rectangular")
+        output = []
+        prev_rowdata = (0,) * rowlength
+        bpp = (rowlength - 1) // columns  # recomputed locally to not change params
+        for row in range(0, len(data), rowlength):
+            rowdata: List[int] = list(data[row : row + rowlength])
+            filter_byte = rowdata[0]
+
+            if filter_byte == 0:
+                pass
+            elif filter_byte == 1:
+                for i in range(bpp + 1, rowlength):
+                    rowdata[i] = (rowdata[i] + rowdata[i - bpp]) % 256
+            elif filter_byte == 2:
+                for i in range(1, rowlength):
+                    rowdata[i] = (rowdata[i] + prev_rowdata[i]) % 256
+            elif filter_byte == 3:
+                for i in range(1, bpp + 1):
+                    # left = 0
+                    floor = prev_rowdata[i] // 2
+                    rowdata[i] = (rowdata[i] + floor) % 256
+                for i in range(bpp + 1, rowlength):
+                    left = rowdata[i - bpp]
+                    floor = (left + prev_rowdata[i]) // 2
+                    rowdata[i] = (rowdata[i] + floor) % 256
+            elif filter_byte == 4:
+                for i in range(1, bpp + 1):
+                    # left = 0
+                    up = prev_rowdata[i]
+                    # up_left = 0
+                    paeth = up
+                    rowdata[i] = (rowdata[i] + paeth) % 256
+                for i in range(bpp + 1, rowlength):
+                    left = rowdata[i - bpp]
+                    up = prev_rowdata[i]
+                    up_left = prev_rowdata[i - bpp]
+
+                    p = left + up - up_left
+                    dist_left = abs(p - left)
+                    dist_up = abs(p - up)
+                    dist_up_left = abs(p - up_left)
+
+                    if dist_left <= dist_up and dist_left <= dist_up_left:
+                        paeth = left
+                    elif dist_up <= dist_up_left:
+                        paeth = up
+                    else:
+                        paeth = up_left
+
+                    rowdata[i] = (rowdata[i] + paeth) % 256
+            else:
+                # unsupported PNG filter
+                raise PdfReadError(
+                    f"Unsupported PNG filter {filter_byte!r}"
+                )  # pragma: no cover
+            prev_rowdata = tuple(rowdata)
+            output.extend(rowdata[1:])
+        return bytes(output)
+
+    @staticmethod
+    def encode(data: bytes, level: int = -1) -> bytes:
+        """
+        Compress the input data using zlib.
+
+        Args:
+            data: The data to be compressed.
+            level: See https://docs.python.org/3/library/zlib.html#zlib.compress
+
+        Returns:
+            The compressed data.
+        """
+        return zlib.compress(data, level)
+
+
+class ASCIIHexDecode:
+    """
+    The ASCIIHexDecode filter decodes data that has been encoded in ASCII
+    hexadecimal form into a base-7 ASCII format.
+    """
+
+    @staticmethod
+    def decode(
+        data: Union[str, bytes],
+        decode_parms: Optional[DictionaryObject] = None,
+        **kwargs: Any,
+    ) -> bytes:
+        """
+        Decode an ASCII-Hex encoded data stream.
+
+        Args:
+          data: a str sequence of hexadecimal-encoded values to be
+            converted into a base-7 ASCII string
+          decode_parms: a string conversion in base-7 ASCII, where each of its values
+            v is such that 0 <= ord(v) <= 127.
+
+        Returns:
+          A string conversion in base-7 ASCII, where each of its values
+          v is such that 0 <= ord(v) <= 127.
+
+        Raises:
+          PdfStreamError:
+        """
+        # decode_parms is unused here
+
+        if isinstance(data, str):
+            data = data.encode()
+        retval = b""
+        hex_pair = b""
+        index = 0
+        while True:
+            if index >= len(data):
+                logger_warning(
+                    "missing EOD in ASCIIHexDecode, check if output is OK", __name__
+                )
+                break  # reach End Of String even if no EOD
+            char = data[index : index + 1]
+            if char == b">":
+                break
+            elif char.isspace():
+                index += 1
+                continue
+            hex_pair += char
+            if len(hex_pair) == 2:
+                retval += bytes((int(hex_pair, base=16),))
+                hex_pair = b""
+            index += 1
+        assert hex_pair == b""
+        return retval
+
+
+class RunLengthDecode:
+    """
+    The RunLengthDecode filter decodes data that has been encoded in a
+    simple byte-oriented format based on run length.
+    The encoded data is a sequence of runs, where each run consists of
+    a length byte followed by 1 to 128 bytes of data. If the length byte is
+    in the range 0 to 127,
+    the following length + 1 (1 to 128) bytes are copied literally during
+    decompression.
+    If length is in the range 129 to 255, the following single byte is to be
+    copied 257 − length (2 to 128) times during decompression. A length value
+    of 128 denotes EOD.
+    """
+
+    @staticmethod
+    def decode(
+        data: bytes,
+        decode_parms: Optional[DictionaryObject] = None,
+        **kwargs: Any,
+    ) -> bytes:
+        """
+        Decode a run length encoded data stream.
+
+        Args:
+          data: a bytes sequence of length/data
+          decode_parms: ignored.
+
+        Returns:
+          A bytes decompressed sequence.
+
+        Raises:
+          PdfStreamError:
+        """
+        # decode_parms is unused here
+
+        lst = []
+        index = 0
+        while True:
+            if index >= len(data):
+                logger_warning(
+                    "missing EOD in RunLengthDecode, check if output is OK", __name__
+                )
+                break  # reach End Of String even if no EOD
+            length = data[index]
+            index += 1
+            if length == 128:
+                if index < len(data):
+                    raise PdfStreamError("early EOD in RunLengthDecode")
+                else:
+                    break
+            elif length < 128:
+                length += 1
+                lst.append(data[index : (index + length)])
+                index += length
+            else:  # >128
+                length = 257 - length
+                lst.append(bytes((data[index],)) * length)
+                index += 1
+        return b"".join(lst)
+
+
+class LZWDecode:
+    """
+    Taken from:
+
+    http://www.java2s.com/Open-Source/Java-Document/PDF/PDF-
+    Renderer/com/sun/pdfview/decode/LZWDecode.java.htm
+    """
+
+    class Decoder:
+        def __init__(self, data: bytes) -> None:
+            self.STOP = 257
+            self.CLEARDICT = 256
+            self.data = data
+            self.bytepos = 0
+            self.bitpos = 0
+            self.dict = [""] * 4096
+            for i in range(256):
+                self.dict[i] = chr(i)
+            self.reset_dict()
+
+        def reset_dict(self) -> None:
+            self.dictlen = 258
+            self.bitspercode = 9
+
+        def next_code(self) -> int:
+            fillbits = self.bitspercode
+            value = 0
+            while fillbits > 0:
+                if self.bytepos >= len(self.data):
+                    return -1
+                nextbits = ord_(self.data[self.bytepos])
+                bitsfromhere = 8 - self.bitpos
+                bitsfromhere = min(bitsfromhere, fillbits)
+                value |= (
+                    (nextbits >> (8 - self.bitpos - bitsfromhere))
+                    & (0xFF >> (8 - bitsfromhere))
+                ) << (fillbits - bitsfromhere)
+                fillbits -= bitsfromhere
+                self.bitpos += bitsfromhere
+                if self.bitpos >= 8:
+                    self.bitpos = 0
+                    self.bytepos = self.bytepos + 1
+            return value
+
+        def decode(self) -> str:
+            """
+            TIFF 6.0 specification explains in sufficient details the steps to
+            implement the LZW encode() and decode() algorithms.
+
+            algorithm derived from:
+            http://www.rasip.fer.hr/research/compress/algorithms/fund/lz/lzw.html
+            and the PDFReference
+
+            Raises:
+              PdfReadError: If the stop code is missing
+            """
+            cW = self.CLEARDICT
+            baos = ""
+            while True:
+                pW = cW
+                cW = self.next_code()
+                if cW == -1:
+                    raise PdfReadError("Missed the stop code in LZWDecode!")
+                if cW == self.STOP:
+                    break
+                elif cW == self.CLEARDICT:
+                    self.reset_dict()
+                elif pW == self.CLEARDICT:
+                    baos += self.dict[cW]
+                else:
+                    if cW < self.dictlen:
+                        baos += self.dict[cW]
+                        p = self.dict[pW] + self.dict[cW][0]
+                        self.dict[self.dictlen] = p
+                        self.dictlen += 1
+                    else:
+                        p = self.dict[pW] + self.dict[pW][0]
+                        baos += p
+                        self.dict[self.dictlen] = p
+                        self.dictlen += 1
+                    if (
+                        self.dictlen >= (1 << self.bitspercode) - 1
+                        and self.bitspercode < 12
+                    ):
+                        self.bitspercode += 1
+            return baos
+
+    @staticmethod
+    def decode(
+        data: bytes,
+        decode_parms: Optional[DictionaryObject] = None,
+        **kwargs: Any,
+    ) -> str:
+        """
+        Decode an LZW encoded data stream.
+
+        Args:
+          data: ``bytes`` or ``str`` text to decode.
+          decode_parms: a dictionary of parameter values.
+
+        Returns:
+          decoded data.
+        """
+        # decode_parms is unused here
+
+        return LZWDecode.Decoder(data).decode()
+
+
+class ASCII85Decode:
+    """Decodes string ASCII85-encoded data into a byte format."""
+
+    @staticmethod
+    def decode(
+        data: Union[str, bytes],
+        decode_parms: Optional[DictionaryObject] = None,
+        **kwargs: Any,
+    ) -> bytes:
+        """
+        Decode an Ascii85 encoded data stream.
+
+        Args:
+          data: ``bytes`` or ``str`` text to decode.
+          decode_parms: a dictionary of parameter values.
+
+        Returns:
+          decoded data.
+        """
+        if isinstance(data, str):
+            data = data.encode()
+        data = data.strip(WHITESPACES_AS_BYTES)
+        return a85decode(data, adobe=True, ignorechars=WHITESPACES_AS_BYTES)
+
+
+class DCTDecode:
+    @staticmethod
+    def decode(
+        data: bytes,
+        decode_parms: Optional[DictionaryObject] = None,
+        **kwargs: Any,
+    ) -> bytes:
+        # decode_parms is unused here
+        return data
+
+
+class JPXDecode:
+    @staticmethod
+    def decode(
+        data: bytes,
+        decode_parms: Optional[DictionaryObject] = None,
+        **kwargs: Any,
+    ) -> bytes:
+        # decode_parms is unused here
+        return data
+
+
+class CCITParameters:
+    """§7.4.6, optional parameters for the CCITTFaxDecode filter."""
+
+    def __init__(self, K: int = 0, columns: int = 0, rows: int = 0) -> None:
+        self.K = K
+        self.EndOfBlock = None
+        self.EndOfLine = None
+        self.EncodedByteAlign = None
+        self.columns = columns  # width
+        self.rows = rows  # height
+        self.DamagedRowsBeforeError = None
+
+    @property
+    def group(self) -> int:
+        if self.K < 0:
+            CCITTgroup = 4
+        else:
+            # k == 0: Pure one-dimensional encoding (Group 3, 1-D)
+            # k > 0: Mixed one- and two-dimensional encoding (Group 3, 2-D)
+            CCITTgroup = 3
+        return CCITTgroup
+
+
+class CCITTFaxDecode:
+    """
+    §7.4.6, CCITTFaxDecode filter (ISO 32000).
+
+    Either Group 3 or Group 4 CCITT facsimile (fax) encoding.
+    CCITT encoding is bit-oriented, not byte-oriented.
+
+    §7.4.6, optional parameters for the CCITTFaxDecode filter.
+    """
+
+    @staticmethod
+    def _get_parameters(
+        parameters: Union[None, ArrayObject, DictionaryObject, IndirectObject],
+        rows: int,
+    ) -> CCITParameters:
+        # §7.4.6, optional parameters for the CCITTFaxDecode filter
+        k = 0
+        columns = 1728
+        if parameters:
+            parameters_unwrapped = cast(
+                Union[ArrayObject, DictionaryObject], parameters.get_object()
+            )
+            if isinstance(parameters_unwrapped, ArrayObject):
+                for decode_parm in parameters_unwrapped:
+                    if CCITT.COLUMNS in decode_parm:
+                        columns = decode_parm[CCITT.COLUMNS]
+                    if CCITT.K in decode_parm:
+                        k = decode_parm[CCITT.K]
+            else:
+                if CCITT.COLUMNS in parameters_unwrapped:
+                    columns = parameters_unwrapped[CCITT.COLUMNS]  # type: ignore
+                if CCITT.K in parameters_unwrapped:
+                    k = parameters_unwrapped[CCITT.K]  # type: ignore
+
+        return CCITParameters(k, columns, rows)
+
+    @staticmethod
+    def decode(
+        data: bytes,
+        decode_parms: Optional[DictionaryObject] = None,
+        height: int = 0,
+        **kwargs: Any,
+    ) -> bytes:
+        # decode_parms is unused here
+        if "decodeParms" in kwargs:  # deprecated
+            deprecate_with_replacement("decodeParms", "parameters", "4.0.0")
+            decode_parms = kwargs["decodeParms"]
+        if isinstance(decode_parms, ArrayObject):  # deprecated
+            deprecation_no_replacement(
+                "decode_parms being an ArrayObject", removed_in="3.15.5"
+            )
+        params = CCITTFaxDecode._get_parameters(decode_parms, height)
+
+        img_size = len(data)
+        tiff_header_struct = "<2shlh" + "hhll" * 8 + "h"
+        tiff_header = struct.pack(
+            tiff_header_struct,
+            b"II",  # Byte order indication: Little endian
+            42,  # Version number (always 42)
+            8,  # Offset to first IFD
+            8,  # Number of tags in IFD
+            256,
+            4,
+            1,
+            params.columns,  # ImageWidth, LONG, 1, width
+            257,
+            4,
+            1,
+            params.rows,  # ImageLength, LONG, 1, length
+            258,
+            3,
+            1,
+            1,  # BitsPerSample, SHORT, 1, 1
+            259,
+            3,
+            1,
+            params.group,  # Compression, SHORT, 1, 4 = CCITT Group 4 fax encoding
+            262,
+            3,
+            1,
+            0,  # Thresholding, SHORT, 1, 0 = WhiteIsZero
+            273,
+            4,
+            1,
+            struct.calcsize(
+                tiff_header_struct
+            ),  # StripOffsets, LONG, 1, length of header
+            278,
+            4,
+            1,
+            params.rows,  # RowsPerStrip, LONG, 1, length
+            279,
+            4,
+            1,
+            img_size,  # StripByteCounts, LONG, 1, size of image
+            0,  # last IFD
+        )
+
+        return tiff_header + data
+
+
+def decode_stream_data(stream: Any) -> Union[bytes, str]:  # utils.StreamObject
+    """
+    Decode the stream data based on the specified filters.
+
+    This function decodes the stream data using the filters provided in the
+    stream. It supports various filter types, including FlateDecode,
+    ASCIIHexDecode, RunLengthDecode, LZWDecode, ASCII85Decode, DCTDecode, JPXDecode, and
+    CCITTFaxDecode.
+
+    Args:
+        stream: The input stream object containing the data and filters.
+
+    Returns:
+        The decoded stream data.
+
+    Raises:
+        NotImplementedError: If an unsupported filter type is encountered.
+    """
+    filters = stream.get(SA.FILTER, ())
+    if isinstance(filters, IndirectObject):
+        filters = cast(ArrayObject, filters.get_object())
+    if not isinstance(filters, ArrayObject):
+        # we have a single filter instance
+        filters = (filters,)
+    decodparms = stream.get(SA.DECODE_PARMS, ({},) * len(filters))
+    if not isinstance(decodparms, (list, tuple)):
+        decodparms = (decodparms,)
+    data: bytes = b_(stream._data)
+    # If there is not data to decode we should not try to decode the data.
+    if data:
+        for filter_type, params in zip(filters, decodparms):
+            if isinstance(params, NullObject):
+                params = {}
+            if filter_type in (FT.FLATE_DECODE, FTA.FL):
+                data = FlateDecode.decode(data, params)
+            elif filter_type in (FT.ASCII_HEX_DECODE, FTA.AHx):
+                data = ASCIIHexDecode.decode(data)
+            elif filter_type in (FT.RUN_LENGTH_DECODE, FTA.RL):
+                data = RunLengthDecode.decode(data)
+            elif filter_type in (FT.LZW_DECODE, FTA.LZW):
+                data = LZWDecode.decode(data, params)  # type: ignore
+            elif filter_type in (FT.ASCII_85_DECODE, FTA.A85):
+                data = ASCII85Decode.decode(data)
+            elif filter_type == FT.DCT_DECODE:
+                data = DCTDecode.decode(data)
+            elif filter_type == FT.JPX_DECODE:
+                data = JPXDecode.decode(data)
+            elif filter_type == FT.CCITT_FAX_DECODE:
+                height = stream.get(IA.HEIGHT, ())
+                data = CCITTFaxDecode.decode(data, params, height)
+            elif filter_type == "/Crypt":
+                if "/Name" in params or "/Type" in params:
+                    raise NotImplementedError(
+                        "/Crypt filter with /Name or /Type not supported yet"
+                    )
+            else:
+                # Unsupported filter
+                raise NotImplementedError(f"unsupported filter {filter_type}")
+    return data
+
+
+def decodeStreamData(stream: Any) -> Union[str, bytes]:  # deprecated
+    """Deprecated. Use decode_stream_data."""
+    deprecate_with_replacement("decodeStreamData", "decode_stream_data", "4.0.0")
+    return decode_stream_data(stream)
+
+
+def _xobj_to_image(x_object_obj: Dict[str, Any]) -> Tuple[Optional[str], bytes, Any]:
+    """
+    Users need to have the pillow package installed.
+
+    It's unclear if pypdf will keep this function here, hence it's private.
+    It might get removed at any point.
+
+    Args:
+      x_object_obj:
+
+    Returns:
+        Tuple[file extension, bytes, PIL.Image.Image]
+    """
+    from ._xobj_image_helpers import (
+        Image,
+        UnidentifiedImageError,
+        _extended_image_frombytes,
+        _get_imagemode,
+        _handle_flate,
+        _handle_jpx,
+        mode_str_type,
+    )
+
+    # for error reporting
+    if (
+        hasattr(x_object_obj, "indirect_reference") and x_object_obj is None
+    ):  # pragma: no cover
+        obj_as_text = x_object_obj.indirect_reference.__repr__()
+    else:
+        obj_as_text = x_object_obj.__repr__()
+
+    size = (cast(int, x_object_obj[IA.WIDTH]), cast(int, x_object_obj[IA.HEIGHT]))
+    data = x_object_obj.get_data()  # type: ignore
+    if isinstance(data, str):  # pragma: no cover
+        data = data.encode()
+    if len(data) % (size[0] * size[1]) == 1 and data[-1] == 0x0A:  # ie. '\n'
+        data = data[:-1]
+    colors = x_object_obj.get("/Colors", 1)
+    color_space: Any = x_object_obj.get("/ColorSpace", NullObject()).get_object()
+    if isinstance(color_space, list) and len(color_space) == 1:
+        color_space = color_space[0].get_object()
+    if (
+        IA.COLOR_SPACE in x_object_obj
+        and x_object_obj[IA.COLOR_SPACE] == ColorSpaces.DEVICE_RGB
+    ):
+        # https://pillow.readthedocs.io/en/stable/handbook/concepts.html#modes
+        mode: mode_str_type = "RGB"
+    if x_object_obj.get("/BitsPerComponent", 8) < 8:
+        mode, invert_color = _get_imagemode(
+            f"{x_object_obj.get('/BitsPerComponent', 8)}bit", 0, ""
+        )
+    else:
+        mode, invert_color = _get_imagemode(
+            color_space,
+            2
+            if (
+                colors == 1
+                and (
+                    not isinstance(color_space, NullObject)
+                    and "Gray" not in color_space
+                )
+            )
+            else colors,
+            "",
+        )
+    extension = None
+    alpha = None
+    filters = x_object_obj.get(SA.FILTER, NullObject()).get_object()
+    lfilters = filters[-1] if isinstance(filters, list) else filters
+    if lfilters in (FT.FLATE_DECODE, FT.RUN_LENGTH_DECODE):
+        img, image_format, extension, _ = _handle_flate(
+            size,
+            data,
+            mode,
+            color_space,
+            colors,
+            obj_as_text,
+        )
+    elif lfilters in (FT.LZW_DECODE, FT.ASCII_85_DECODE, FT.CCITT_FAX_DECODE):
+        # I'm not sure if the following logic is correct.
+        # There might not be any relationship between the filters and the
+        # extension
+        if lfilters in (FT.LZW_DECODE, FT.CCITT_FAX_DECODE):
+            extension = ".tiff"  # mime_type = "image/tiff"
+            image_format = "TIFF"
+        else:
+            extension = ".png"  # mime_type = "image/png"
+            image_format = "PNG"
+        try:
+            img = Image.open(BytesIO(data), formats=("TIFF", "PNG"))
+        except UnidentifiedImageError:
+            img = _extended_image_frombytes(mode, size, data)
+    elif lfilters == FT.DCT_DECODE:
+        img, image_format, extension = Image.open(BytesIO(data)), "JPEG", ".jpg"
+        # invert_color kept unchanged
+    elif lfilters == FT.JPX_DECODE:
+        img, image_format, extension, invert_color = _handle_jpx(
+            size, data, mode, color_space, colors
+        )
+    elif lfilters == FT.CCITT_FAX_DECODE:
+        img, image_format, extension, invert_color = (
+            Image.open(BytesIO(data), formats=("TIFF",)),
+            "TIFF",
+            ".tiff",
+            False,
+        )
+    elif mode == "CMYK":
+        img, image_format, extension, invert_color = (
+            _extended_image_frombytes(mode, size, data),
+            "TIFF",
+            ".tif",
+            False,
+        )
+    elif mode == "":
+        raise PdfReadError(f"ColorSpace field not found in {x_object_obj}")
+    else:
+        img, image_format, extension, invert_color = (
+            _extended_image_frombytes(mode, size, data),
+            "PNG",
+            ".png",
+            False,
+        )
+    # CMYK image and other colorspaces without decode
+    # requires reverting scale (cf p243,2§ last sentence)
+    decode = x_object_obj.get(
+        IA.DECODE,
+        ([1.0, 0.0] * len(img.getbands()))
+        if (
+            (img.mode == "CMYK" and lfilters in (FT.DCT_DECODE, FT.JPX_DECODE))
+            or (invert_color and img.mode == "L")
+        )
+        else None,
+    )
+    if (
+        isinstance(color_space, ArrayObject)
+        and color_space[0].get_object() == "/Indexed"
+    ):
+        decode = None  # decode is meanless of Indexed
+    if (
+        isinstance(color_space, ArrayObject)
+        and color_space[0].get_object() == "/Separation"
+    ):
+        decode = [1.0, 0.0] * len(img.getbands())
+    if decode is not None and not all(decode[i] == i % 2 for i in range(len(decode))):
+        lut: List[int] = []
+        for i in range(0, len(decode), 2):
+            dmin = decode[i]
+            dmax = decode[i + 1]
+            lut.extend(
+                round(255.0 * (j / 255.0 * (dmax - dmin) + dmin)) for j in range(256)
+            )
+        img = img.point(lut)
+
+    if IA.S_MASK in x_object_obj:  # add alpha channel
+        alpha = _xobj_to_image(x_object_obj[IA.S_MASK])[2]
+        if img.size != alpha.size:
+            logger_warning(f"image and mask size not matching: {obj_as_text}", __name__)
+        else:
+            # TODO : implement mask
+            if alpha.mode != "L":
+                alpha = alpha.convert("L")
+            if img.mode == "P":
+                img = img.convert("RGB")
+            elif img.mode == "1":
+                img = img.convert("L")
+            img.putalpha(alpha)
+        if "JPEG" in image_format:
+            extension = ".jp2"
+            image_format = "JPEG2000"
+        else:
+            extension = ".png"
+            image_format = "PNG"
+
+    img_byte_arr = BytesIO()
+    try:
+        img.save(img_byte_arr, format=image_format)
+    except OSError:  # pragma: no cover  # covered with pillow 10.3
+        # in case of we convert to RGBA and then to PNG
+        img1 = img.convert("RGBA")
+        image_format = "PNG"
+        extension = ".png"
+        img_byte_arr = BytesIO()
+        img1.save(img_byte_arr, format=image_format)
+    data = img_byte_arr.getvalue()
+
+    try:  # temporary try/except until other fixes of images
+        img = Image.open(BytesIO(data))
+    except Exception:
+        img = None  # type: ignore
+    return extension, data, img
diff --git a/.venv/lib/python3.12/site-packages/pypdf/generic/__init__.py b/.venv/lib/python3.12/site-packages/pypdf/generic/__init__.py
new file mode 100644
index 00000000..48045e0a
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/generic/__init__.py
@@ -0,0 +1,464 @@
+# Copyright (c) 2006, Mathieu Fenniak
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# * The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+"""Implementation of generic PDF objects (dictionary, number, string, ...)."""
+__author__ = "Mathieu Fenniak"
+__author_email__ = "biziqe@mathieu.fenniak.net"
+
+from typing import Dict, List, Optional, Tuple, Union
+
+from .._utils import StreamType, deprecate_with_replacement
+from ..constants import OutlineFontFlag
+from ._base import (
+    BooleanObject,
+    ByteStringObject,
+    FloatObject,
+    IndirectObject,
+    NameObject,
+    NullObject,
+    NumberObject,
+    PdfObject,
+    TextStringObject,
+    encode_pdfdocencoding,
+)
+from ._data_structures import (
+    ArrayObject,
+    ContentStream,
+    DecodedStreamObject,
+    Destination,
+    DictionaryObject,
+    EncodedStreamObject,
+    Field,
+    StreamObject,
+    TreeObject,
+    read_object,
+)
+from ._fit import Fit
+from ._outline import OutlineItem
+from ._rectangle import RectangleObject
+from ._utils import (
+    create_string_object,
+    decode_pdfdocencoding,
+    hex_to_rgb,
+    read_hex_string_from_stream,
+    read_string_from_stream,
+)
+from ._viewerpref import ViewerPreferences
+
+
+def readHexStringFromStream(
+    stream: StreamType,
+) -> Union["TextStringObject", "ByteStringObject"]:  # deprecated
+    """Deprecated, use read_hex_string_from_stream."""
+    deprecate_with_replacement(
+        "readHexStringFromStream", "read_hex_string_from_stream", "4.0.0"
+    )
+    return read_hex_string_from_stream(stream)
+
+
+def readStringFromStream(
+    stream: StreamType,
+    forced_encoding: Union[None, str, List[str], Dict[int, str]] = None,
+) -> Union["TextStringObject", "ByteStringObject"]:  # deprecated
+    """Deprecated, use read_string_from_stream."""
+    deprecate_with_replacement(
+        "readStringFromStream", "read_string_from_stream", "4.0.0"
+    )
+    return read_string_from_stream(stream, forced_encoding)
+
+
+def createStringObject(
+    string: Union[str, bytes],
+    forced_encoding: Union[None, str, List[str], Dict[int, str]] = None,
+) -> Union[TextStringObject, ByteStringObject]:  # deprecated
+    """Deprecated, use create_string_object."""
+    deprecate_with_replacement("createStringObject", "create_string_object", "4.0.0")
+    return create_string_object(string, forced_encoding)
+
+
+PAGE_FIT = Fit.fit()
+
+
+class AnnotationBuilder:
+    """
+    The AnnotationBuilder is deprecated.
+
+    Instead, use the annotation classes in pypdf.annotations.
+
+    See `adding PDF annotations <../user/adding-pdf-annotations.html>`_ for
+    its usage combined with PdfWriter.
+    """
+
+    from ..generic._rectangle import RectangleObject
+
+    @staticmethod
+    def text(
+        rect: Union[RectangleObject, Tuple[float, float, float, float]],
+        text: str,
+        open: bool = False,
+        flags: int = 0,
+    ) -> DictionaryObject:
+        """
+        Add text annotation.
+
+        Args:
+            rect: array of four integers ``[xLL, yLL, xUR, yUR]``
+                specifying the clickable rectangular area
+            text: The text that is added to the document
+            open:
+            flags:
+
+        Returns:
+            A dictionary object representing the annotation.
+        """
+        deprecate_with_replacement(
+            "AnnotationBuilder.text", "pypdf.annotations.Text", "4.0.0"
+        )
+        from ..annotations import Text
+
+        return Text(rect=rect, text=text, open=open, flags=flags)
+
+    @staticmethod
+    def free_text(
+        text: str,
+        rect: Union[RectangleObject, Tuple[float, float, float, float]],
+        font: str = "Helvetica",
+        bold: bool = False,
+        italic: bool = False,
+        font_size: str = "14pt",
+        font_color: str = "000000",
+        border_color: Optional[str] = "000000",
+        background_color: Optional[str] = "ffffff",
+    ) -> DictionaryObject:
+        """
+        Add text in a rectangle to a page.
+
+        Args:
+            text: Text to be added
+            rect: array of four integers ``[xLL, yLL, xUR, yUR]``
+                specifying the clickable rectangular area
+            font: Name of the Font, e.g. 'Helvetica'
+            bold: Print the text in bold
+            italic: Print the text in italic
+            font_size: How big the text will be, e.g. '14pt'
+            font_color: Hex-string for the color, e.g. cdcdcd
+            border_color: Hex-string for the border color, e.g. cdcdcd.
+                Use ``None`` for no border.
+            background_color: Hex-string for the background of the annotation,
+                e.g. cdcdcd. Use ``None`` for transparent background.
+
+        Returns:
+            A dictionary object representing the annotation.
+        """
+        deprecate_with_replacement(
+            "AnnotationBuilder.free_text", "pypdf.annotations.FreeText", "4.0.0"
+        )
+        from ..annotations import FreeText
+
+        return FreeText(
+            text=text,
+            rect=rect,
+            font=font,
+            bold=bold,
+            italic=italic,
+            font_size=font_size,
+            font_color=font_color,
+            background_color=background_color,
+            border_color=border_color,
+        )
+
+    @staticmethod
+    def popup(
+        *,
+        rect: Union[RectangleObject, Tuple[float, float, float, float]],
+        flags: int = 0,
+        parent: Optional[DictionaryObject] = None,
+        open: bool = False,
+    ) -> DictionaryObject:
+        """
+        Add a popup to the document.
+
+        Args:
+            rect:
+                Specifies the clickable rectangular area as `[xLL, yLL, xUR, yUR]`
+            flags:
+                1 - invisible, 2 - hidden, 3 - print, 4 - no zoom,
+                5 - no rotate, 6 - no view, 7 - read only, 8 - locked,
+                9 - toggle no view, 10 - locked contents
+            open:
+                Whether the popup should be shown directly (default is False).
+            parent:
+                The contents of the popup. Create this via the AnnotationBuilder.
+
+        Returns:
+            A dictionary object representing the annotation.
+        """
+        deprecate_with_replacement(
+            "AnnotationBuilder.popup", "pypdf.annotations.Popup", "4.0.0"
+        )
+        from ..annotations import Popup
+
+        popup = Popup(rect=rect, open=open, parent=parent)
+        popup.flags = flags  # type: ignore
+
+        return popup
+
+    @staticmethod
+    def line(
+        p1: Tuple[float, float],
+        p2: Tuple[float, float],
+        rect: Union[RectangleObject, Tuple[float, float, float, float]],
+        text: str = "",
+        title_bar: Optional[str] = None,
+    ) -> DictionaryObject:
+        """
+        Draw a line on the PDF.
+
+        Args:
+            p1: First point
+            p2: Second point
+            rect: array of four integers ``[xLL, yLL, xUR, yUR]``
+                specifying the clickable rectangular area
+            text: Text to be displayed as the line annotation
+            title_bar: Text to be displayed in the title bar of the
+                annotation; by convention this is the name of the author
+
+        Returns:
+            A dictionary object representing the annotation.
+        """
+        deprecate_with_replacement(
+            "AnnotationBuilder.line", "pypdf.annotations.Line", "4.0.0"
+        )
+        from ..annotations import Line
+
+        return Line(p1=p1, p2=p2, rect=rect, text=text, title_bar=title_bar)
+
+    @staticmethod
+    def polyline(
+        vertices: List[Tuple[float, float]],
+    ) -> DictionaryObject:
+        """
+        Draw a polyline on the PDF.
+
+        Args:
+            vertices: Array specifying the vertices (x, y) coordinates of the poly-line.
+
+        Returns:
+            A dictionary object representing the annotation.
+        """
+        deprecate_with_replacement(
+            "AnnotationBuilder.polyline", "pypdf.annotations.PolyLine", "4.0.0"
+        )
+        from ..annotations import PolyLine
+
+        return PolyLine(vertices=vertices)
+
+    @staticmethod
+    def rectangle(
+        rect: Union[RectangleObject, Tuple[float, float, float, float]],
+        interiour_color: Optional[str] = None,
+    ) -> DictionaryObject:
+        """
+        Draw a rectangle on the PDF.
+
+        This method uses the /Square annotation type of the PDF format.
+
+        Args:
+            rect: array of four integers ``[xLL, yLL, xUR, yUR]``
+                specifying the clickable rectangular area
+            interiour_color: None or hex-string for the color, e.g. cdcdcd
+                If None is used, the interiour is transparent.
+
+        Returns:
+            A dictionary object representing the annotation.
+        """
+        deprecate_with_replacement(
+            "AnnotationBuilder.rectangle", "pypdf.annotations.Rectangle", "4.0.0"
+        )
+        from ..annotations import Rectangle
+
+        return Rectangle(rect=rect, interiour_color=interiour_color)
+
+    @staticmethod
+    def highlight(
+        *,
+        rect: Union[RectangleObject, Tuple[float, float, float, float]],
+        quad_points: ArrayObject,
+        highlight_color: str = "ff0000",
+        printing: bool = False,
+    ) -> DictionaryObject:
+        """
+        Add a highlight annotation to the document.
+
+        Args:
+            rect: Array of four integers ``[xLL, yLL, xUR, yUR]``
+                specifying the highlighted area
+            quad_points: An ArrayObject of 8 FloatObjects. Must match a word or
+                a group of words, otherwise no highlight will be shown.
+            highlight_color: The color used for the highlight.
+            printing: Whether to print out the highlight annotation when the page
+                is printed.
+
+        Returns:
+            A dictionary object representing the annotation.
+        """
+        deprecate_with_replacement(
+            "AnnotationBuilder.highlight", "pypdf.annotations.Highlight", "4.0.0"
+        )
+        from ..annotations import Highlight
+
+        return Highlight(
+            rect=rect, quad_points=quad_points, highlight_color=highlight_color, printing=printing
+        )
+
+    @staticmethod
+    def ellipse(
+        rect: Union[RectangleObject, Tuple[float, float, float, float]],
+        interiour_color: Optional[str] = None,
+    ) -> DictionaryObject:
+        """
+        Draw an ellipse on the PDF.
+
+        This method uses the /Circle annotation type of the PDF format.
+
+        Args:
+            rect: array of four integers ``[xLL, yLL, xUR, yUR]`` specifying
+                the bounding box of the ellipse
+            interiour_color: None or hex-string for the color, e.g. cdcdcd
+                If None is used, the interiour is transparent.
+
+        Returns:
+            A dictionary object representing the annotation.
+        """
+        deprecate_with_replacement(
+            "AnnotationBuilder.ellipse", "pypdf.annotations.Ellipse", "4.0.0"
+        )
+        from ..annotations import Ellipse
+
+        return Ellipse(rect=rect, interiour_color=interiour_color)
+
+    @staticmethod
+    def polygon(vertices: List[Tuple[float, float]]) -> DictionaryObject:
+        deprecate_with_replacement(
+            "AnnotationBuilder.polygon", "pypdf.annotations.Polygon", "4.0.0"
+        )
+        from ..annotations import Polygon
+
+        return Polygon(vertices=vertices)
+
+    from ._fit import DEFAULT_FIT
+
+    @staticmethod
+    def link(
+        rect: Union[RectangleObject, Tuple[float, float, float, float]],
+        border: Optional[ArrayObject] = None,
+        url: Optional[str] = None,
+        target_page_index: Optional[int] = None,
+        fit: Fit = DEFAULT_FIT,
+    ) -> DictionaryObject:
+        """
+        Add a link to the document.
+
+        The link can either be an external link or an internal link.
+
+        An external link requires the URL parameter.
+        An internal link requires the target_page_index, fit, and fit args.
+
+        Args:
+            rect: array of four integers ``[xLL, yLL, xUR, yUR]``
+                specifying the clickable rectangular area
+            border: if provided, an array describing border-drawing
+                properties. See the PDF spec for details. No border will be
+                drawn if this argument is omitted.
+                - horizontal corner radius,
+                - vertical corner radius, and
+                - border width
+                - Optionally: Dash
+            url: Link to a website (if you want to make an external link)
+            target_page_index: index of the page to which the link should go
+                (if you want to make an internal link)
+            fit: Page fit or 'zoom' option.
+
+        Returns:
+            A dictionary object representing the annotation.
+        """
+        deprecate_with_replacement(
+            "AnnotationBuilder.link", "pypdf.annotations.Link", "4.0.0"
+        )
+        from ..annotations import Link
+
+        return Link(
+            rect=rect,
+            border=border,
+            url=url,
+            target_page_index=target_page_index,
+            fit=fit,
+        )
+
+
+__all__ = [
+    # Base types
+    "BooleanObject",
+    "FloatObject",
+    "NumberObject",
+    "NameObject",
+    "IndirectObject",
+    "NullObject",
+    "PdfObject",
+    "TextStringObject",
+    "ByteStringObject",
+    # Annotations
+    "AnnotationBuilder",
+    # Fit
+    "Fit",
+    "PAGE_FIT",
+    # Data structures
+    "ArrayObject",
+    "DictionaryObject",
+    "TreeObject",
+    "StreamObject",
+    "DecodedStreamObject",
+    "EncodedStreamObject",
+    "ContentStream",
+    "RectangleObject",
+    "Field",
+    "Destination",
+    "ViewerPreferences",
+    # --- More specific stuff
+    # Outline
+    "OutlineItem",
+    "OutlineFontFlag",
+    # Data structures core functions
+    "read_object",
+    # Utility functions
+    "create_string_object",
+    "encode_pdfdocencoding",
+    "decode_pdfdocencoding",
+    "hex_to_rgb",
+    "read_hex_string_from_stream",
+    "read_string_from_stream",
+]
diff --git a/.venv/lib/python3.12/site-packages/pypdf/generic/_base.py b/.venv/lib/python3.12/site-packages/pypdf/generic/_base.py
new file mode 100644
index 00000000..2d606b41
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/generic/_base.py
@@ -0,0 +1,721 @@
+# Copyright (c) 2006, Mathieu Fenniak
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# * The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+import binascii
+import codecs
+import hashlib
+import re
+from binascii import unhexlify
+from math import log10
+from typing import Any, Callable, ClassVar, Dict, Optional, Sequence, Union, cast
+
+from .._codecs import _pdfdoc_encoding_rev
+from .._protocols import PdfObjectProtocol, PdfWriterProtocol
+from .._utils import (
+    StreamType,
+    b_,
+    deprecate_no_replacement,
+    logger_warning,
+    read_non_whitespace,
+    read_until_regex,
+    str_,
+)
+from ..errors import STREAM_TRUNCATED_PREMATURELY, PdfReadError, PdfStreamError
+
+__author__ = "Mathieu Fenniak"
+__author_email__ = "biziqe@mathieu.fenniak.net"
+
+
+class PdfObject(PdfObjectProtocol):
+    # function for calculating a hash value
+    hash_func: Callable[..., "hashlib._Hash"] = hashlib.sha1
+    indirect_reference: Optional["IndirectObject"]
+
+    def hash_value_data(self) -> bytes:
+        return ("%s" % self).encode()
+
+    def hash_value(self) -> bytes:
+        return (
+            "%s:%s"
+            % (
+                self.__class__.__name__,
+                self.hash_func(self.hash_value_data()).hexdigest(),
+            )
+        ).encode()
+
+    def clone(
+        self,
+        pdf_dest: PdfWriterProtocol,
+        force_duplicate: bool = False,
+        ignore_fields: Optional[Sequence[Union[str, int]]] = (),
+    ) -> "PdfObject":
+        """
+        Clone object into pdf_dest (PdfWriterProtocol which is an interface for PdfWriter).
+
+        By default, this method will call ``_reference_clone`` (see ``_reference``).
+
+
+        Args:
+          pdf_dest: Target to clone to.
+          force_duplicate: By default, if the object has already been cloned and referenced,
+            the copy will be returned; when ``True``, a new copy will be created.
+            (Default value = ``False``)
+          ignore_fields: List/tuple of field names (for dictionaries) that will be ignored
+            during cloning (applies to children duplication as well). If fields are to be
+            considered for a limited number of levels, you have to add it as integer, for
+            example ``[1,"/B","/TOTO"]`` means that ``"/B"`` will be ignored at the first
+            level only but ``"/TOTO"`` on all levels.
+
+        Returns:
+          The cloned PdfObject
+        """
+        raise NotImplementedError(
+            f"{self.__class__.__name__} does not implement .clone so far"
+        )
+
+    def _reference_clone(
+        self, clone: Any, pdf_dest: PdfWriterProtocol, force_duplicate: bool = False
+    ) -> PdfObjectProtocol:
+        """
+        Reference the object within the _objects of pdf_dest only if
+        indirect_reference attribute exists (which means the objects was
+        already identified in xref/xobjstm) if object has been already
+        referenced do nothing.
+
+        Args:
+          clone:
+          pdf_dest:
+
+        Returns:
+          The clone
+        """
+        try:
+            if not force_duplicate and clone.indirect_reference.pdf == pdf_dest:
+                return clone
+        except Exception:
+            pass
+        # if hasattr(clone, "indirect_reference"):
+        try:
+            ind = self.indirect_reference
+        except AttributeError:
+            return clone
+        i = len(pdf_dest._objects) + 1
+        if ind is not None:
+            if id(ind.pdf) not in pdf_dest._id_translated:
+                pdf_dest._id_translated[id(ind.pdf)] = {}
+                pdf_dest._id_translated[id(ind.pdf)]["PreventGC"] = ind.pdf  # type: ignore
+            if (
+                not force_duplicate
+                and ind.idnum in pdf_dest._id_translated[id(ind.pdf)]
+            ):
+                obj = pdf_dest.get_object(
+                    pdf_dest._id_translated[id(ind.pdf)][ind.idnum]
+                )
+                assert obj is not None
+                return obj
+            pdf_dest._id_translated[id(ind.pdf)][ind.idnum] = i
+        pdf_dest._objects.append(clone)
+        clone.indirect_reference = IndirectObject(i, 0, pdf_dest)
+        return clone
+
+    def get_object(self) -> Optional["PdfObject"]:
+        """Resolve indirect references."""
+        return self
+
+    def write_to_stream(
+        self, stream: StreamType, encryption_key: Union[None, str, bytes] = None
+    ) -> None:
+        raise NotImplementedError
+
+
+class NullObject(PdfObject):
+    def clone(
+        self,
+        pdf_dest: PdfWriterProtocol,
+        force_duplicate: bool = False,
+        ignore_fields: Optional[Sequence[Union[str, int]]] = (),
+    ) -> "NullObject":
+        """Clone object into pdf_dest."""
+        return cast(
+            "NullObject", self._reference_clone(NullObject(), pdf_dest, force_duplicate)
+        )
+
+    def write_to_stream(
+        self, stream: StreamType, encryption_key: Union[None, str, bytes] = None
+    ) -> None:
+        if encryption_key is not None:  # deprecated
+            deprecate_no_replacement(
+                "the encryption_key parameter of write_to_stream", "5.0.0"
+            )
+        stream.write(b"null")
+
+    @staticmethod
+    def read_from_stream(stream: StreamType) -> "NullObject":
+        nulltxt = stream.read(4)
+        if nulltxt != b"null":
+            raise PdfReadError("Could not read Null object")
+        return NullObject()
+
+    def __repr__(self) -> str:
+        return "NullObject"
+
+
+class BooleanObject(PdfObject):
+    def __init__(self, value: Any) -> None:
+        self.value = value
+
+    def clone(
+        self,
+        pdf_dest: PdfWriterProtocol,
+        force_duplicate: bool = False,
+        ignore_fields: Optional[Sequence[Union[str, int]]] = (),
+    ) -> "BooleanObject":
+        """Clone object into pdf_dest."""
+        return cast(
+            "BooleanObject",
+            self._reference_clone(BooleanObject(self.value), pdf_dest, force_duplicate),
+        )
+
+    def __eq__(self, __o: object) -> bool:
+        if isinstance(__o, BooleanObject):
+            return self.value == __o.value
+        elif isinstance(__o, bool):
+            return self.value == __o
+        else:
+            return False
+
+    def __repr__(self) -> str:
+        return "True" if self.value else "False"
+
+    def write_to_stream(
+        self, stream: StreamType, encryption_key: Union[None, str, bytes] = None
+    ) -> None:
+        if encryption_key is not None:  # deprecated
+            deprecate_no_replacement(
+                "the encryption_key parameter of write_to_stream", "5.0.0"
+            )
+        if self.value:
+            stream.write(b"true")
+        else:
+            stream.write(b"false")
+
+    @staticmethod
+    def read_from_stream(stream: StreamType) -> "BooleanObject":
+        word = stream.read(4)
+        if word == b"true":
+            return BooleanObject(True)
+        elif word == b"fals":
+            stream.read(1)
+            return BooleanObject(False)
+        else:
+            raise PdfReadError("Could not read Boolean object")
+
+
+class IndirectObject(PdfObject):
+    def __init__(self, idnum: int, generation: int, pdf: Any) -> None:  # PdfReader
+        self.idnum = idnum
+        self.generation = generation
+        self.pdf = pdf
+
+    def clone(
+        self,
+        pdf_dest: PdfWriterProtocol,
+        force_duplicate: bool = False,
+        ignore_fields: Optional[Sequence[Union[str, int]]] = (),
+    ) -> "IndirectObject":
+        """Clone object into pdf_dest."""
+        if self.pdf == pdf_dest and not force_duplicate:
+            # Already duplicated and no extra duplication required
+            return self
+        if id(self.pdf) not in pdf_dest._id_translated:
+            pdf_dest._id_translated[id(self.pdf)] = {}
+
+        if self.idnum in pdf_dest._id_translated[id(self.pdf)]:
+            dup = pdf_dest.get_object(pdf_dest._id_translated[id(self.pdf)][self.idnum])
+            if force_duplicate:
+                assert dup is not None
+                assert dup.indirect_reference is not None
+                idref = dup.indirect_reference
+                return IndirectObject(idref.idnum, idref.generation, idref.pdf)
+        else:
+            obj = self.get_object()
+            # case observed : a pointed object can not be found
+            if obj is None:
+                # this normally
+                obj = NullObject()
+                assert isinstance(self, (IndirectObject,))
+                obj.indirect_reference = self
+            dup = pdf_dest._add_object(
+                obj.clone(pdf_dest, force_duplicate, ignore_fields)
+            )
+        # asserts added to prevent errors in mypy
+        assert dup is not None
+        assert dup.indirect_reference is not None
+        return dup.indirect_reference
+
+    @property
+    def indirect_reference(self) -> "IndirectObject":  # type: ignore[override]
+        return self
+
+    def get_object(self) -> Optional["PdfObject"]:
+        return self.pdf.get_object(self)
+
+    def __deepcopy__(self, memo: Any) -> "IndirectObject":
+        return IndirectObject(self.idnum, self.generation, self.pdf)
+
+    def _get_object_with_check(self) -> Optional["PdfObject"]:
+        o = self.get_object()
+        # the check is done here to not slow down get_object()
+        if isinstance(o, IndirectObject):
+            raise PdfStreamError(
+                f"{self.__repr__()} references an IndirectObject {o.__repr__()}"
+            )
+        return o
+
+    def __getattr__(self, name: str) -> Any:
+        # Attribute not found in object: look in pointed object
+        try:
+            return getattr(self._get_object_with_check(), name)
+        except AttributeError:
+            raise AttributeError(
+                f"No attribute {name} found in IndirectObject or pointed object"
+            )
+
+    def __getitem__(self, key: Any) -> Any:
+        # items should be extracted from pointed Object
+        return self._get_object_with_check()[key]  # type: ignore
+
+    def __str__(self) -> str:
+        # in this case we are looking for the pointed data
+        return self.get_object().__str__()
+
+    def __repr__(self) -> str:
+        return f"IndirectObject({self.idnum!r}, {self.generation!r}, {id(self.pdf)})"
+
+    def __eq__(self, other: object) -> bool:
+        return (
+            other is not None
+            and isinstance(other, IndirectObject)
+            and self.idnum == other.idnum
+            and self.generation == other.generation
+            and self.pdf is other.pdf
+        )
+
+    def __ne__(self, other: object) -> bool:
+        return not self.__eq__(other)
+
+    def write_to_stream(
+        self, stream: StreamType, encryption_key: Union[None, str, bytes] = None
+    ) -> None:
+        if encryption_key is not None:  # deprecated
+            deprecate_no_replacement(
+                "the encryption_key parameter of write_to_stream", "5.0.0"
+            )
+        stream.write(f"{self.idnum} {self.generation} R".encode())
+
+    @staticmethod
+    def read_from_stream(stream: StreamType, pdf: Any) -> "IndirectObject":  # PdfReader
+        idnum = b""
+        while True:
+            tok = stream.read(1)
+            if not tok:
+                raise PdfStreamError(STREAM_TRUNCATED_PREMATURELY)
+            if tok.isspace():
+                break
+            idnum += tok
+        generation = b""
+        while True:
+            tok = stream.read(1)
+            if not tok:
+                raise PdfStreamError(STREAM_TRUNCATED_PREMATURELY)
+            if tok.isspace():
+                if not generation:
+                    continue
+                break
+            generation += tok
+        r = read_non_whitespace(stream)
+        if r != b"R":
+            raise PdfReadError(
+                f"Error reading indirect object reference at byte {hex(stream.tell())}"
+            )
+        return IndirectObject(int(idnum), int(generation), pdf)
+
+
+FLOAT_WRITE_PRECISION = 8  # shall be min 5 digits max, allow user adj
+
+
+class FloatObject(float, PdfObject):
+    def __new__(
+        cls, value: Union[str, Any] = "0.0", context: Optional[Any] = None
+    ) -> "FloatObject":
+        try:
+            value = float(str_(value))
+            return float.__new__(cls, value)
+        except Exception as e:
+            # If this isn't a valid decimal (happens in malformed PDFs)
+            # fallback to 0
+            logger_warning(
+                f"{e} : FloatObject ({value}) invalid; use 0.0 instead", __name__
+            )
+            return float.__new__(cls, 0.0)
+
+    def clone(
+        self,
+        pdf_dest: Any,
+        force_duplicate: bool = False,
+        ignore_fields: Optional[Sequence[Union[str, int]]] = (),
+    ) -> "FloatObject":
+        """Clone object into pdf_dest."""
+        return cast(
+            "FloatObject",
+            self._reference_clone(FloatObject(self), pdf_dest, force_duplicate),
+        )
+
+    def myrepr(self) -> str:
+        if self == 0:
+            return "0.0"
+        nb = FLOAT_WRITE_PRECISION - int(log10(abs(self)))
+        s = f"{self:.{max(1,nb)}f}".rstrip("0").rstrip(".")
+        return s
+
+    def __repr__(self) -> str:
+        return self.myrepr()  # repr(float(self))
+
+    def as_numeric(self) -> float:
+        return float(self)
+
+    def write_to_stream(
+        self, stream: StreamType, encryption_key: Union[None, str, bytes] = None
+    ) -> None:
+        if encryption_key is not None:  # deprecated
+            deprecate_no_replacement(
+                "the encryption_key parameter of write_to_stream", "5.0.0"
+            )
+        stream.write(self.myrepr().encode("utf8"))
+
+
+class NumberObject(int, PdfObject):
+    NumberPattern = re.compile(b"[^+-.0-9]")
+
+    def __new__(cls, value: Any) -> "NumberObject":
+        try:
+            return int.__new__(cls, int(value))
+        except ValueError:
+            logger_warning(f"NumberObject({value}) invalid; use 0 instead", __name__)
+            return int.__new__(cls, 0)
+
+    def clone(
+        self,
+        pdf_dest: Any,
+        force_duplicate: bool = False,
+        ignore_fields: Optional[Sequence[Union[str, int]]] = (),
+    ) -> "NumberObject":
+        """Clone object into pdf_dest."""
+        return cast(
+            "NumberObject",
+            self._reference_clone(NumberObject(self), pdf_dest, force_duplicate),
+        )
+
+    def as_numeric(self) -> int:
+        return int(repr(self).encode("utf8"))
+
+    def write_to_stream(
+        self, stream: StreamType, encryption_key: Union[None, str, bytes] = None
+    ) -> None:
+        if encryption_key is not None:  # deprecated
+            deprecate_no_replacement(
+                "the encryption_key parameter of write_to_stream", "5.0.0"
+            )
+        stream.write(repr(self).encode("utf8"))
+
+    @staticmethod
+    def read_from_stream(stream: StreamType) -> Union["NumberObject", "FloatObject"]:
+        num = read_until_regex(stream, NumberObject.NumberPattern)
+        if num.find(b".") != -1:
+            return FloatObject(num)
+        return NumberObject(num)
+
+
+class ByteStringObject(bytes, PdfObject):
+    """
+    Represents a string object where the text encoding could not be determined.
+
+    This occurs quite often, as the PDF spec doesn't provide an alternate way to
+    represent strings -- for example, the encryption data stored in files (like
+    /O) is clearly not text, but is still stored in a "String" object.
+    """
+
+    def clone(
+        self,
+        pdf_dest: Any,
+        force_duplicate: bool = False,
+        ignore_fields: Optional[Sequence[Union[str, int]]] = (),
+    ) -> "ByteStringObject":
+        """Clone object into pdf_dest."""
+        return cast(
+            "ByteStringObject",
+            self._reference_clone(
+                ByteStringObject(bytes(self)), pdf_dest, force_duplicate
+            ),
+        )
+
+    @property
+    def original_bytes(self) -> bytes:
+        """For compatibility with TextStringObject.original_bytes."""
+        return self
+
+    def write_to_stream(
+        self, stream: StreamType, encryption_key: Union[None, str, bytes] = None
+    ) -> None:
+        if encryption_key is not None:  # deprecated
+            deprecate_no_replacement(
+                "the encryption_key parameter of write_to_stream", "5.0.0"
+            )
+        stream.write(b"<")
+        stream.write(binascii.hexlify(self))
+        stream.write(b">")
+
+
+class TextStringObject(str, PdfObject):  # noqa: SLOT000
+    """
+    A string object that has been decoded into a real unicode string.
+
+    If read from a PDF document, this string appeared to match the
+    PDFDocEncoding, or contained a UTF-16BE BOM mark to cause UTF-16 decoding
+    to occur.
+    """
+
+    autodetect_pdfdocencoding: bool
+    autodetect_utf16: bool
+    utf16_bom: bytes
+
+    def __new__(cls, value: Any) -> "TextStringObject":
+        if isinstance(value, bytes):
+            value = value.decode("charmap")
+        o = str.__new__(cls, value)
+        o.autodetect_utf16 = False
+        o.autodetect_pdfdocencoding = False
+        o.utf16_bom = b""
+        if value.startswith(("\xfe\xff", "\xff\xfe")):
+            o.autodetect_utf16 = True
+            o.utf16_bom = value[:2].encode("charmap")
+        else:
+            try:
+                encode_pdfdocencoding(o)
+                o.autodetect_pdfdocencoding = True
+            except UnicodeEncodeError:
+                o.autodetect_utf16 = True
+        return o
+
+    def clone(
+        self,
+        pdf_dest: Any,
+        force_duplicate: bool = False,
+        ignore_fields: Optional[Sequence[Union[str, int]]] = (),
+    ) -> "TextStringObject":
+        """Clone object into pdf_dest."""
+        obj = TextStringObject(self)
+        obj.autodetect_pdfdocencoding = self.autodetect_pdfdocencoding
+        obj.autodetect_utf16 = self.autodetect_utf16
+        obj.utf16_bom = self.utf16_bom
+        return cast(
+            "TextStringObject", self._reference_clone(obj, pdf_dest, force_duplicate)
+        )
+
+    @property
+    def original_bytes(self) -> bytes:
+        """
+        It is occasionally possible that a text string object gets created where
+        a byte string object was expected due to the autodetection mechanism --
+        if that occurs, this "original_bytes" property can be used to
+        back-calculate what the original encoded bytes were.
+        """
+        return self.get_original_bytes()
+
+    def get_original_bytes(self) -> bytes:
+        # We're a text string object, but the library is trying to get our raw
+        # bytes. This can happen if we auto-detected this string as text, but
+        # we were wrong. It's pretty common. Return the original bytes that
+        # would have been used to create this object, based upon the autodetect
+        # method.
+        if self.autodetect_utf16:
+            if self.utf16_bom == codecs.BOM_UTF16_LE:
+                return codecs.BOM_UTF16_LE + self.encode("utf-16le")
+            elif self.utf16_bom == codecs.BOM_UTF16_BE:
+                return codecs.BOM_UTF16_BE + self.encode("utf-16be")
+            else:
+                return self.encode("utf-16be")
+        elif self.autodetect_pdfdocencoding:
+            return encode_pdfdocencoding(self)
+        else:
+            raise Exception("no information about original bytes")  # pragma: no cover
+
+    def get_encoded_bytes(self) -> bytes:
+        # Try to write the string out as a PDFDocEncoding encoded string. It's
+        # nicer to look at in the PDF file. Sadly, we take a performance hit
+        # here for trying...
+        try:
+            if self.autodetect_utf16:
+                raise UnicodeEncodeError("", "forced", -1, -1, "")
+            bytearr = encode_pdfdocencoding(self)
+        except UnicodeEncodeError:
+            if self.utf16_bom == codecs.BOM_UTF16_LE:
+                bytearr = codecs.BOM_UTF16_LE + self.encode("utf-16le")
+            elif self.utf16_bom == codecs.BOM_UTF16_BE:
+                bytearr = codecs.BOM_UTF16_BE + self.encode("utf-16be")
+            else:
+                bytearr = self.encode("utf-16be")
+        return bytearr
+
+    def write_to_stream(
+        self, stream: StreamType, encryption_key: Union[None, str, bytes] = None
+    ) -> None:
+        if encryption_key is not None:  # deprecated
+            deprecate_no_replacement(
+                "the encryption_key parameter of write_to_stream", "5.0.0"
+            )
+        bytearr = self.get_encoded_bytes()
+        stream.write(b"(")
+        for c in bytearr:
+            if not chr(c).isalnum() and c != b" ":
+                # This:
+                #   stream.write(rf"\{c:0>3o}".encode())
+                # gives
+                #   https://github.com/davidhalter/parso/issues/207
+                stream.write(("\\%03o" % c).encode())
+            else:
+                stream.write(b_(chr(c)))
+        stream.write(b")")
+
+
+class NameObject(str, PdfObject):  # noqa: SLOT000
+    delimiter_pattern = re.compile(rb"\s+|[\(\)<>\[\]{}/%]")
+    surfix = b"/"
+    renumber_table: ClassVar[Dict[str, bytes]] = {
+        "#": b"#23",
+        "(": b"#28",
+        ")": b"#29",
+        "/": b"#2F",
+        "%": b"#25",
+        **{chr(i): f"#{i:02X}".encode() for i in range(33)},
+    }
+
+    def clone(
+        self,
+        pdf_dest: Any,
+        force_duplicate: bool = False,
+        ignore_fields: Optional[Sequence[Union[str, int]]] = (),
+    ) -> "NameObject":
+        """Clone object into pdf_dest."""
+        return cast(
+            "NameObject",
+            self._reference_clone(NameObject(self), pdf_dest, force_duplicate),
+        )
+
+    def write_to_stream(
+        self, stream: StreamType, encryption_key: Union[None, str, bytes] = None
+    ) -> None:
+        if encryption_key is not None:  # deprecated
+            deprecate_no_replacement(
+                "the encryption_key parameter of write_to_stream", "5.0.0"
+            )
+        stream.write(self.renumber())
+
+    def renumber(self) -> bytes:
+        out = self[0].encode("utf-8")
+        if out != b"/":
+            deprecate_no_replacement(
+                f"Incorrect first char in NameObject, should start with '/': ({self})",
+                "6.0.0",
+            )
+        for c in self[1:]:
+            if c > "~":
+                for x in c.encode("utf-8"):
+                    out += f"#{x:02X}".encode()
+            else:
+                try:
+                    out += self.renumber_table[c]
+                except KeyError:
+                    out += c.encode("utf-8")
+        return out
+
+    @staticmethod
+    def unnumber(sin: bytes) -> bytes:
+        i = sin.find(b"#", 0)
+        while i >= 0:
+            try:
+                sin = sin[:i] + unhexlify(sin[i + 1 : i + 3]) + sin[i + 3 :]
+                i = sin.find(b"#", i + 1)
+            except ValueError:
+                # if the 2 characters after # can not be converted to hex
+                # we change nothing and carry on
+                i = i + 1
+        return sin
+
+    CHARSETS = ("utf-8", "gbk", "latin1")
+
+    @staticmethod
+    def read_from_stream(stream: StreamType, pdf: Any) -> "NameObject":  # PdfReader
+        name = stream.read(1)
+        if name != NameObject.surfix:
+            raise PdfReadError("name read error")
+        name += read_until_regex(stream, NameObject.delimiter_pattern)
+        try:
+            # Name objects should represent irregular characters
+            # with a '#' followed by the symbol's hex number
+            name = NameObject.unnumber(name)
+            for enc in NameObject.CHARSETS:
+                try:
+                    ret = name.decode(enc)
+                    return NameObject(ret)
+                except Exception:
+                    pass
+            raise UnicodeDecodeError("", name, 0, 0, "Code Not Found")
+        except (UnicodeEncodeError, UnicodeDecodeError) as e:
+            if not pdf.strict:
+                logger_warning(
+                    f"Illegal character in NameObject ({name!r}), "
+                    "you may need to adjust NameObject.CHARSETS",
+                    __name__,
+                )
+                return NameObject(name.decode("charmap"))
+            else:
+                raise PdfReadError(
+                    f"Illegal character in NameObject ({name!r}). "
+                    "You may need to adjust NameObject.CHARSETS.",
+                ) from e
+
+
+def encode_pdfdocencoding(unicode_string: str) -> bytes:
+    retval = bytearray()
+    for c in unicode_string:
+        try:
+            retval += b_(chr(_pdfdoc_encoding_rev[c]))
+        except KeyError:
+            raise UnicodeEncodeError(
+                "pdfdocencoding", c, -1, -1, "does not exist in translation table"
+            )
+    return bytes(retval)
diff --git a/.venv/lib/python3.12/site-packages/pypdf/generic/_data_structures.py b/.venv/lib/python3.12/site-packages/pypdf/generic/_data_structures.py
new file mode 100644
index 00000000..87d68867
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/generic/_data_structures.py
@@ -0,0 +1,1616 @@
+# Copyright (c) 2006, Mathieu Fenniak
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# * The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+
+__author__ = "Mathieu Fenniak"
+__author_email__ = "biziqe@mathieu.fenniak.net"
+
+import logging
+import re
+import sys
+from io import BytesIO
+from math import ceil
+from typing import (
+    Any,
+    Callable,
+    Dict,
+    Iterable,
+    List,
+    Optional,
+    Sequence,
+    Set,
+    Tuple,
+    Union,
+    cast,
+)
+
+from .._protocols import PdfReaderProtocol, PdfWriterProtocol, XmpInformationProtocol
+from .._utils import (
+    WHITESPACES,
+    StreamType,
+    b_,
+    deprecate_no_replacement,
+    deprecate_with_replacement,
+    logger_warning,
+    read_non_whitespace,
+    read_until_regex,
+    skip_over_comment,
+)
+from ..constants import (
+    CheckboxRadioButtonAttributes,
+    FieldDictionaryAttributes,
+    OutlineFontFlag,
+)
+from ..constants import FilterTypes as FT
+from ..constants import StreamAttributes as SA
+from ..constants import TypArguments as TA
+from ..constants import TypFitArguments as TF
+from ..errors import STREAM_TRUNCATED_PREMATURELY, PdfReadError, PdfStreamError
+from ._base import (
+    BooleanObject,
+    ByteStringObject,
+    FloatObject,
+    IndirectObject,
+    NameObject,
+    NullObject,
+    NumberObject,
+    PdfObject,
+    TextStringObject,
+)
+from ._fit import Fit
+from ._image_inline import (
+    extract_inline_A85,
+    extract_inline_AHx,
+    extract_inline_DCT,
+    extract_inline_default,
+    extract_inline_RL,
+)
+from ._utils import read_hex_string_from_stream, read_string_from_stream
+
+if sys.version_info >= (3, 11):
+    from typing import Self
+else:
+    from typing_extensions import Self
+
+logger = logging.getLogger(__name__)
+NumberSigns = b"+-"
+IndirectPattern = re.compile(rb"[+-]?(\d+)\s+(\d+)\s+R[^a-zA-Z]")
+
+
+class ArrayObject(List[Any], PdfObject):
+    def clone(
+        self,
+        pdf_dest: PdfWriterProtocol,
+        force_duplicate: bool = False,
+        ignore_fields: Optional[Sequence[Union[str, int]]] = (),
+    ) -> "ArrayObject":
+        """Clone object into pdf_dest."""
+        try:
+            if self.indirect_reference.pdf == pdf_dest and not force_duplicate:  # type: ignore
+                return self
+        except Exception:
+            pass
+        arr = cast(
+            "ArrayObject",
+            self._reference_clone(ArrayObject(), pdf_dest, force_duplicate),
+        )
+        for data in self:
+            if isinstance(data, StreamObject):
+                dup = data._reference_clone(
+                    data.clone(pdf_dest, force_duplicate, ignore_fields),
+                    pdf_dest,
+                    force_duplicate,
+                )
+                arr.append(dup.indirect_reference)
+            elif hasattr(data, "clone"):
+                arr.append(data.clone(pdf_dest, force_duplicate, ignore_fields))
+            else:
+                arr.append(data)
+        return arr
+
+    def items(self) -> Iterable[Any]:
+        """Emulate DictionaryObject.items for a list (index, object)."""
+        return enumerate(self)
+
+    def _to_lst(self, lst: Any) -> List[Any]:
+        # Convert to list, internal
+        if isinstance(lst, (list, tuple, set)):
+            pass
+        elif isinstance(lst, PdfObject):
+            lst = [lst]
+        elif isinstance(lst, str):
+            if lst[0] == "/":
+                lst = [NameObject(lst)]
+            else:
+                lst = [TextStringObject(lst)]
+        elif isinstance(lst, bytes):
+            lst = [ByteStringObject(lst)]
+        else:  # for numbers,...
+            lst = [lst]
+        return lst
+
+    def __add__(self, lst: Any) -> "ArrayObject":
+        """
+        Allow extension by adding list or add one element only
+
+        Args:
+            lst: any list, tuples are extended the list.
+            other types(numbers,...) will be appended.
+            if str is passed it will be converted into TextStringObject
+            or NameObject (if starting with "/")
+            if bytes is passed it will be converted into ByteStringObject
+
+        Returns:
+            ArrayObject with all elements
+        """
+        temp = ArrayObject(self)
+        temp.extend(self._to_lst(lst))
+        return temp
+
+    def __iadd__(self, lst: Any) -> Self:
+        """
+         Allow extension by adding list or add one element only
+
+        Args:
+            lst: any list, tuples are extended the list.
+            other types(numbers,...) will be appended.
+            if str is passed it will be converted into TextStringObject
+            or NameObject (if starting with "/")
+            if bytes is passed it will be converted into ByteStringObject
+        """
+        self.extend(self._to_lst(lst))
+        return self
+
+    def __isub__(self, lst: Any) -> Self:
+        """Allow to remove items"""
+        for x in self._to_lst(lst):
+            try:
+                x = self.index(x)
+                del self[x]
+            except ValueError:
+                pass
+        return self
+
+    def write_to_stream(
+        self, stream: StreamType, encryption_key: Union[None, str, bytes] = None
+    ) -> None:
+        if encryption_key is not None:  # deprecated
+            deprecate_no_replacement(
+                "the encryption_key parameter of write_to_stream", "5.0.0"
+            )
+        stream.write(b"[")
+        for data in self:
+            stream.write(b" ")
+            data.write_to_stream(stream)
+        stream.write(b" ]")
+
+    @staticmethod
+    def read_from_stream(
+        stream: StreamType,
+        pdf: Optional[PdfReaderProtocol],
+        forced_encoding: Union[None, str, List[str], Dict[int, str]] = None,
+    ) -> "ArrayObject":
+        arr = ArrayObject()
+        tmp = stream.read(1)
+        if tmp != b"[":
+            raise PdfReadError("Could not read array")
+        while True:
+            # skip leading whitespace
+            tok = stream.read(1)
+            while tok.isspace():
+                tok = stream.read(1)
+            stream.seek(-1, 1)
+            # check for array ending
+            peek_ahead = stream.read(1)
+            if peek_ahead == b"]":
+                break
+            stream.seek(-1, 1)
+            # read and append obj
+            arr.append(read_object(stream, pdf, forced_encoding))
+        return arr
+
+
+class DictionaryObject(Dict[Any, Any], PdfObject):
+    def clone(
+        self,
+        pdf_dest: PdfWriterProtocol,
+        force_duplicate: bool = False,
+        ignore_fields: Optional[Sequence[Union[str, int]]] = (),
+    ) -> "DictionaryObject":
+        """Clone object into pdf_dest."""
+        try:
+            if self.indirect_reference.pdf == pdf_dest and not force_duplicate:  # type: ignore
+                return self
+        except Exception:
+            pass
+
+        visited: Set[Tuple[int, int]] = set()  # (idnum, generation)
+        d__ = cast(
+            "DictionaryObject",
+            self._reference_clone(self.__class__(), pdf_dest, force_duplicate),
+        )
+        if ignore_fields is None:
+            ignore_fields = []
+        if len(d__.keys()) == 0:
+            d__._clone(self, pdf_dest, force_duplicate, ignore_fields, visited)
+        return d__
+
+    def _clone(
+        self,
+        src: "DictionaryObject",
+        pdf_dest: PdfWriterProtocol,
+        force_duplicate: bool,
+        ignore_fields: Optional[Sequence[Union[str, int]]],
+        visited: Set[Tuple[int, int]],  # (idnum, generation)
+    ) -> None:
+        """
+        Update the object from src.
+
+        Args:
+            src: "DictionaryObject":
+            pdf_dest:
+            force_duplicate:
+            ignore_fields:
+        """
+        # first we remove for the ignore_fields
+        # that are for a limited number of levels
+        x = 0
+        assert ignore_fields is not None
+        ignore_fields = list(ignore_fields)
+        while x < len(ignore_fields):
+            if isinstance(ignore_fields[x], int):
+                if cast(int, ignore_fields[x]) <= 0:
+                    del ignore_fields[x]
+                    del ignore_fields[x]
+                    continue
+                else:
+                    ignore_fields[x] -= 1  # type:ignore
+            x += 1
+        #  First check if this is a chain list, we need to loop to prevent recur
+        if any(
+            field not in ignore_fields
+            and field in src
+            and isinstance(src.raw_get(field), IndirectObject)
+            and isinstance(src[field], DictionaryObject)
+            and (
+                src.get("/Type", None) is None
+                or cast(DictionaryObject, src[field]).get("/Type", None) is None
+                or src.get("/Type", None)
+                == cast(DictionaryObject, src[field]).get("/Type", None)
+            )
+            for field in ["/Next", "/Prev", "/N", "/V"]
+        ):
+            ignore_fields = list(ignore_fields)
+            for lst in (("/Next", "/Prev"), ("/N", "/V")):
+                for k in lst:
+                    objs = []
+                    if (
+                        k in src
+                        and k not in self
+                        and isinstance(src.raw_get(k), IndirectObject)
+                        and isinstance(src[k], DictionaryObject)
+                        # IF need to go further the idea is to check
+                        # that the types are the same:
+                        and (
+                            src.get("/Type", None) is None
+                            or cast(DictionaryObject, src[k]).get("/Type", None) is None
+                            or src.get("/Type", None)
+                            == cast(DictionaryObject, src[k]).get("/Type", None)
+                        )
+                    ):
+                        cur_obj: Optional[DictionaryObject] = cast(
+                            "DictionaryObject", src[k]
+                        )
+                        prev_obj: Optional[DictionaryObject] = self
+                        while cur_obj is not None:
+                            clon = cast(
+                                "DictionaryObject",
+                                cur_obj._reference_clone(
+                                    cur_obj.__class__(), pdf_dest, force_duplicate
+                                ),
+                            )
+                            # check to see if we've previously processed our item
+                            if clon.indirect_reference is not None:
+                                idnum = clon.indirect_reference.idnum
+                                generation = clon.indirect_reference.generation
+                                if (idnum, generation) in visited:
+                                    cur_obj = None
+                                    break
+                                visited.add((idnum, generation))
+                            objs.append((cur_obj, clon))
+                            assert prev_obj is not None
+                            prev_obj[NameObject(k)] = clon.indirect_reference
+                            prev_obj = clon
+                            try:
+                                if cur_obj == src:
+                                    cur_obj = None
+                                else:
+                                    cur_obj = cast("DictionaryObject", cur_obj[k])
+                            except Exception:
+                                cur_obj = None
+                        for s, c in objs:
+                            c._clone(
+                                s, pdf_dest, force_duplicate, ignore_fields, visited
+                            )
+
+        for k, v in src.items():
+            if k not in ignore_fields:
+                if isinstance(v, StreamObject):
+                    if not hasattr(v, "indirect_reference"):
+                        v.indirect_reference = None
+                    vv = v.clone(pdf_dest, force_duplicate, ignore_fields)
+                    assert vv.indirect_reference is not None
+                    self[k.clone(pdf_dest)] = vv.indirect_reference  # type: ignore[attr-defined]
+                elif k not in self:
+                    self[NameObject(k)] = (
+                        v.clone(pdf_dest, force_duplicate, ignore_fields)
+                        if hasattr(v, "clone")
+                        else v
+                    )
+
+    def raw_get(self, key: Any) -> Any:
+        return dict.__getitem__(self, key)
+
+    def get_inherited(self, key: str, default: Any = None) -> Any:
+        """
+        Returns the value of a key or from the parent if not found.
+        If not found returns default.
+
+        Args:
+            key: string identifying the field to return
+
+            default: default value to return
+
+        Returns:
+            Current key or inherited one, otherwise default value.
+        """
+        if key in self:
+            return self[key]
+        try:
+            if "/Parent" not in self:
+                return default
+            raise KeyError("not present")
+        except KeyError:
+            return cast("DictionaryObject", self["/Parent"].get_object()).get_inherited(
+                key, default
+            )
+
+    def __setitem__(self, key: Any, value: Any) -> Any:
+        if not isinstance(key, PdfObject):
+            raise ValueError("key must be PdfObject")
+        if not isinstance(value, PdfObject):
+            raise ValueError("value must be PdfObject")
+        return dict.__setitem__(self, key, value)
+
+    def setdefault(self, key: Any, value: Optional[Any] = None) -> Any:
+        if not isinstance(key, PdfObject):
+            raise ValueError("key must be PdfObject")
+        if not isinstance(value, PdfObject):
+            raise ValueError("value must be PdfObject")
+        return dict.setdefault(self, key, value)  # type: ignore
+
+    def __getitem__(self, key: Any) -> PdfObject:
+        return dict.__getitem__(self, key).get_object()
+
+    @property
+    def xmp_metadata(self) -> Optional[XmpInformationProtocol]:
+        """
+        Retrieve XMP (Extensible Metadata Platform) data relevant to the this
+        object, if available.
+
+        See Table 347 — Additional entries in a metadata stream dictionary.
+
+        Returns:
+          Returns a :class:`~pypdf.xmp.XmpInformation` instance
+          that can be used to access XMP metadata from the document. Can also
+          return None if no metadata was found on the document root.
+        """
+        from ..xmp import XmpInformation
+
+        metadata = self.get("/Metadata", None)
+        if metadata is None:
+            return None
+        metadata = metadata.get_object()
+
+        if not isinstance(metadata, XmpInformation):
+            metadata = XmpInformation(metadata)
+            self[NameObject("/Metadata")] = metadata
+        return metadata
+
+    def write_to_stream(
+        self, stream: StreamType, encryption_key: Union[None, str, bytes] = None
+    ) -> None:
+        if encryption_key is not None:  # deprecated
+            deprecate_no_replacement(
+                "the encryption_key parameter of write_to_stream", "5.0.0"
+            )
+        stream.write(b"<<\n")
+        for key, value in list(self.items()):
+            if len(key) > 2 and key[1] == "%" and key[-1] == "%":
+                continue
+            key.write_to_stream(stream, encryption_key)
+            stream.write(b" ")
+            value.write_to_stream(stream)
+            stream.write(b"\n")
+        stream.write(b">>")
+
+    @staticmethod
+    def read_from_stream(
+        stream: StreamType,
+        pdf: Optional[PdfReaderProtocol],
+        forced_encoding: Union[None, str, List[str], Dict[int, str]] = None,
+    ) -> "DictionaryObject":
+        def get_next_obj_pos(
+            p: int, p1: int, rem_gens: List[int], pdf: PdfReaderProtocol
+        ) -> int:
+            out = p1
+            for gen in rem_gens:
+                loc = pdf.xref[gen]
+                try:
+                    out = min(out, min([x for x in loc.values() if p < x <= p1]))
+                except ValueError:
+                    pass
+            return out
+
+        def read_unsized_from_stream(
+            stream: StreamType, pdf: PdfReaderProtocol
+        ) -> bytes:
+            # we are just pointing at beginning of the stream
+            eon = get_next_obj_pos(stream.tell(), 2**32, list(pdf.xref), pdf) - 1
+            curr = stream.tell()
+            rw = stream.read(eon - stream.tell())
+            p = rw.find(b"endstream")
+            if p < 0:
+                raise PdfReadError(
+                    f"Unable to find 'endstream' marker for obj starting at {curr}."
+                )
+            stream.seek(curr + p + 9)
+            return rw[: p - 1]
+
+        tmp = stream.read(2)
+        if tmp != b"<<":
+            raise PdfReadError(
+                f"Dictionary read error at byte {hex(stream.tell())}: "
+                "stream must begin with '<<'"
+            )
+        data: Dict[Any, Any] = {}
+        while True:
+            tok = read_non_whitespace(stream)
+            if tok == b"\x00":
+                continue
+            elif tok == b"%":
+                stream.seek(-1, 1)
+                skip_over_comment(stream)
+                continue
+            if not tok:
+                raise PdfStreamError(STREAM_TRUNCATED_PREMATURELY)
+
+            if tok == b">":
+                stream.read(1)
+                break
+            stream.seek(-1, 1)
+            try:
+                key = read_object(stream, pdf)
+                tok = read_non_whitespace(stream)
+                stream.seek(-1, 1)
+                value = read_object(stream, pdf, forced_encoding)
+            except Exception as exc:
+                if pdf is not None and pdf.strict:
+                    raise PdfReadError(exc.__repr__())
+                logger_warning(exc.__repr__(), __name__)
+                retval = DictionaryObject()
+                retval.update(data)
+                return retval  # return partial data
+
+            if not data.get(key):
+                data[key] = value
+            else:
+                # multiple definitions of key not permitted
+                msg = (
+                    f"Multiple definitions in dictionary at byte "
+                    f"{hex(stream.tell())} for key {key}"
+                )
+                if pdf is not None and pdf.strict:
+                    raise PdfReadError(msg)
+                logger_warning(msg, __name__)
+
+        pos = stream.tell()
+        s = read_non_whitespace(stream)
+        if s == b"s" and stream.read(5) == b"tream":
+            eol = stream.read(1)
+            # odd PDF file output has spaces after 'stream' keyword but before EOL.
+            # patch provided by Danial Sandler
+            while eol == b" ":
+                eol = stream.read(1)
+            if eol not in (b"\n", b"\r"):
+                raise PdfStreamError("Stream data must be followed by a newline")
+            if eol == b"\r" and stream.read(1) != b"\n":
+                stream.seek(-1, 1)
+            # this is a stream object, not a dictionary
+            if SA.LENGTH not in data:
+                if pdf is not None and pdf.strict:
+                    raise PdfStreamError("Stream length not defined")
+                else:
+                    logger_warning(
+                        f"Stream length not defined @pos={stream.tell()}", __name__
+                    )
+                data[NameObject(SA.LENGTH)] = NumberObject(-1)
+            length = data[SA.LENGTH]
+            if isinstance(length, IndirectObject):
+                t = stream.tell()
+                assert pdf is not None  # hint for mypy
+                length = pdf.get_object(length)
+                stream.seek(t, 0)
+            if length is None:  # if the PDF is damaged
+                length = -1
+            pstart = stream.tell()
+            if length > 0:
+                data["__streamdata__"] = stream.read(length)
+            else:
+                data["__streamdata__"] = read_until_regex(
+                    stream, re.compile(b"endstream")
+                )
+            e = read_non_whitespace(stream)
+            ndstream = stream.read(8)
+            if (e + ndstream) != b"endstream":
+                # (sigh) - the odd PDF file has a length that is too long, so
+                # we need to read backwards to find the "endstream" ending.
+                # ReportLab (unknown version) generates files with this bug,
+                # and Python users into PDF files tend to be our audience.
+                # we need to do this to correct the streamdata and chop off
+                # an extra character.
+                pos = stream.tell()
+                stream.seek(-10, 1)
+                end = stream.read(9)
+                if end == b"endstream":
+                    # we found it by looking back one character further.
+                    data["__streamdata__"] = data["__streamdata__"][:-1]
+                elif pdf is not None and not pdf.strict:
+                    stream.seek(pstart, 0)
+                    data["__streamdata__"] = read_unsized_from_stream(stream, pdf)
+                    pos = stream.tell()
+                else:
+                    stream.seek(pos, 0)
+                    raise PdfReadError(
+                        "Unable to find 'endstream' marker after stream at byte "
+                        f"{hex(stream.tell())} (nd='{ndstream!r}', end='{end!r}')."
+                    )
+        else:
+            stream.seek(pos, 0)
+        if "__streamdata__" in data:
+            return StreamObject.initialize_from_dictionary(data)
+        else:
+            retval = DictionaryObject()
+            retval.update(data)
+            return retval
+
+
+class TreeObject(DictionaryObject):
+    def __init__(self, dct: Optional[DictionaryObject] = None) -> None:
+        DictionaryObject.__init__(self)
+        if dct:
+            self.update(dct)
+
+    def hasChildren(self) -> bool:  # deprecated
+        deprecate_with_replacement("hasChildren", "has_children", "4.0.0")
+        return self.has_children()
+
+    def has_children(self) -> bool:
+        return "/First" in self
+
+    def __iter__(self) -> Any:
+        return self.children()
+
+    def children(self) -> Iterable[Any]:
+        if not self.has_children():
+            return
+
+        child_ref = self[NameObject("/First")]
+        child = child_ref.get_object()
+        while True:
+            yield child
+            if child == self[NameObject("/Last")]:
+                return
+            child_ref = child.get(NameObject("/Next"))  # type: ignore
+            if child_ref is None:
+                return
+            child = child_ref.get_object()
+
+    def add_child(self, child: Any, pdf: PdfWriterProtocol) -> None:
+        self.insert_child(child, None, pdf)
+
+    def inc_parent_counter_default(
+        self, parent: Union[None, IndirectObject, "TreeObject"], n: int
+    ) -> None:
+        if parent is None:
+            return
+        parent = cast("TreeObject", parent.get_object())
+        if "/Count" in parent:
+            parent[NameObject("/Count")] = NumberObject(
+                max(0, cast(int, parent[NameObject("/Count")]) + n)
+            )
+            self.inc_parent_counter_default(parent.get("/Parent", None), n)
+
+    def inc_parent_counter_outline(
+        self, parent: Union[None, IndirectObject, "TreeObject"], n: int
+    ) -> None:
+        if parent is None:
+            return
+        parent = cast("TreeObject", parent.get_object())
+        #  BooleanObject requires comparison with == not is
+        opn = parent.get("/%is_open%", True) == True  # noqa
+        c = cast(int, parent.get("/Count", 0))
+        if c < 0:
+            c = abs(c)
+        parent[NameObject("/Count")] = NumberObject((c + n) * (1 if opn else -1))
+        if not opn:
+            return
+        self.inc_parent_counter_outline(parent.get("/Parent", None), n)
+
+    def insert_child(
+        self,
+        child: Any,
+        before: Any,
+        pdf: PdfWriterProtocol,
+        inc_parent_counter: Optional[Callable[..., Any]] = None,
+    ) -> IndirectObject:
+        if inc_parent_counter is None:
+            inc_parent_counter = self.inc_parent_counter_default
+        child_obj = child.get_object()
+        child = child.indirect_reference  # get_reference(child_obj)
+
+        prev: Optional[DictionaryObject]
+        if "/First" not in self:  # no child yet
+            self[NameObject("/First")] = child
+            self[NameObject("/Count")] = NumberObject(0)
+            self[NameObject("/Last")] = child
+            child_obj[NameObject("/Parent")] = self.indirect_reference
+            inc_parent_counter(self, child_obj.get("/Count", 1))
+            if "/Next" in child_obj:
+                del child_obj["/Next"]
+            if "/Prev" in child_obj:
+                del child_obj["/Prev"]
+            return child
+        else:
+            prev = cast("DictionaryObject", self["/Last"])
+
+        while prev.indirect_reference != before:
+            if "/Next" in prev:
+                prev = cast("TreeObject", prev["/Next"])
+            else:  # append at the end
+                prev[NameObject("/Next")] = cast("TreeObject", child)
+                child_obj[NameObject("/Prev")] = prev.indirect_reference
+                child_obj[NameObject("/Parent")] = self.indirect_reference
+                if "/Next" in child_obj:
+                    del child_obj["/Next"]
+                self[NameObject("/Last")] = child
+                inc_parent_counter(self, child_obj.get("/Count", 1))
+                return child
+        try:  # insert as first or in the middle
+            assert isinstance(prev["/Prev"], DictionaryObject)
+            prev["/Prev"][NameObject("/Next")] = child
+            child_obj[NameObject("/Prev")] = prev["/Prev"]
+        except Exception:  # it means we are inserting in first position
+            del child_obj["/Next"]
+        child_obj[NameObject("/Next")] = prev
+        prev[NameObject("/Prev")] = child
+        child_obj[NameObject("/Parent")] = self.indirect_reference
+        inc_parent_counter(self, child_obj.get("/Count", 1))
+        return child
+
+    def _remove_node_from_tree(
+        self, prev: Any, prev_ref: Any, cur: Any, last: Any
+    ) -> None:
+        """
+        Adjust the pointers of the linked list and tree node count.
+
+        Args:
+            prev:
+            prev_ref:
+            cur:
+            last:
+        """
+        next_ref = cur.get(NameObject("/Next"), None)
+        if prev is None:
+            if next_ref:
+                # Removing first tree node
+                next_obj = next_ref.get_object()
+                del next_obj[NameObject("/Prev")]
+                self[NameObject("/First")] = next_ref
+                self[NameObject("/Count")] = NumberObject(
+                    self[NameObject("/Count")] - 1  # type: ignore
+                )
+
+            else:
+                # Removing only tree node
+                self[NameObject("/Count")] = NumberObject(0)
+                del self[NameObject("/First")]
+                if NameObject("/Last") in self:
+                    del self[NameObject("/Last")]
+        else:
+            if next_ref:
+                # Removing middle tree node
+                next_obj = next_ref.get_object()
+                next_obj[NameObject("/Prev")] = prev_ref
+                prev[NameObject("/Next")] = next_ref
+            else:
+                # Removing last tree node
+                assert cur == last
+                del prev[NameObject("/Next")]
+                self[NameObject("/Last")] = prev_ref
+            self[NameObject("/Count")] = NumberObject(self[NameObject("/Count")] - 1)  # type: ignore
+
+    def remove_child(self, child: Any) -> None:
+        child_obj = child.get_object()
+        child = child_obj.indirect_reference
+
+        if NameObject("/Parent") not in child_obj:
+            raise ValueError("Removed child does not appear to be a tree item")
+        elif child_obj[NameObject("/Parent")] != self:
+            raise ValueError("Removed child is not a member of this tree")
+
+        found = False
+        prev_ref = None
+        prev = None
+        cur_ref: Optional[Any] = self[NameObject("/First")]
+        cur: Optional[Dict[str, Any]] = cur_ref.get_object()  # type: ignore
+        last_ref = self[NameObject("/Last")]
+        last = last_ref.get_object()
+        while cur is not None:
+            if cur == child_obj:
+                self._remove_node_from_tree(prev, prev_ref, cur, last)
+                found = True
+                break
+
+            # Go to the next node
+            prev_ref = cur_ref
+            prev = cur
+            if NameObject("/Next") in cur:
+                cur_ref = cur[NameObject("/Next")]
+                cur = cur_ref.get_object()
+            else:
+                cur_ref = None
+                cur = None
+
+        if not found:
+            raise ValueError("Removal couldn't find item in tree")
+
+        _reset_node_tree_relationship(child_obj)
+
+    def remove_from_tree(self) -> None:
+        """Remove the object from the tree it is in."""
+        if NameObject("/Parent") not in self:
+            raise ValueError("Removed child does not appear to be a tree item")
+        else:
+            cast("TreeObject", self["/Parent"]).remove_child(self)
+
+    def emptyTree(self) -> None:  # deprecated
+        deprecate_with_replacement("emptyTree", "empty_tree", "4.0.0")
+        self.empty_tree()
+
+    def empty_tree(self) -> None:
+        for child in self:
+            child_obj = child.get_object()
+            _reset_node_tree_relationship(child_obj)
+
+        if NameObject("/Count") in self:
+            del self[NameObject("/Count")]
+        if NameObject("/First") in self:
+            del self[NameObject("/First")]
+        if NameObject("/Last") in self:
+            del self[NameObject("/Last")]
+
+
+def _reset_node_tree_relationship(child_obj: Any) -> None:
+    """
+    Call this after a node has been removed from a tree.
+
+    This resets the nodes attributes in respect to that tree.
+
+    Args:
+        child_obj:
+    """
+    del child_obj[NameObject("/Parent")]
+    if NameObject("/Next") in child_obj:
+        del child_obj[NameObject("/Next")]
+    if NameObject("/Prev") in child_obj:
+        del child_obj[NameObject("/Prev")]
+
+
+class StreamObject(DictionaryObject):
+    def __init__(self) -> None:
+        self._data: Union[bytes, str] = b""
+        self.decoded_self: Optional[DecodedStreamObject] = None
+
+    def _clone(
+        self,
+        src: DictionaryObject,
+        pdf_dest: PdfWriterProtocol,
+        force_duplicate: bool,
+        ignore_fields: Optional[Sequence[Union[str, int]]],
+        visited: Set[Tuple[int, int]],
+    ) -> None:
+        """
+        Update the object from src.
+
+        Args:
+            src:
+            pdf_dest:
+            force_duplicate:
+            ignore_fields:
+        """
+        self._data = cast("StreamObject", src)._data
+        try:
+            decoded_self = cast("StreamObject", src).decoded_self
+            if decoded_self is None:
+                self.decoded_self = None
+            else:
+                self.decoded_self = cast(
+                    "DecodedStreamObject",
+                    decoded_self.clone(pdf_dest, force_duplicate, ignore_fields),
+                )
+        except Exception:
+            pass
+        super()._clone(src, pdf_dest, force_duplicate, ignore_fields, visited)
+
+    def get_data(self) -> Union[bytes, str]:
+        return self._data
+
+    def set_data(self, data: bytes) -> None:
+        self._data = data
+
+    def hash_value_data(self) -> bytes:
+        data = super().hash_value_data()
+        data += b_(self._data)
+        return data
+
+    def write_to_stream(
+        self, stream: StreamType, encryption_key: Union[None, str, bytes] = None
+    ) -> None:
+        if encryption_key is not None:  # deprecated
+            deprecate_no_replacement(
+                "the encryption_key parameter of write_to_stream", "5.0.0"
+            )
+        self[NameObject(SA.LENGTH)] = NumberObject(len(self._data))
+        DictionaryObject.write_to_stream(self, stream)
+        del self[SA.LENGTH]
+        stream.write(b"\nstream\n")
+        stream.write(self._data)
+        stream.write(b"\nendstream")
+
+    @staticmethod
+    def initializeFromDictionary(
+        data: Dict[str, Any]
+    ) -> Union["EncodedStreamObject", "DecodedStreamObject"]:
+        deprecate_with_replacement(
+            "initializeFromDictionary", "initialize_from_dictionary", "5.0.0"
+        )  # pragma: no cover
+        return StreamObject.initialize_from_dictionary(data)  # pragma: no cover
+
+    @staticmethod
+    def initialize_from_dictionary(
+        data: Dict[str, Any]
+    ) -> Union["EncodedStreamObject", "DecodedStreamObject"]:
+        retval: Union[EncodedStreamObject, DecodedStreamObject]
+        if SA.FILTER in data:
+            retval = EncodedStreamObject()
+        else:
+            retval = DecodedStreamObject()
+        retval._data = data["__streamdata__"]
+        del data["__streamdata__"]
+        del data[SA.LENGTH]
+        retval.update(data)
+        return retval
+
+    def flate_encode(self, level: int = -1) -> "EncodedStreamObject":
+        from ..filters import FlateDecode
+
+        if SA.FILTER in self:
+            f = self[SA.FILTER]
+            if isinstance(f, ArrayObject):
+                f = ArrayObject([NameObject(FT.FLATE_DECODE), *f])
+                try:
+                    params = ArrayObject(
+                        [NullObject(), *self.get(SA.DECODE_PARMS, ArrayObject())]
+                    )
+                except TypeError:
+                    # case of error where the * operator is not working (not an array
+                    params = ArrayObject(
+                        [NullObject(), self.get(SA.DECODE_PARMS, ArrayObject())]
+                    )
+            else:
+                f = ArrayObject([NameObject(FT.FLATE_DECODE), f])
+                params = ArrayObject(
+                    [NullObject(), self.get(SA.DECODE_PARMS, NullObject())]
+                )
+        else:
+            f = NameObject(FT.FLATE_DECODE)
+            params = None
+        retval = EncodedStreamObject()
+        retval.update(self)
+        retval[NameObject(SA.FILTER)] = f
+        if params is not None:
+            retval[NameObject(SA.DECODE_PARMS)] = params
+        retval._data = FlateDecode.encode(b_(self._data), level)
+        return retval
+
+    def decode_as_image(self) -> Any:
+        """
+        Try to decode the stream object as an image
+
+        Returns:
+            a PIL image if proper decoding has been found
+        Raises:
+            Exception: (any)during decoding to to invalid object or
+                errors during decoding will be reported
+                It is recommended to catch exceptions to prevent
+                stops in your program.
+        """
+        from ..filters import _xobj_to_image
+
+        if self.get("/Subtype", "") != "/Image":
+            try:
+                msg = f"{self.indirect_reference} does not seem to be an Image"  # pragma: no cover
+            except AttributeError:
+                msg = f"{self.__repr__()} object does not seem to be an Image"  # pragma: no cover
+            logger_warning(msg, __name__)
+        extension, byte_stream, img = _xobj_to_image(self)
+        if extension is None:
+            return None  # pragma: no cover
+        return img
+
+
+class DecodedStreamObject(StreamObject):
+    pass
+
+
+class EncodedStreamObject(StreamObject):
+    def __init__(self) -> None:
+        self.decoded_self: Optional[DecodedStreamObject] = None
+
+    # This overrides the parent method:
+    def get_data(self) -> Union[bytes, str]:
+        from ..filters import decode_stream_data
+
+        if self.decoded_self is not None:
+            # cached version of decoded object
+            return self.decoded_self.get_data()
+        else:
+            # create decoded object
+            decoded = DecodedStreamObject()
+
+            decoded.set_data(b_(decode_stream_data(self)))
+            for key, value in list(self.items()):
+                if key not in (SA.LENGTH, SA.FILTER, SA.DECODE_PARMS):
+                    decoded[key] = value
+            self.decoded_self = decoded
+            return decoded.get_data()
+
+    # This overrides the parent method:
+    def set_data(self, data: bytes) -> None:  # deprecated
+        from ..filters import FlateDecode
+
+        if self.get(SA.FILTER, "") == FT.FLATE_DECODE:
+            if not isinstance(data, bytes):
+                raise TypeError("data must be bytes")
+            assert self.decoded_self is not None
+            self.decoded_self.set_data(data)
+            super().set_data(FlateDecode.encode(data))
+        else:
+            raise PdfReadError(
+                "Streams encoded with different filter from only FlateDecode is not supported"
+            )
+
+
+class ContentStream(DecodedStreamObject):
+    """
+    In order to be fast, this data structure can contain either:
+
+    * raw data in ._data
+    * parsed stream operations in ._operations.
+
+    At any time, ContentStream object can either have both of those fields defined,
+    or one field defined and the other set to None.
+
+    These fields are "rebuilt" lazily, when accessed:
+
+    * when .get_data() is called, if ._data is None, it is rebuilt from ._operations.
+    * when .operations is called, if ._operations is None, it is rebuilt from ._data.
+
+    Conversely, these fields can be invalidated:
+
+    * when .set_data() is called, ._operations is set to None.
+    * when .operations is set, ._data is set to None.
+    """
+
+    def __init__(
+        self,
+        stream: Any,
+        pdf: Any,
+        forced_encoding: Union[None, str, List[str], Dict[int, str]] = None,
+    ) -> None:
+        self.pdf = pdf
+
+        # The inner list has two elements:
+        #  Element 0: List
+        #  Element 1: str
+        self._operations: List[Tuple[Any, Any]] = []
+
+        # stream may be a StreamObject or an ArrayObject containing
+        # multiple StreamObjects to be cat'd together.
+        if stream is None:
+            super().set_data(b"")
+        else:
+            stream = stream.get_object()
+            if isinstance(stream, ArrayObject):
+                data = b""
+                for s in stream:
+                    data += b_(s.get_object().get_data())
+                    if len(data) == 0 or data[-1] != b"\n":
+                        data += b"\n"
+                super().set_data(bytes(data))
+            else:
+                stream_data = stream.get_data()
+                assert stream_data is not None
+                super().set_data(b_(stream_data))
+            self.forced_encoding = forced_encoding
+
+    def clone(
+        self,
+        pdf_dest: Any,
+        force_duplicate: bool = False,
+        ignore_fields: Optional[Sequence[Union[str, int]]] = (),
+    ) -> "ContentStream":
+        """
+        Clone object into pdf_dest.
+
+        Args:
+            pdf_dest:
+            force_duplicate:
+            ignore_fields:
+
+        Returns:
+            The cloned ContentStream
+        """
+        try:
+            if self.indirect_reference.pdf == pdf_dest and not force_duplicate:  # type: ignore
+                return self
+        except Exception:
+            pass
+
+        visited: Set[Tuple[int, int]] = set()
+        d__ = cast(
+            "ContentStream",
+            self._reference_clone(
+                self.__class__(None, None), pdf_dest, force_duplicate
+            ),
+        )
+        if ignore_fields is None:
+            ignore_fields = []
+        d__._clone(self, pdf_dest, force_duplicate, ignore_fields, visited)
+        return d__
+
+    def _clone(
+        self,
+        src: DictionaryObject,
+        pdf_dest: PdfWriterProtocol,
+        force_duplicate: bool,
+        ignore_fields: Optional[Sequence[Union[str, int]]],
+        visited: Set[Tuple[int, int]],
+    ) -> None:
+        """
+        Update the object from src.
+
+        Args:
+            src:
+            pdf_dest:
+            force_duplicate:
+            ignore_fields:
+        """
+        src_cs = cast("ContentStream", src)
+        super().set_data(b_(src_cs._data))
+        self.pdf = pdf_dest
+        self._operations = list(src_cs._operations)
+        self.forced_encoding = src_cs.forced_encoding
+        # no need to call DictionaryObjection or anything
+        # like super(DictionaryObject,self)._clone(src, pdf_dest, force_duplicate, ignore_fields, visited)
+
+    def _parse_content_stream(self, stream: StreamType) -> None:
+        # 7.8.2 Content Streams
+        stream.seek(0, 0)
+        operands: List[Union[int, str, PdfObject]] = []
+        while True:
+            peek = read_non_whitespace(stream)
+            if peek == b"" or peek == 0:
+                break
+            stream.seek(-1, 1)
+            if peek.isalpha() or peek in (b"'", b'"'):
+                operator = read_until_regex(stream, NameObject.delimiter_pattern)
+                if operator == b"BI":
+                    # begin inline image - a completely different parsing
+                    # mechanism is required, of course... thanks buddy...
+                    assert operands == []
+                    ii = self._read_inline_image(stream)
+                    self._operations.append((ii, b"INLINE IMAGE"))
+                else:
+                    self._operations.append((operands, operator))
+                    operands = []
+            elif peek == b"%":
+                # If we encounter a comment in the content stream, we have to
+                # handle it here. Typically, read_object will handle
+                # encountering a comment -- but read_object assumes that
+                # following the comment must be the object we're trying to
+                # read. In this case, it could be an operator instead.
+                while peek not in (b"\r", b"\n", b""):
+                    peek = stream.read(1)
+            else:
+                operands.append(read_object(stream, None, self.forced_encoding))
+
+    def _read_inline_image(self, stream: StreamType) -> Dict[str, Any]:
+        # begin reading just after the "BI" - begin image
+        # first read the dictionary of settings.
+        settings = DictionaryObject()
+        while True:
+            tok = read_non_whitespace(stream)
+            stream.seek(-1, 1)
+            if tok == b"I":
+                # "ID" - begin of image data
+                break
+            key = read_object(stream, self.pdf)
+            tok = read_non_whitespace(stream)
+            stream.seek(-1, 1)
+            value = read_object(stream, self.pdf)
+            settings[key] = value
+        # left at beginning of ID
+        tmp = stream.read(3)
+        assert tmp[:2] == b"ID"
+        filtr = settings.get("/F", settings.get("/Filter", "not set"))
+        savpos = stream.tell()
+        if isinstance(filtr, list):
+            filtr = filtr[0]  # used forencoding
+        if "AHx" in filtr or "ASCIIHexDecode" in filtr:
+            data = extract_inline_AHx(stream)
+        elif "A85" in filtr or "ASCII85Decode" in filtr:
+            data = extract_inline_A85(stream)
+        elif "RL" in filtr or "RunLengthDecode" in filtr:
+            data = extract_inline_RL(stream)
+        elif "DCT" in filtr or "DCTDecode" in filtr:
+            data = extract_inline_DCT(stream)
+        elif filtr == "not set":
+            cs = settings.get("/CS", "")
+            if "RGB" in cs:
+                lcs = 3
+            elif "CMYK" in cs:
+                lcs = 4
+            else:
+                bits = settings.get(
+                    "/BPC",
+                    8 if cs in {"/I", "/G", "/Indexed", "/DeviceGray"} else -1,
+                )
+                if bits > 0:
+                    lcs = bits / 8.0
+                else:
+                    data = extract_inline_default(stream)
+                    lcs = -1
+            if lcs > 0:
+                data = stream.read(
+                    ceil(cast(int, settings["/W"]) * lcs) * cast(int, settings["/H"])
+                )
+            ei = read_non_whitespace(stream)
+            stream.seek(-1, 1)
+        else:
+            data = extract_inline_default(stream)
+
+        ei = stream.read(3)
+        stream.seek(-1, 1)
+        if ei[0:2] != b"EI" or ei[2:3] not in WHITESPACES:
+            stream.seek(savpos, 0)
+            data = extract_inline_default(stream)
+        return {"settings": settings, "data": data}
+
+    # This overrides the parent method:
+    def get_data(self) -> bytes:
+        if not self._data:
+            new_data = BytesIO()
+            for operands, operator in self._operations:
+                if operator == b"INLINE IMAGE":
+                    new_data.write(b"BI")
+                    dict_text = BytesIO()
+                    operands["settings"].write_to_stream(dict_text)
+                    new_data.write(dict_text.getvalue()[2:-2])
+                    new_data.write(b"ID ")
+                    new_data.write(operands["data"])
+                    new_data.write(b"EI")
+                else:
+                    for op in operands:
+                        op.write_to_stream(new_data)
+                        new_data.write(b" ")
+                    new_data.write(b_(operator))
+                new_data.write(b"\n")
+            self._data = new_data.getvalue()
+        return b_(self._data)
+
+    # This overrides the parent method:
+    def set_data(self, data: bytes) -> None:
+        super().set_data(data)
+        self._operations = []
+
+    @property
+    def operations(self) -> List[Tuple[Any, Any]]:
+        if not self._operations and self._data:
+            self._parse_content_stream(BytesIO(b_(self._data)))
+            self._data = b""
+        return self._operations
+
+    @operations.setter
+    def operations(self, operations: List[Tuple[Any, Any]]) -> None:
+        self._operations = operations
+        self._data = b""
+
+    def isolate_graphics_state(self) -> None:
+        if self._operations:
+            self._operations.insert(0, ([], "q"))
+            self._operations.append(([], "Q"))
+        elif self._data:
+            self._data = b"q\n" + b_(self._data) + b"\nQ\n"
+
+    # This overrides the parent method:
+    def write_to_stream(
+        self, stream: StreamType, encryption_key: Union[None, str, bytes] = None
+    ) -> None:
+        if not self._data and self._operations:
+            self.get_data()  # this ensures ._data is rebuilt
+        super().write_to_stream(stream, encryption_key)
+
+
+def read_object(
+    stream: StreamType,
+    pdf: Optional[PdfReaderProtocol],
+    forced_encoding: Union[None, str, List[str], Dict[int, str]] = None,
+) -> Union[PdfObject, int, str, ContentStream]:
+    tok = stream.read(1)
+    stream.seek(-1, 1)  # reset to start
+    if tok == b"/":
+        return NameObject.read_from_stream(stream, pdf)
+    elif tok == b"<":
+        # hexadecimal string OR dictionary
+        peek = stream.read(2)
+        stream.seek(-2, 1)  # reset to start
+        if peek == b"<<":
+            return DictionaryObject.read_from_stream(stream, pdf, forced_encoding)
+        else:
+            return read_hex_string_from_stream(stream, forced_encoding)
+    elif tok == b"[":
+        return ArrayObject.read_from_stream(stream, pdf, forced_encoding)
+    elif tok == b"t" or tok == b"f":
+        return BooleanObject.read_from_stream(stream)
+    elif tok == b"(":
+        return read_string_from_stream(stream, forced_encoding)
+    elif tok == b"e" and stream.read(6) == b"endobj":
+        stream.seek(-6, 1)
+        return NullObject()
+    elif tok == b"n":
+        return NullObject.read_from_stream(stream)
+    elif tok == b"%":
+        # comment
+        while tok not in (b"\r", b"\n"):
+            tok = stream.read(1)
+            # Prevents an infinite loop by raising an error if the stream is at
+            # the EOF
+            if len(tok) <= 0:
+                raise PdfStreamError("File ended unexpectedly.")
+        tok = read_non_whitespace(stream)
+        stream.seek(-1, 1)
+        return read_object(stream, pdf, forced_encoding)
+    elif tok in b"0123456789+-.":
+        # number object OR indirect reference
+        peek = stream.read(20)
+        stream.seek(-len(peek), 1)  # reset to start
+        if IndirectPattern.match(peek) is not None:
+            assert pdf is not None  # hint for mypy
+            return IndirectObject.read_from_stream(stream, pdf)
+        else:
+            return NumberObject.read_from_stream(stream)
+    else:
+        stream.seek(-20, 1)
+        raise PdfReadError(
+            f"Invalid Elementary Object starting with {tok!r} @{stream.tell()}: {stream.read(80).__repr__()}"
+        )
+
+
+class Field(TreeObject):
+    """
+    A class representing a field dictionary.
+
+    This class is accessed through
+    :meth:`get_fields()<pypdf.PdfReader.get_fields>`
+    """
+
+    def __init__(self, data: DictionaryObject) -> None:
+        DictionaryObject.__init__(self)
+        field_attributes = (
+            FieldDictionaryAttributes.attributes()
+            + CheckboxRadioButtonAttributes.attributes()
+        )
+        self.indirect_reference = data.indirect_reference
+        for attr in field_attributes:
+            try:
+                self[NameObject(attr)] = data[attr]
+            except KeyError:
+                pass
+        if isinstance(self.get("/V"), EncodedStreamObject):
+            d = cast(EncodedStreamObject, self[NameObject("/V")]).get_data()
+            if isinstance(d, bytes):
+                d_str = d.decode()
+            elif d is None:
+                d_str = ""
+            else:
+                raise Exception("Should never happen")
+            self[NameObject("/V")] = TextStringObject(d_str)
+
+    # TABLE 8.69 Entries common to all field dictionaries
+    @property
+    def field_type(self) -> Optional[NameObject]:
+        """Read-only property accessing the type of this field."""
+        return self.get(FieldDictionaryAttributes.FT)
+
+    @property
+    def parent(self) -> Optional[DictionaryObject]:
+        """Read-only property accessing the parent of this field."""
+        return self.get(FieldDictionaryAttributes.Parent)
+
+    @property
+    def kids(self) -> Optional["ArrayObject"]:
+        """Read-only property accessing the kids of this field."""
+        return self.get(FieldDictionaryAttributes.Kids)
+
+    @property
+    def name(self) -> Optional[str]:
+        """Read-only property accessing the name of this field."""
+        return self.get(FieldDictionaryAttributes.T)
+
+    @property
+    def alternate_name(self) -> Optional[str]:
+        """Read-only property accessing the alternate name of this field."""
+        return self.get(FieldDictionaryAttributes.TU)
+
+    @property
+    def mapping_name(self) -> Optional[str]:
+        """
+        Read-only property accessing the mapping name of this field.
+
+        This name is used by pypdf as a key in the dictionary returned by
+        :meth:`get_fields()<pypdf.PdfReader.get_fields>`
+        """
+        return self.get(FieldDictionaryAttributes.TM)
+
+    @property
+    def flags(self) -> Optional[int]:
+        """
+        Read-only property accessing the field flags, specifying various
+        characteristics of the field (see Table 8.70 of the PDF 1.7 reference).
+        """
+        return self.get(FieldDictionaryAttributes.Ff)
+
+    @property
+    def value(self) -> Optional[Any]:
+        """
+        Read-only property accessing the value of this field.
+
+        Format varies based on field type.
+        """
+        return self.get(FieldDictionaryAttributes.V)
+
+    @property
+    def default_value(self) -> Optional[Any]:
+        """Read-only property accessing the default value of this field."""
+        return self.get(FieldDictionaryAttributes.DV)
+
+    @property
+    def additional_actions(self) -> Optional[DictionaryObject]:
+        """
+        Read-only property accessing the additional actions dictionary.
+
+        This dictionary defines the field's behavior in response to trigger
+        events. See Section 8.5.2 of the PDF 1.7 reference.
+        """
+        return self.get(FieldDictionaryAttributes.AA)
+
+
+class Destination(TreeObject):
+    """
+    A class representing a destination within a PDF file.
+
+    See section 12.3.2 of the PDF 2.0 reference.
+
+    Args:
+        title: Title of this destination.
+        page: Reference to the page of this destination. Should
+            be an instance of :class:`IndirectObject<pypdf.generic.IndirectObject>`.
+        fit: How the destination is displayed.
+
+    Raises:
+        PdfReadError: If destination type is invalid.
+    """
+
+    node: Optional[
+        DictionaryObject
+    ] = None  # node provide access to the original Object
+
+    def __init__(
+        self,
+        title: str,
+        page: Union[NumberObject, IndirectObject, NullObject, DictionaryObject],
+        fit: Fit,
+    ) -> None:
+        self._filtered_children: List[Any] = []  # used in PdfWriter
+
+        typ = fit.fit_type
+        args = fit.fit_args
+
+        DictionaryObject.__init__(self)
+        self[NameObject("/Title")] = TextStringObject(title)
+        self[NameObject("/Page")] = page
+        self[NameObject("/Type")] = typ
+
+        # from table 8.2 of the PDF 1.7 reference.
+        if typ == "/XYZ":
+            if len(args) < 1:  # left is missing : should never occur
+                args.append(NumberObject(0.0))
+            if len(args) < 2:  # top is missing
+                args.append(NumberObject(0.0))
+            if len(args) < 3:  # zoom is missing
+                args.append(NumberObject(0.0))
+            (
+                self[NameObject(TA.LEFT)],
+                self[NameObject(TA.TOP)],
+                self[NameObject("/Zoom")],
+            ) = args
+        elif len(args) == 0:
+            pass
+        elif typ == TF.FIT_R:
+            (
+                self[NameObject(TA.LEFT)],
+                self[NameObject(TA.BOTTOM)],
+                self[NameObject(TA.RIGHT)],
+                self[NameObject(TA.TOP)],
+            ) = args
+        elif typ in [TF.FIT_H, TF.FIT_BH]:
+            try:  # Preferred to be more robust not only to null parameters
+                (self[NameObject(TA.TOP)],) = args
+            except Exception:
+                (self[NameObject(TA.TOP)],) = (NullObject(),)
+        elif typ in [TF.FIT_V, TF.FIT_BV]:
+            try:  # Preferred to be more robust not only to null parameters
+                (self[NameObject(TA.LEFT)],) = args
+            except Exception:
+                (self[NameObject(TA.LEFT)],) = (NullObject(),)
+        elif typ in [TF.FIT, TF.FIT_B]:
+            pass
+        else:
+            raise PdfReadError(f"Unknown Destination Type: {typ!r}")
+
+    @property
+    def dest_array(self) -> "ArrayObject":
+        return ArrayObject(
+            [self.raw_get("/Page"), self["/Type"]]
+            + [
+                self[x]
+                for x in ["/Left", "/Bottom", "/Right", "/Top", "/Zoom"]
+                if x in self
+            ]
+        )
+
+    def write_to_stream(
+        self, stream: StreamType, encryption_key: Union[None, str, bytes] = None
+    ) -> None:
+        if encryption_key is not None:  # deprecated
+            deprecate_no_replacement(
+                "the encryption_key parameter of write_to_stream", "5.0.0"
+            )
+        stream.write(b"<<\n")
+        key = NameObject("/D")
+        key.write_to_stream(stream)
+        stream.write(b" ")
+        value = self.dest_array
+        value.write_to_stream(stream)
+
+        key = NameObject("/S")
+        key.write_to_stream(stream)
+        stream.write(b" ")
+        value_s = NameObject("/GoTo")
+        value_s.write_to_stream(stream)
+
+        stream.write(b"\n")
+        stream.write(b">>")
+
+    @property
+    def title(self) -> Optional[str]:
+        """Read-only property accessing the destination title."""
+        return self.get("/Title")
+
+    @property
+    def page(self) -> Optional[int]:
+        """Read-only property accessing the destination page number."""
+        return self.get("/Page")
+
+    @property
+    def typ(self) -> Optional[str]:
+        """Read-only property accessing the destination type."""
+        return self.get("/Type")
+
+    @property
+    def zoom(self) -> Optional[int]:
+        """Read-only property accessing the zoom factor."""
+        return self.get("/Zoom", None)
+
+    @property
+    def left(self) -> Optional[FloatObject]:
+        """Read-only property accessing the left horizontal coordinate."""
+        return self.get("/Left", None)
+
+    @property
+    def right(self) -> Optional[FloatObject]:
+        """Read-only property accessing the right horizontal coordinate."""
+        return self.get("/Right", None)
+
+    @property
+    def top(self) -> Optional[FloatObject]:
+        """Read-only property accessing the top vertical coordinate."""
+        return self.get("/Top", None)
+
+    @property
+    def bottom(self) -> Optional[FloatObject]:
+        """Read-only property accessing the bottom vertical coordinate."""
+        return self.get("/Bottom", None)
+
+    @property
+    def color(self) -> Optional["ArrayObject"]:
+        """Read-only property accessing the color in (R, G, B) with values 0.0-1.0."""
+        return self.get(
+            "/C", ArrayObject([FloatObject(0), FloatObject(0), FloatObject(0)])
+        )
+
+    @property
+    def font_format(self) -> Optional[OutlineFontFlag]:
+        """
+        Read-only property accessing the font type.
+
+        1=italic, 2=bold, 3=both
+        """
+        return self.get("/F", 0)
+
+    @property
+    def outline_count(self) -> Optional[int]:
+        """
+        Read-only property accessing the outline count.
+
+        positive = expanded
+        negative = collapsed
+        absolute value = number of visible descendants at all levels
+        """
+        return self.get("/Count", None)
diff --git a/.venv/lib/python3.12/site-packages/pypdf/generic/_fit.py b/.venv/lib/python3.12/site-packages/pypdf/generic/_fit.py
new file mode 100644
index 00000000..4132f4b7
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/generic/_fit.py
@@ -0,0 +1,168 @@
+from typing import Any, Optional, Tuple, Union
+
+
+class Fit:
+    def __init__(
+        self, fit_type: str, fit_args: Tuple[Union[None, float, Any], ...] = ()
+    ):
+        from ._base import FloatObject, NameObject, NullObject
+
+        self.fit_type = NameObject(fit_type)
+        self.fit_args = [
+            NullObject() if a is None or isinstance(a, NullObject) else FloatObject(a)
+            for a in fit_args
+        ]
+
+    @classmethod
+    def xyz(
+        cls,
+        left: Optional[float] = None,
+        top: Optional[float] = None,
+        zoom: Optional[float] = None,
+    ) -> "Fit":
+        """
+        Display the page designated by page, with the coordinates (left, top)
+        positioned at the upper-left corner of the window and the contents
+        of the page magnified by the factor zoom.
+
+        A null value for any of the parameters left, top, or zoom specifies
+        that the current value of that parameter is to be retained unchanged.
+
+        A zoom value of 0 has the same meaning as a null value.
+
+        Args:
+            left:
+            top:
+            zoom:
+
+        Returns:
+            The created fit object.
+        """
+        return Fit(fit_type="/XYZ", fit_args=(left, top, zoom))
+
+    @classmethod
+    def fit(cls) -> "Fit":
+        """
+        Display the page designated by page, with its contents magnified just
+        enough to fit the entire page within the window both horizontally and
+        vertically.
+
+        If the required horizontal and vertical magnification factors are
+        different, use the smaller of the two, centering the page within the
+        window in the other dimension.
+        """
+        return Fit(fit_type="/Fit")
+
+    @classmethod
+    def fit_horizontally(cls, top: Optional[float] = None) -> "Fit":
+        """
+        Display the page designated by page, with the vertical coordinate top
+        positioned at the top edge of the window and the contents of the page
+        magnified just enough to fit the entire width of the page within the
+        window.
+
+        A null value for ``top`` specifies that the current value of that
+        parameter is to be retained unchanged.
+
+        Args:
+            top:
+
+        Returns:
+            The created fit object.
+        """
+        return Fit(fit_type="/FitH", fit_args=(top,))
+
+    @classmethod
+    def fit_vertically(cls, left: Optional[float] = None) -> "Fit":
+        return Fit(fit_type="/FitV", fit_args=(left,))
+
+    @classmethod
+    def fit_rectangle(
+        cls,
+        left: Optional[float] = None,
+        bottom: Optional[float] = None,
+        right: Optional[float] = None,
+        top: Optional[float] = None,
+    ) -> "Fit":
+        """
+        Display the page designated by page, with its contents magnified
+        just enough to fit the rectangle specified by the coordinates
+        left, bottom, right, and top entirely within the window
+        both horizontally and vertically.
+
+        If the required horizontal and vertical magnification factors are
+        different, use the smaller of the two, centering the rectangle within
+        the window in the other dimension.
+
+        A null value for any of the parameters may result in unpredictable
+        behavior.
+
+        Args:
+            left:
+            bottom:
+            right:
+            top:
+
+        Returns:
+            The created fit object.
+        """
+        return Fit(fit_type="/FitR", fit_args=(left, bottom, right, top))
+
+    @classmethod
+    def fit_box(cls) -> "Fit":
+        """
+        Display the page designated by page, with its contents magnified just
+        enough to fit its bounding box entirely within the window both
+        horizontally and vertically.
+
+        If the required horizontal and vertical magnification factors are
+        different, use the smaller of the two, centering the bounding box
+        within the window in the other dimension.
+        """
+        return Fit(fit_type="/FitB")
+
+    @classmethod
+    def fit_box_horizontally(cls, top: Optional[float] = None) -> "Fit":
+        """
+        Display the page designated by page, with the vertical coordinate top
+        positioned at the top edge of the window and the contents of the page
+        magnified just enough to fit the entire width of its bounding box
+        within the window.
+
+        A null value for top specifies that the current value of that parameter
+        is to be retained unchanged.
+
+        Args:
+            top:
+
+        Returns:
+            The created fit object.
+        """
+        return Fit(fit_type="/FitBH", fit_args=(top,))
+
+    @classmethod
+    def fit_box_vertically(cls, left: Optional[float] = None) -> "Fit":
+        """
+        Display the page designated by page, with the horizontal coordinate
+        left positioned at the left edge of the window and the contents of the
+        page magnified just enough to fit the entire height of its bounding box
+        within the window.
+
+        A null value for left specifies that the current value of that
+        parameter is to be retained unchanged.
+
+        Args:
+            left:
+
+        Returns:
+            The created fit object.
+        """
+        return Fit(fit_type="/FitBV", fit_args=(left,))
+
+    def __str__(self) -> str:
+        if not self.fit_args:
+            return f"Fit({self.fit_type})"
+        return f"Fit({self.fit_type}, {self.fit_args})"
+
+
+DEFAULT_FIT = Fit.fit()
diff --git a/.venv/lib/python3.12/site-packages/pypdf/generic/_image_inline.py b/.venv/lib/python3.12/site-packages/pypdf/generic/_image_inline.py
new file mode 100644
index 00000000..41826ac3
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/generic/_image_inline.py
@@ -0,0 +1,235 @@
+# Copyright (c) 2024, pypdf contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# * The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+import logging
+from io import BytesIO
+
+from .._utils import (
+    WHITESPACES,
+    StreamType,
+    read_non_whitespace,
+)
+from ..errors import PdfReadError
+
+logger = logging.getLogger(__name__)
+
+BUFFER_SIZE = 8192
+
+
+def extract_inline_AHx(stream: StreamType) -> bytes:
+    """
+    Extract HexEncoded Stream from Inline Image.
+    the stream will be moved onto the EI
+    """
+    data_out: bytes = b""
+    # Read data until delimiter > and EI as backup
+    # ignoring backup.
+    while True:
+        data_buffered = read_non_whitespace(stream) + stream.read(BUFFER_SIZE)
+        if not data_buffered:
+            raise PdfReadError("Unexpected end of stream")
+        pos_tok = data_buffered.find(b">")
+        if pos_tok >= 0:  # found >
+            data_out += data_buffered[: (pos_tok + 1)]
+            stream.seek(-len(data_buffered) + pos_tok + 1, 1)
+            break
+        pos_ei = data_buffered.find(b"EI")
+        if pos_ei >= 0:  # found EI
+            stream.seek(-len(data_buffered) + pos_ei - 1, 1)
+            c = stream.read(1)
+            while c in WHITESPACES:
+                stream.seek(-2, 1)
+                c = stream.read(1)
+                pos_ei -= 1
+            data_out += data_buffered[:pos_ei]
+            break
+        elif len(data_buffered) == 2:
+            data_out += data_buffered
+            raise PdfReadError("Unexpected end of stream")
+        else:  # > nor EI found
+            data_out += data_buffered[:-2]
+            stream.seek(-2, 1)
+
+    ei_tok = read_non_whitespace(stream)
+    ei_tok += stream.read(2)
+    stream.seek(-3, 1)
+    if ei_tok[0:2] != b"EI" or not (ei_tok[2:3] == b"" or ei_tok[2:3] in WHITESPACES):
+        raise PdfReadError("EI stream not found")
+    return data_out
+
+
+def extract_inline_A85(stream: StreamType) -> bytes:
+    """
+    Extract A85 Stream from Inline Image.
+    the stream will be moved onto the EI
+    """
+    data_out: bytes = b""
+    # Read data up to delimiter ~>
+    # see §3.3.2 from PDF ref 1.7
+    while True:
+        data_buffered = read_non_whitespace(stream) + stream.read(BUFFER_SIZE)
+        if not data_buffered:
+            raise PdfReadError("Unexpected end of stream")
+        pos_tok = data_buffered.find(b"~>")
+        if pos_tok >= 0:  # found!
+            data_out += data_buffered[: pos_tok + 2]
+            stream.seek(-len(data_buffered) + pos_tok + 2, 1)
+            break
+        elif len(data_buffered) == 2:  # end of buffer
+            data_out += data_buffered
+            raise PdfReadError("Unexpected end of stream")
+        data_out += data_buffered[
+            :-2
+        ]  # back by one char in case of in the middle of ~>
+        stream.seek(-2, 1)
+
+    ei_tok = read_non_whitespace(stream)
+    ei_tok += stream.read(2)
+    stream.seek(-3, 1)
+    if ei_tok[0:2] != b"EI" or not (ei_tok[2:3] == b"" or ei_tok[2:3] in WHITESPACES):
+        raise PdfReadError("EI stream not found")
+    return data_out
+
+
+def extract_inline_RL(stream: StreamType) -> bytes:
+    """
+    Extract RL Stream from Inline Image.
+    the stream will be moved onto the EI
+    """
+    data_out: bytes = b""
+    # Read data up to delimiter ~>
+    # see §3.3.4 from PDF ref 1.7
+    while True:
+        data_buffered = stream.read(BUFFER_SIZE)
+        if not data_buffered:
+            raise PdfReadError("Unexpected end of stream")
+        pos_tok = data_buffered.find(b"\x80")
+        if pos_tok >= 0:  # found
+            data_out += data_buffered[: pos_tok + 1]
+            stream.seek(-len(data_buffered) + pos_tok + 1, 1)
+            break
+        data_out += data_buffered
+
+    ei_tok = read_non_whitespace(stream)
+    ei_tok += stream.read(2)
+    stream.seek(-3, 1)
+    if ei_tok[0:2] != b"EI" or not (ei_tok[2:3] == b"" or ei_tok[2:3] in WHITESPACES):
+        raise PdfReadError("EI stream not found")
+    return data_out
+
+
+def extract_inline_DCT(stream: StreamType) -> bytes:
+    """
+    Extract DCT (JPEG) Stream from Inline Image.
+    the stream will be moved onto the EI
+    """
+    data_out: bytes = b""
+    # Read Blocks of data (ID/Size/data) up to ID=FF/D9
+    # see https://www.digicamsoft.com/itu/itu-t81-36.html
+    notfirst = False
+    while True:
+        c = stream.read(1)
+        if notfirst or (c == b"\xff"):
+            data_out += c
+        if c != b"\xff":
+            continue
+        else:
+            notfirst = True
+        c = stream.read(1)
+        data_out += c
+        if c == b"\xff":
+            stream.seek(-1, 1)  # pragma: no cover
+        elif c == b"\x00":  # stuffing
+            pass
+        elif c == b"\xd9":  # end
+            break
+        elif c in (
+            b"\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc9\xca\xcb\xcc\xcd\xce\xcf"
+            b"\xda\xdb\xdc\xdd\xde\xdf"
+            b"\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xfe"
+        ):
+            c = stream.read(2)
+            data_out += c
+            sz = c[0] * 256 + c[1]
+            data_out += stream.read(sz - 2)
+        # else: pass
+
+    ei_tok = read_non_whitespace(stream)
+    ei_tok += stream.read(2)
+    stream.seek(-3, 1)
+    if ei_tok[0:2] != b"EI" or not (ei_tok[2:3] == b"" or ei_tok[2:3] in WHITESPACES):
+        raise PdfReadError("EI stream not found")
+    return data_out
+
+
+def extract_inline_default(stream: StreamType) -> bytes:
+    """
+    Legacy method
+    used by default
+    """
+    stream_out = BytesIO()
+    # Read the inline image, while checking for EI (End Image) operator.
+    while True:
+        data_buffered = stream.read(BUFFER_SIZE)
+        if not data_buffered:
+            raise PdfReadError("Unexpected end of stream")
+        pos_ei = data_buffered.find(
+            b"E"
+        )  # we can not look straight for "EI" because it may not have been loaded in the buffer
+
+        if pos_ei == -1:
+            stream_out.write(data_buffered)
+        else:
+            # Write out everything including E (the one from EI to be removed).
+            stream_out.write(data_buffered[0 : pos_ei + 1])
+            sav_pos_ei = stream_out.tell() - 1
+            # Seek back in the stream to read the E next.
+            stream.seek(pos_ei + 1 - len(data_buffered), 1)
+            saved_pos = stream.tell()
+            # Check for End Image
+            tok2 = stream.read(1)  # I of "EI"
+            if tok2 != b"I":
+                stream.seek(saved_pos, 0)
+                continue
+            tok3 = stream.read(1)  # possible space after "EI"
+            if tok3 not in WHITESPACES:
+                stream.seek(saved_pos, 0)
+                continue
+            while tok3 in WHITESPACES:
+                tok3 = stream.read(1)
+            if data_buffered[pos_ei - 1 : pos_ei] not in WHITESPACES and tok3 not in {
+                b"Q",
+                b"E",
+            }:  # for Q ou EMC
+                stream.seek(saved_pos, 0)
+                continue
+            # Data contains [\s]EI[\s](Q|EMC): 4 chars are sufficients
+            # remove E(I) wrongly inserted earlier
+            stream_out.truncate(sav_pos_ei)
+            break
+
+    return stream_out.getvalue()
diff --git a/.venv/lib/python3.12/site-packages/pypdf/generic/_outline.py b/.venv/lib/python3.12/site-packages/pypdf/generic/_outline.py
new file mode 100644
index 00000000..4d6a47da
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/generic/_outline.py
@@ -0,0 +1,33 @@
+from typing import Union
+
+from .._utils import StreamType, deprecate_no_replacement
+from ._base import NameObject
+from ._data_structures import Destination
+
+
+class OutlineItem(Destination):
+    def write_to_stream(
+        self, stream: StreamType, encryption_key: Union[None, str, bytes] = None
+    ) -> None:
+        if encryption_key is not None:  # deprecated
+            deprecate_no_replacement(
+                "the encryption_key parameter of write_to_stream", "5.0.0"
+            )
+        stream.write(b"<<\n")
+        for key in [
+            NameObject(x)
+            for x in ["/Title", "/Parent", "/First", "/Last", "/Next", "/Prev"]
+            if x in self
+        ]:
+            key.write_to_stream(stream)
+            stream.write(b" ")
+            value = self.raw_get(key)
+            value.write_to_stream(stream)
+            stream.write(b"\n")
+        key = NameObject("/Dest")
+        key.write_to_stream(stream)
+        stream.write(b" ")
+        value = self.dest_array
+        value.write_to_stream(stream)
+        stream.write(b"\n")
+        stream.write(b">>")
diff --git a/.venv/lib/python3.12/site-packages/pypdf/generic/_rectangle.py b/.venv/lib/python3.12/site-packages/pypdf/generic/_rectangle.py
new file mode 100644
index 00000000..690b5217
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/generic/_rectangle.py
@@ -0,0 +1,132 @@
+from typing import Any, Tuple, Union
+
+from ._base import FloatObject, NumberObject
+from ._data_structures import ArrayObject
+
+
+class RectangleObject(ArrayObject):
+    """
+    This class is used to represent *page boxes* in pypdf.
+
+    These boxes include:
+
+    * :attr:`artbox <pypdf._page.PageObject.artbox>`
+    * :attr:`bleedbox <pypdf._page.PageObject.bleedbox>`
+    * :attr:`cropbox <pypdf._page.PageObject.cropbox>`
+    * :attr:`mediabox <pypdf._page.PageObject.mediabox>`
+    * :attr:`trimbox <pypdf._page.PageObject.trimbox>`
+    """
+
+    def __init__(
+        self, arr: Union["RectangleObject", Tuple[float, float, float, float]]
+    ) -> None:
+        # must have four points
+        assert len(arr) == 4
+        # automatically convert arr[x] into NumberObject(arr[x]) if necessary
+        ArrayObject.__init__(self, [self._ensure_is_number(x) for x in arr])  # type: ignore
+
+    def _ensure_is_number(self, value: Any) -> Union[FloatObject, NumberObject]:
+        if not isinstance(value, (NumberObject, FloatObject)):
+            value = FloatObject(value)
+        return value
+
+    def scale(self, sx: float, sy: float) -> "RectangleObject":
+        return RectangleObject(
+            (
+                float(self.left) * sx,
+                float(self.bottom) * sy,
+                float(self.right) * sx,
+                float(self.top) * sy,
+            )
+        )
+
+    def __repr__(self) -> str:
+        return f"RectangleObject({list(self)!r})"
+
+    @property
+    def left(self) -> FloatObject:
+        return self[0]
+
+    @left.setter
+    def left(self, f: float) -> None:
+        self[0] = FloatObject(f)
+
+    @property
+    def bottom(self) -> FloatObject:
+        return self[1]
+
+    @bottom.setter
+    def bottom(self, f: float) -> None:
+        self[1] = FloatObject(f)
+
+    @property
+    def right(self) -> FloatObject:
+        return self[2]
+
+    @right.setter
+    def right(self, f: float) -> None:
+        self[2] = FloatObject(f)
+
+    @property
+    def top(self) -> FloatObject:
+        return self[3]
+
+    @top.setter
+    def top(self, f: float) -> None:
+        self[3] = FloatObject(f)
+
+    @property
+    def lower_left(self) -> Tuple[float, float]:
+        """
+        Property to read and modify the lower left coordinate of this box
+        in (x,y) form.
+        """
+        return self.left, self.bottom
+
+    @lower_left.setter
+    def lower_left(self, value: Tuple[float, float]) -> None:
+        self[0], self[1] = (self._ensure_is_number(x) for x in value)
+
+    @property
+    def lower_right(self) -> Tuple[float, float]:
+        """
+        Property to read and modify the lower right coordinate of this box
+        in (x,y) form.
+        """
+        return self.right, self.bottom
+
+    @lower_right.setter
+    def lower_right(self, value: Tuple[float, float]) -> None:
+        self[2], self[1] = (self._ensure_is_number(x) for x in value)
+
+    @property
+    def upper_left(self) -> Tuple[float, float]:
+        """
+        Property to read and modify the upper left coordinate of this box
+        in (x,y) form.
+        """
+        return self.left, self.top
+
+    @upper_left.setter
+    def upper_left(self, value: Tuple[float, float]) -> None:
+        self[0], self[3] = (self._ensure_is_number(x) for x in value)
+
+    @property
+    def upper_right(self) -> Tuple[float, float]:
+        """
+        Property to read and modify the upper right coordinate of this box
+        in (x,y) form.
+        """
+        return self.right, self.top
+
+    @upper_right.setter
+    def upper_right(self, value: Tuple[float, float]) -> None:
+        self[2], self[3] = (self._ensure_is_number(x) for x in value)
+
+    @property
+    def width(self) -> float:
+        return self.right - self.left
+
+    @property
+    def height(self) -> float:
+        return self.top - self.bottom
diff --git a/.venv/lib/python3.12/site-packages/pypdf/generic/_utils.py b/.venv/lib/python3.12/site-packages/pypdf/generic/_utils.py
new file mode 100644
index 00000000..fdcdc333
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/generic/_utils.py
@@ -0,0 +1,180 @@
+import codecs
+from typing import Dict, List, Tuple, Union
+
+from .._codecs import _pdfdoc_encoding
+from .._utils import StreamType, b_, logger_warning, read_non_whitespace
+from ..errors import STREAM_TRUNCATED_PREMATURELY, PdfStreamError
+from ._base import ByteStringObject, TextStringObject
+
+
+def hex_to_rgb(value: str) -> Tuple[float, float, float]:
+    return tuple(int(value.lstrip("#")[i : i + 2], 16) / 255.0 for i in (0, 2, 4))  # type: ignore
+
+
+def read_hex_string_from_stream(
+    stream: StreamType,
+    forced_encoding: Union[None, str, List[str], Dict[int, str]] = None,
+) -> Union["TextStringObject", "ByteStringObject"]:
+    stream.read(1)
+    txt = ""
+    x = b""
+    while True:
+        tok = read_non_whitespace(stream)
+        if not tok:
+            raise PdfStreamError(STREAM_TRUNCATED_PREMATURELY)
+        if tok == b">":
+            break
+        x += tok
+        if len(x) == 2:
+            txt += chr(int(x, base=16))
+            x = b""
+    if len(x) == 1:
+        x += b"0"
+    if len(x) == 2:
+        txt += chr(int(x, base=16))
+    return create_string_object(b_(txt), forced_encoding)
+
+
+def read_string_from_stream(
+    stream: StreamType,
+    forced_encoding: Union[None, str, List[str], Dict[int, str]] = None,
+) -> Union["TextStringObject", "ByteStringObject"]:
+    tok = stream.read(1)
+    parens = 1
+    txt = []
+    while True:
+        tok = stream.read(1)
+        if not tok:
+            raise PdfStreamError(STREAM_TRUNCATED_PREMATURELY)
+        if tok == b"(":
+            parens += 1
+        elif tok == b")":
+            parens -= 1
+            if parens == 0:
+                break
+        elif tok == b"\\":
+            tok = stream.read(1)
+            escape_dict = {
+                b"n": b"\n",
+                b"r": b"\r",
+                b"t": b"\t",
+                b"b": b"\b",
+                b"f": b"\f",
+                b"c": rb"\c",
+                b"(": b"(",
+                b")": b")",
+                b"/": b"/",
+                b"\\": b"\\",
+                b" ": b" ",
+                b"%": b"%",
+                b"<": b"<",
+                b">": b">",
+                b"[": b"[",
+                b"]": b"]",
+                b"#": b"#",
+                b"_": b"_",
+                b"&": b"&",
+                b"$": b"$",
+            }
+            try:
+                tok = escape_dict[tok]
+            except KeyError:
+                if b"0" <= tok <= b"7":
+                    # "The number ddd may consist of one, two, or three
+                    # octal digits; high-order overflow shall be ignored.
+                    # Three octal digits shall be used, with leading zeros
+                    # as needed, if the next character of the string is also
+                    # a digit." (PDF reference 7.3.4.2, p 16)
+                    for _ in range(2):
+                        ntok = stream.read(1)
+                        if b"0" <= ntok <= b"7":
+                            tok += ntok
+                        else:
+                            stream.seek(-1, 1)  # ntok has to be analyzed
+                            break
+                    tok = b_(chr(int(tok, base=8)))
+                elif tok in b"\n\r":
+                    # This case is  hit when a backslash followed by a line
+                    # break occurs. If it's a multi-char EOL, consume the
+                    # second character:
+                    tok = stream.read(1)
+                    if tok not in b"\n\r":
+                        stream.seek(-1, 1)
+                    # Then don't add anything to the actual string, since this
+                    # line break was escaped:
+                    tok = b""
+                else:
+                    msg = f"Unexpected escaped string: {tok.decode('utf-8','ignore')}"
+                    logger_warning(msg, __name__)
+        txt.append(tok)
+    return create_string_object(b"".join(txt), forced_encoding)
+
+
+def create_string_object(
+    string: Union[str, bytes],
+    forced_encoding: Union[None, str, List[str], Dict[int, str]] = None,
+) -> Union[TextStringObject, ByteStringObject]:
+    """
+    Create a ByteStringObject or a TextStringObject from a string to represent the string.
+
+    Args:
+        string: The data being used
+        forced_encoding: Typically None, or an encoding string
+
+    Returns:
+        A ByteStringObject
+
+    Raises:
+        TypeError: If string is not of type str or bytes.
+    """
+    if isinstance(string, str):
+        return TextStringObject(string)
+    elif isinstance(string, bytes):
+        if isinstance(forced_encoding, (list, dict)):
+            out = ""
+            for x in string:
+                try:
+                    out += forced_encoding[x]
+                except Exception:
+                    out += bytes((x,)).decode("charmap")
+            return TextStringObject(out)
+        elif isinstance(forced_encoding, str):
+            if forced_encoding == "bytes":
+                return ByteStringObject(string)
+            return TextStringObject(string.decode(forced_encoding))
+        else:
+            try:
+                if string.startswith((codecs.BOM_UTF16_BE, codecs.BOM_UTF16_LE)):
+                    retval = TextStringObject(string.decode("utf-16"))
+                    retval.autodetect_utf16 = True
+                    retval.utf16_bom = string[:2]
+                    return retval
+                else:
+                    # This is probably a big performance hit here, but we need
+                    # to convert string objects into the text/unicode-aware
+                    # version if possible... and the only way to check if that's
+                    # possible is to try.
+                    # Some strings are strings, some are just byte arrays.
+                    retval = TextStringObject(decode_pdfdocencoding(string))
+                    retval.autodetect_pdfdocencoding = True
+                    return retval
+            except UnicodeDecodeError:
+                return ByteStringObject(string)
+    else:
+        raise TypeError("create_string_object should have str or unicode arg")
+
+
+def decode_pdfdocencoding(byte_array: bytes) -> str:
+    retval = ""
+    for b in byte_array:
+        c = _pdfdoc_encoding[b]
+        if c == "\u0000":
+            raise UnicodeDecodeError(
+                "pdfdocencoding",
+                bytearray(b),
+                -1,
+                -1,
+                "does not exist in translation table",
+            )
+        retval += c
+    return retval
diff --git a/.venv/lib/python3.12/site-packages/pypdf/generic/_viewerpref.py b/.venv/lib/python3.12/site-packages/pypdf/generic/_viewerpref.py
new file mode 100644
index 00000000..a12f2d44
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/generic/_viewerpref.py
@@ -0,0 +1,164 @@
+# Copyright (c) 2023, Pubpub-ZZ
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# * The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+from typing import (
+    Any,
+    List,
+    Optional,
+)
+
+from ._base import BooleanObject, NameObject, NumberObject
+from ._data_structures import ArrayObject, DictionaryObject
+
+f_obj = BooleanObject(False)
+
+
+class ViewerPreferences(DictionaryObject):
+    def _get_bool(self, key: str, deft: Optional[BooleanObject]) -> BooleanObject:
+        return self.get(key, deft)
+
+    def _set_bool(self, key: str, v: bool) -> None:
+        self[NameObject(key)] = BooleanObject(v is True)
+
+    def _get_name(self, key: str, deft: Optional[NameObject]) -> Optional[NameObject]:
+        return self.get(key, deft)
+
+    def _set_name(self, key: str, lst: List[str], v: NameObject) -> None:
+        if v[0] != "/":
+            raise ValueError(f"{v} is not starting with '/'")
+        if lst != [] and v not in lst:
+            raise ValueError(f"{v} is not par of acceptable values")
+        self[NameObject(key)] = NameObject(v)
+
+    def _get_arr(self, key: str, deft: Optional[List[Any]]) -> NumberObject:
+        return self.get(key, None if deft is None else ArrayObject(deft))
+
+    def _set_arr(self, key: str, v: Optional[ArrayObject]) -> None:
+        if v is None:
+            try:
+                del self[NameObject(key)]
+            except KeyError:
+                pass
+            return
+        if not isinstance(v, ArrayObject):
+            raise ValueError("ArrayObject is expected")
+        self[NameObject(key)] = v
+
+    def _get_int(self, key: str, deft: Optional[NumberObject]) -> NumberObject:
+        return self.get(key, deft)
+
+    def _set_int(self, key: str, v: int) -> None:
+        self[NameObject(key)] = NumberObject(v)
+
+    @property
+    def PRINT_SCALING(self) -> NameObject:
+        return NameObject("/PrintScaling")
+
+    def __new__(cls: Any, value: Any = None) -> "ViewerPreferences":
+        def _add_prop_bool(key: str, deft: Optional[BooleanObject]) -> property:
+            return property(
+                lambda self: self._get_bool(key, deft),
+                lambda self, v: self._set_bool(key, v),
+                None,
+                f"""
+            Returns/Modify the status of {key}, Returns {deft} if not defined
+            """,
+            )
+
+        def _add_prop_name(
+            key: str, lst: List[str], deft: Optional[NameObject]
+        ) -> property:
+            return property(
+                lambda self: self._get_name(key, deft),
+                lambda self, v: self._set_name(key, lst, v),
+                None,
+                f"""
+            Returns/Modify the status of {key}, Returns {deft} if not defined.
+            Acceptable values: {lst}
+            """,
+            )
+
+        def _add_prop_arr(key: str, deft: Optional[ArrayObject]) -> property:
+            return property(
+                lambda self: self._get_arr(key, deft),
+                lambda self, v: self._set_arr(key, v),
+                None,
+                f"""
+            Returns/Modify the status of {key}, Returns {deft} if not defined
+            """,
+            )
+
+        def _add_prop_int(key: str, deft: Optional[int]) -> property:
+            return property(
+                lambda self: self._get_int(key, deft),
+                lambda self, v: self._set_int(key, v),
+                None,
+                f"""
+            Returns/Modify the status of {key}, Returns {deft} if not defined
+            """,
+            )
+
+        cls.hide_toolbar = _add_prop_bool("/HideToolbar", f_obj)
+        cls.hide_menubar = _add_prop_bool("/HideMenubar", f_obj)
+        cls.hide_windowui = _add_prop_bool("/HideWindowUI", f_obj)
+        cls.fit_window = _add_prop_bool("/FitWindow", f_obj)
+        cls.center_window = _add_prop_bool("/CenterWindow", f_obj)
+        cls.display_doctitle = _add_prop_bool("/DisplayDocTitle", f_obj)
+
+        cls.non_fullscreen_pagemode = _add_prop_name(
+            "/NonFullScreenPageMode",
+            ["/UseNone", "/UseOutlines", "/UseThumbs", "/UseOC"],
+            NameObject("/UseNone"),
+        )
+        cls.direction = _add_prop_name(
+            "/Direction", ["/L2R", "/R2L"], NameObject("/L2R")
+        )
+        cls.view_area = _add_prop_name("/ViewArea", [], None)
+        cls.view_clip = _add_prop_name("/ViewClip", [], None)
+        cls.print_area = _add_prop_name("/PrintArea", [], None)
+        cls.print_clip = _add_prop_name("/PrintClip", [], None)
+        cls.print_scaling = _add_prop_name("/PrintScaling", [], None)
+        cls.duplex = _add_prop_name(
+            "/Duplex", ["/Simplex", "/DuplexFlipShortEdge", "/DuplexFlipLongEdge"], None
+        )
+        cls.pick_tray_by_pdfsize = _add_prop_bool("/PickTrayByPDFSize", None)
+        cls.print_pagerange = _add_prop_arr("/PrintPageRange", None)
+        cls.num_copies = _add_prop_int("/NumCopies", None)
+
+        cls.enforce = _add_prop_arr("/Enforce", ArrayObject())
+
+        return DictionaryObject.__new__(cls)
+
+    def __init__(self, obj: Optional[DictionaryObject] = None) -> None:
+        super().__init__(self)
+        if obj is not None:
+            self.update(obj.items())
+        try:
+            self.indirect_reference = obj.indirect_reference  # type: ignore
+        except AttributeError:
+            pass
diff --git a/.venv/lib/python3.12/site-packages/pypdf/pagerange.py b/.venv/lib/python3.12/site-packages/pypdf/pagerange.py
new file mode 100644
index 00000000..47a72c72
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/pagerange.py
@@ -0,0 +1,192 @@
+"""
+Representation and utils for ranges of PDF file pages.
+
+Copyright (c) 2014, Steve Witham <switham_github@mac-guyver.com>.
+All rights reserved. This software is available under a BSD license;
+see https://github.com/py-pdf/pypdf/blob/main/LICENSE
+"""
+
+import re
+from typing import Any, List, Tuple, Union
+
+from .errors import ParseError
+
+_INT_RE = r"(0|-?[1-9]\d*)"  # A decimal int, don't allow "-0".
+PAGE_RANGE_RE = f"^({_INT_RE}|({_INT_RE}?(:{_INT_RE}?(:{_INT_RE}?)?)))$"
+# groups:         12     34     5 6     7 8
+
+
+class PageRange:
+    """
+    A slice-like representation of a range of page indices.
+
+    For example, page numbers, only starting at zero.
+
+    The syntax is like what you would put between brackets [ ].
+    The slice is one of the few Python types that can't be subclassed,
+    but this class converts to and from slices, and allows similar use.
+
+      -  PageRange(str) parses a string representing a page range.
+      -  PageRange(slice) directly "imports" a slice.
+      -  to_slice() gives the equivalent slice.
+      -  str() and repr() allow printing.
+      -  indices(n) is like slice.indices(n).
+    """
+
+    def __init__(self, arg: Union[slice, "PageRange", str]) -> None:
+        """
+        Initialize with either a slice -- giving the equivalent page range,
+        or a PageRange object -- making a copy,
+        or a string like
+            "int", "[int]:[int]" or "[int]:[int]:[int]",
+            where the brackets indicate optional ints.
+        Remember, page indices start with zero.
+        Page range expression examples:
+
+            :     all pages.                   -1    last page.
+            22    just the 23rd page.          :-1   all but the last page.
+            0:3   the first three pages.       -2    second-to-last page.
+            :3    the first three pages.       -2:   last two pages.
+            5:    from the sixth page onward.  -3:-1 third & second to last.
+        The third, "stride" or "step" number is also recognized.
+            ::2       0 2 4 ... to the end.    3:0:-1    3 2 1 but not 0.
+            1:10:2    1 3 5 7 9                2::-1     2 1 0.
+            ::-1      all pages in reverse order.
+        Note the difference between this notation and arguments to slice():
+            slice(3) means the first three pages;
+            PageRange("3") means the range of only the fourth page.
+            However PageRange(slice(3)) means the first three pages.
+        """
+        if isinstance(arg, slice):
+            self._slice = arg
+            return
+
+        if isinstance(arg, PageRange):
+            self._slice = arg.to_slice()
+            return
+
+        m = isinstance(arg, str) and re.match(PAGE_RANGE_RE, arg)
+        if not m:
+            raise ParseError(arg)
+        elif m.group(2):
+            # Special case: just an int means a range of one page.
+            start = int(m.group(2))
+            stop = start + 1 if start != -1 else None
+            self._slice = slice(start, stop)
+        else:
+            self._slice = slice(*[int(g) if g else None for g in m.group(4, 6, 8)])
+
+    @staticmethod
+    def valid(input: Any) -> bool:
+        """
+        True if input is a valid initializer for a PageRange.
+
+        Args:
+            input: A possible PageRange string or a PageRange object.
+
+        Returns:
+            True, if the ``input`` is a valid PageRange.
+        """
+        return isinstance(input, (slice, PageRange)) or (
+            isinstance(input, str) and bool(re.match(PAGE_RANGE_RE, input))
+        )
+
+    def to_slice(self) -> slice:
+        """Return the slice equivalent of this page range."""
+        return self._slice
+
+    def __str__(self) -> str:
+        """A string like "1:2:3"."""
+        s = self._slice
+        indices: Union[Tuple[int, int], Tuple[int, int, int]]
+        if s.step is None:
+            if s.start is not None and s.stop == s.start + 1:
+                return str(s.start)
+
+            indices = s.start, s.stop
+        else:
+            indices = s.start, s.stop, s.step
+        return ":".join("" if i is None else str(i) for i in indices)
+
+    def __repr__(self) -> str:
+        """A string like "PageRange('1:2:3')"."""
+        return "PageRange(" + repr(str(self)) + ")"
+
+    def indices(self, n: int) -> Tuple[int, int, int]:
+        """
+        Assuming a sequence of length n, calculate the start and stop indices,
+        and the stride length of the PageRange.
+
+        See help(slice.indices).
+
+        Args:
+            n:  the length of the list of pages to choose from.
+
+        Returns:
+            Arguments for range().
+        """
+        return self._slice.indices(n)
+
+    def __eq__(self, other: object) -> bool:
+        if not isinstance(other, PageRange):
+            return False
+        return self._slice == other._slice
+
+    def __add__(self, other: "PageRange") -> "PageRange":
+        if not isinstance(other, PageRange):
+            raise TypeError(f"Can't add PageRange and {type(other)}")
+        if self._slice.step is not None or other._slice.step is not None:
+            raise ValueError("Can't add PageRange with stride")
+        a = self._slice.start, self._slice.stop
+        b = other._slice.start, other._slice.stop
+
+        if a[0] > b[0]:
+            a, b = b, a
+
+        # Now a[0] is the smallest
+        if b[0] > a[1]:
+            # There is a gap between a and b.
+            raise ValueError("Can't add PageRanges with gap")
+        return PageRange(slice(a[0], max(a[1], b[1])))
+
+
+PAGE_RANGE_ALL = PageRange(":")  # The range of all pages.
+
+
+def parse_filename_page_ranges(
+    args: List[Union[str, PageRange, None]]
+) -> List[Tuple[str, PageRange]]:
+    """
+    Given a list of filenames and page ranges, return a list of (filename, page_range) pairs.
+
+    Args:
+        args: A list where the first element is a filename. The other elements are
+            filenames, page-range expressions, slice objects, or PageRange objects.
+            A filename not followed by a page range indicates all pages of the file.
+
+    Returns:
+        A list of (filename, page_range) pairs.
+    """
+    pairs: List[Tuple[str, PageRange]] = []
+    pdf_filename = None
+    did_page_range = False
+    for arg in args + [None]:
+        if PageRange.valid(arg):
+            if not pdf_filename:
+                raise ValueError(
+                    "The first argument must be a filename, not a page range."
+                )
+
+            pairs.append((pdf_filename, PageRange(arg)))
+            did_page_range = True
+        else:
+            # New filename or end of list--do all of the previous file?
+            if pdf_filename and not did_page_range:
+                pairs.append((pdf_filename, PAGE_RANGE_ALL))
+
+            pdf_filename = arg
+            did_page_range = False
+    return pairs
+
+
+PageRangeSpec = Union[str, PageRange, Tuple[int, int], Tuple[int, int, int], List[int]]
diff --git a/.venv/lib/python3.12/site-packages/pypdf/papersizes.py b/.venv/lib/python3.12/site-packages/pypdf/papersizes.py
new file mode 100644
index 00000000..2d83e1d5
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/papersizes.py
@@ -0,0 +1,51 @@
+"""Helper to get paper sizes."""
+
+from typing import NamedTuple
+
+
+class Dimensions(NamedTuple):
+    width: int
+    height: int
+
+
+class PaperSize:
+    """(width, height) of the paper in portrait mode in pixels at 72 ppi."""
+
+    # Notes how to calculate it:
+    # 1. Get the size of the paper in mm
+    # 2. Convert it to inches (25.4 millimeters are equal to 1 inches)
+    # 3. Convert it to pixels ad 72dpi (1 inch is equal to 72 pixels)
+
+    # All Din-A paper sizes follow this pattern:
+    # 2xA(n-1) = A(n)
+    # So the height of the next bigger one is the width of the smaller one
+    # The ratio is always approximately the ratio 1:2**0.5
+    # Additionally, A0 is defined to have an area of 1 m**2
+    # Be aware of rounding issues!
+    A0 = Dimensions(2384, 3370)  # 841mm x 1189mm
+    A1 = Dimensions(1684, 2384)
+    A2 = Dimensions(1191, 1684)
+    A3 = Dimensions(842, 1191)
+    A4 = Dimensions(
+        595, 842
+    )  # Printer paper, documents - this is by far the most common
+    A5 = Dimensions(420, 595)  # Paperback books
+    A6 = Dimensions(298, 420)  # Postcards
+    A7 = Dimensions(210, 298)
+    A8 = Dimensions(147, 210)
+
+    # Envelopes
+    C4 = Dimensions(649, 918)
+
+
+_din_a = (
+    PaperSize.A0,
+    PaperSize.A1,
+    PaperSize.A2,
+    PaperSize.A3,
+    PaperSize.A4,
+    PaperSize.A5,
+    PaperSize.A6,
+    PaperSize.A7,
+    PaperSize.A8,
+)
diff --git a/.venv/lib/python3.12/site-packages/pypdf/py.typed b/.venv/lib/python3.12/site-packages/pypdf/py.typed
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/py.typed
diff --git a/.venv/lib/python3.12/site-packages/pypdf/types.py b/.venv/lib/python3.12/site-packages/pypdf/types.py
new file mode 100644
index 00000000..b8fbab92
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/types.py
@@ -0,0 +1,83 @@
+"""Helpers for working with PDF types."""
+
+import sys
+from typing import List, Union
+
+if sys.version_info[:2] >= (3, 8):
+    # Python 3.8+: https://peps.python.org/pep-0586
+    from typing import Literal
+else:
+    from typing_extensions import Literal
+
+if sys.version_info[:2] >= (3, 10):
+    # Python 3.10+: https://www.python.org/dev/peps/pep-0484
+    from typing import TypeAlias
+else:
+    from typing_extensions import TypeAlias
+
+from .generic._base import NameObject, NullObject, NumberObject
+from .generic._data_structures import ArrayObject, Destination
+from .generic._outline import OutlineItem
+
+BorderArrayType: TypeAlias = List[Union[NameObject, NumberObject, ArrayObject]]
+OutlineItemType: TypeAlias = Union[OutlineItem, Destination]
+FitType: TypeAlias = Literal[
+    "/XYZ", "/Fit", "/FitH", "/FitV", "/FitR", "/FitB", "/FitBH", "/FitBV"
+]
+# Those go with the FitType: They specify values for the fit
+ZoomArgType: TypeAlias = Union[NumberObject, NullObject, float]
+ZoomArgsType: TypeAlias = List[ZoomArgType]
+
+# Recursive types like the following are not yet supported by mypy:
+#    OutlineType = List[Union[Destination, "OutlineType"]]
+# See https://github.com/python/mypy/issues/731
+# Hence use this for the moment:
+OutlineType = List[Union[Destination, List[Union[Destination, List[Destination]]]]]
+
+LayoutType: TypeAlias = Literal[
+    "/NoLayout",
+    "/SinglePage",
+    "/OneColumn",
+    "/TwoColumnLeft",
+    "/TwoColumnRight",
+    "/TwoPageLeft",
+    "/TwoPageRight",
+]
+PagemodeType: TypeAlias = Literal[
+    "/UseNone",
+    "/UseOutlines",
+    "/UseThumbs",
+    "/FullScreen",
+    "/UseOC",
+    "/UseAttachments",
+]
+AnnotationSubtype: TypeAlias = Literal[
+    "/Text",
+    "/Link",
+    "/FreeText",
+    "/Line",
+    "/Square",
+    "/Circle",
+    "/Polygon",
+    "/PolyLine",
+    "/Highlight",
+    "/Underline",
+    "/Squiggly",
+    "/StrikeOut",
+    "/Caret",
+    "/Stamp",
+    "/Ink",
+    "/Popup",
+    "/FileAttachment",
+    "/Sound",
+    "/Movie",
+    "/Screen",
+    "/Widget",
+    "/PrinterMark",
+    "/TrapNet",
+    "/Watermark",
+    "/3D",
+    "/Redact",
+    "/Projection",
+    "/RichMedia",
+]
diff --git a/.venv/lib/python3.12/site-packages/pypdf/xmp.py b/.venv/lib/python3.12/site-packages/pypdf/xmp.py
new file mode 100644
index 00000000..df55c905
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pypdf/xmp.py
@@ -0,0 +1,392 @@
+"""
+Anything related to Extensible Metadata Platform (XMP) metadata.
+
+https://en.wikipedia.org/wiki/Extensible_Metadata_Platform
+"""
+
+import datetime
+import decimal
+import re
+from typing import (
+    Any,
+    Callable,
+    Dict,
+    Iterator,
+    List,
+    Optional,
+    TypeVar,
+    Union,
+)
+from xml.dom.minidom import Document, parseString
+from xml.dom.minidom import Element as XmlElement
+from xml.parsers.expat import ExpatError
+
+from ._utils import StreamType, deprecate_no_replacement
+from .errors import PdfReadError
+from .generic import ContentStream, PdfObject
+
+RDF_NAMESPACE = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+DC_NAMESPACE = "http://purl.org/dc/elements/1.1/"
+XMP_NAMESPACE = "http://ns.adobe.com/xap/1.0/"
+PDF_NAMESPACE = "http://ns.adobe.com/pdf/1.3/"
+XMPMM_NAMESPACE = "http://ns.adobe.com/xap/1.0/mm/"
+
+# What is the PDFX namespace, you might ask?
+# It's documented here: https://github.com/adobe/xmp-docs/raw/master/XMPSpecifications/XMPSpecificationPart3.pdf
+# This namespace is used to place "custom metadata"
+# properties, which are arbitrary metadata properties with no semantic or
+# documented meaning.
+#
+# Elements in the namespace are key/value-style storage,
+# where the element name is the key and the content is the value. The keys
+# are transformed into valid XML identifiers by substituting an invalid
+# identifier character with \u2182 followed by the unicode hex ID of the
+# original character. A key like "my car" is therefore "my\u21820020car".
+#
+# \u2182 is the unicode character \u{ROMAN NUMERAL TEN THOUSAND}
+#
+# The pdfx namespace should be avoided.
+# A custom data schema and sensical XML elements could be used instead, as is
+# suggested by Adobe's own documentation on XMP under "Extensibility of
+# Schemas".
+PDFX_NAMESPACE = "http://ns.adobe.com/pdfx/1.3/"
+
+iso8601 = re.compile(
+    """
+        (?P<year>[0-9]{4})
+        (-
+            (?P<month>[0-9]{2})
+            (-
+                (?P<day>[0-9]+)
+                (T
+                    (?P<hour>[0-9]{2}):
+                    (?P<minute>[0-9]{2})
+                    (:(?P<second>[0-9]{2}(.[0-9]+)?))?
+                    (?P<tzd>Z|[-+][0-9]{2}:[0-9]{2})
+                )?
+            )?
+        )?
+        """,
+    re.VERBOSE,
+)
+
+
+K = TypeVar("K")
+
+
+def _identity(value: K) -> K:
+    return value
+
+
+def _converter_date(value: str) -> datetime.datetime:
+    matches = iso8601.match(value)
+    if matches is None:
+        raise ValueError(f"Invalid date format: {value}")
+    year = int(matches.group("year"))
+    month = int(matches.group("month") or "1")
+    day = int(matches.group("day") or "1")
+    hour = int(matches.group("hour") or "0")
+    minute = int(matches.group("minute") or "0")
+    second = decimal.Decimal(matches.group("second") or "0")
+    seconds_dec = second.to_integral(decimal.ROUND_FLOOR)
+    milliseconds_dec = (second - seconds_dec) * 1_000_000
+
+    seconds = int(seconds_dec)
+    milliseconds = int(milliseconds_dec)
+
+    tzd = matches.group("tzd") or "Z"
+    dt = datetime.datetime(year, month, day, hour, minute, seconds, milliseconds)
+    if tzd != "Z":
+        tzd_hours, tzd_minutes = (int(x) for x in tzd.split(":"))
+        tzd_hours *= -1
+        if tzd_hours < 0:
+            tzd_minutes *= -1
+        dt = dt + datetime.timedelta(hours=tzd_hours, minutes=tzd_minutes)
+    return dt
+
+
+def _getter_bag(
+    namespace: str, name: str
+) -> Callable[["XmpInformation"], Optional[List[str]]]:
+    def get(self: "XmpInformation") -> Optional[List[str]]:
+        cached = self.cache.get(namespace, {}).get(name)
+        if cached:
+            return cached
+        retval = []
+        for element in self.get_element("", namespace, name):
+            bags = element.getElementsByTagNameNS(RDF_NAMESPACE, "Bag")
+            if len(bags):
+                for bag in bags:
+                    for item in bag.getElementsByTagNameNS(RDF_NAMESPACE, "li"):
+                        value = self._get_text(item)
+                        retval.append(value)
+        ns_cache = self.cache.setdefault(namespace, {})
+        ns_cache[name] = retval
+        return retval
+
+    return get
+
+
+def _getter_seq(
+    namespace: str, name: str, converter: Callable[[Any], Any] = _identity
+) -> Callable[["XmpInformation"], Optional[List[Any]]]:
+    def get(self: "XmpInformation") -> Optional[List[Any]]:
+        cached = self.cache.get(namespace, {}).get(name)
+        if cached:
+            return cached
+        retval = []
+        for element in self.get_element("", namespace, name):
+            seqs = element.getElementsByTagNameNS(RDF_NAMESPACE, "Seq")
+            if len(seqs):
+                for seq in seqs:
+                    for item in seq.getElementsByTagNameNS(RDF_NAMESPACE, "li"):
+                        value = self._get_text(item)
+                        value = converter(value)
+                        retval.append(value)
+            else:
+                value = converter(self._get_text(element))
+                retval.append(value)
+        ns_cache = self.cache.setdefault(namespace, {})
+        ns_cache[name] = retval
+        return retval
+
+    return get
+
+
+def _getter_langalt(
+    namespace: str, name: str
+) -> Callable[["XmpInformation"], Optional[Dict[Any, Any]]]:
+    def get(self: "XmpInformation") -> Optional[Dict[Any, Any]]:
+        cached = self.cache.get(namespace, {}).get(name)
+        if cached:
+            return cached
+        retval = {}
+        for element in self.get_element("", namespace, name):
+            alts = element.getElementsByTagNameNS(RDF_NAMESPACE, "Alt")
+            if len(alts):
+                for alt in alts:
+                    for item in alt.getElementsByTagNameNS(RDF_NAMESPACE, "li"):
+                        value = self._get_text(item)
+                        retval[item.getAttribute("xml:lang")] = value
+            else:
+                retval["x-default"] = self._get_text(element)
+        ns_cache = self.cache.setdefault(namespace, {})
+        ns_cache[name] = retval
+        return retval
+
+    return get
+
+
+def _getter_single(
+    namespace: str, name: str, converter: Callable[[str], Any] = _identity
+) -> Callable[["XmpInformation"], Optional[Any]]:
+    def get(self: "XmpInformation") -> Optional[Any]:
+        cached = self.cache.get(namespace, {}).get(name)
+        if cached:
+            return cached
+        value = None
+        for element in self.get_element("", namespace, name):
+            if element.nodeType == element.ATTRIBUTE_NODE:
+                value = element.nodeValue
+            else:
+                value = self._get_text(element)
+            break
+        if value is not None:
+            value = converter(value)
+        ns_cache = self.cache.setdefault(namespace, {})
+        ns_cache[name] = value
+        return value
+
+    return get
+
+
+class XmpInformation(PdfObject):
+    """
+    An object that represents Extensible Metadata Platform (XMP) metadata.
+    Usually accessed by :py:attr:`xmp_metadata()<pypdf.PdfReader.xmp_metadata>`.
+
+    Raises:
+      PdfReadError: if XML is invalid
+    """
+
+    def __init__(self, stream: ContentStream) -> None:
+        self.stream = stream
+        try:
+            data = self.stream.get_data()
+            doc_root: Document = parseString(data)  # noqa: S318
+        except ExpatError as e:
+            raise PdfReadError(f"XML in XmpInformation was invalid: {e}")
+        self.rdf_root: XmlElement = doc_root.getElementsByTagNameNS(
+            RDF_NAMESPACE, "RDF"
+        )[0]
+        self.cache: Dict[Any, Any] = {}
+
+    def write_to_stream(
+        self, stream: StreamType, encryption_key: Union[None, str, bytes] = None
+    ) -> None:
+        if encryption_key is not None:  # deprecated
+            deprecate_no_replacement(
+                "the encryption_key parameter of write_to_stream", "5.0.0"
+            )
+        self.stream.write_to_stream(stream)
+
+    def get_element(self, about_uri: str, namespace: str, name: str) -> Iterator[Any]:
+        for desc in self.rdf_root.getElementsByTagNameNS(RDF_NAMESPACE, "Description"):
+            if desc.getAttributeNS(RDF_NAMESPACE, "about") == about_uri:
+                attr = desc.getAttributeNodeNS(namespace, name)
+                if attr is not None:
+                    yield attr
+                yield from desc.getElementsByTagNameNS(namespace, name)
+
+    def get_nodes_in_namespace(self, about_uri: str, namespace: str) -> Iterator[Any]:
+        for desc in self.rdf_root.getElementsByTagNameNS(RDF_NAMESPACE, "Description"):
+            if desc.getAttributeNS(RDF_NAMESPACE, "about") == about_uri:
+                for i in range(desc.attributes.length):
+                    attr = desc.attributes.item(i)
+                    if attr.namespaceURI == namespace:
+                        yield attr
+                for child in desc.childNodes:
+                    if child.namespaceURI == namespace:
+                        yield child
+
+    def _get_text(self, element: XmlElement) -> str:
+        text = ""
+        for child in element.childNodes:
+            if child.nodeType == child.TEXT_NODE:
+                text += child.data
+        return text
+
+    dc_contributor = property(_getter_bag(DC_NAMESPACE, "contributor"))
+    """
+    Contributors to the resource (other than the authors).
+
+    An unsorted array of names.
+    """
+
+    dc_coverage = property(_getter_single(DC_NAMESPACE, "coverage"))
+    """Text describing the extent or scope of the resource."""
+
+    dc_creator = property(_getter_seq(DC_NAMESPACE, "creator"))
+    """A sorted array of names of the authors of the resource, listed in order
+    of precedence."""
+
+    dc_date = property(_getter_seq(DC_NAMESPACE, "date", _converter_date))
+    """
+    A sorted array of dates (datetime.datetime instances) of significance to
+    the resource.
+
+    The dates and times are in UTC.
+    """
+
+    dc_description = property(_getter_langalt(DC_NAMESPACE, "description"))
+    """A language-keyed dictionary of textual descriptions of the content of the
+    resource."""
+
+    dc_format = property(_getter_single(DC_NAMESPACE, "format"))
+    """The mime-type of the resource."""
+
+    dc_identifier = property(_getter_single(DC_NAMESPACE, "identifier"))
+    """Unique identifier of the resource."""
+
+    dc_language = property(_getter_bag(DC_NAMESPACE, "language"))
+    """An unordered array specifying the languages used in the resource."""
+
+    dc_publisher = property(_getter_bag(DC_NAMESPACE, "publisher"))
+    """An unordered array of publisher names."""
+
+    dc_relation = property(_getter_bag(DC_NAMESPACE, "relation"))
+    """An unordered array of text descriptions of relationships to other
+    documents."""
+
+    dc_rights = property(_getter_langalt(DC_NAMESPACE, "rights"))
+    """A language-keyed dictionary of textual descriptions of the rights the
+    user has to this resource."""
+
+    dc_source = property(_getter_single(DC_NAMESPACE, "source"))
+    """Unique identifier of the work from which this resource was derived."""
+
+    dc_subject = property(_getter_bag(DC_NAMESPACE, "subject"))
+    """An unordered array of descriptive phrases or keywrods that specify the
+    topic of the content of the resource."""
+
+    dc_title = property(_getter_langalt(DC_NAMESPACE, "title"))
+    """A language-keyed dictionary of the title of the resource."""
+
+    dc_type = property(_getter_bag(DC_NAMESPACE, "type"))
+    """An unordered array of textual descriptions of the document type."""
+
+    pdf_keywords = property(_getter_single(PDF_NAMESPACE, "Keywords"))
+    """An unformatted text string representing document keywords."""
+
+    pdf_pdfversion = property(_getter_single(PDF_NAMESPACE, "PDFVersion"))
+    """The PDF file version, for example 1.0 or 1.3."""
+
+    pdf_producer = property(_getter_single(PDF_NAMESPACE, "Producer"))
+    """The name of the tool that created the PDF document."""
+
+    xmp_create_date = property(
+        _getter_single(XMP_NAMESPACE, "CreateDate", _converter_date)
+    )
+    """
+    The date and time the resource was originally created.
+
+    The date and time are returned as a UTC datetime.datetime object.
+    """
+
+    xmp_modify_date = property(
+        _getter_single(XMP_NAMESPACE, "ModifyDate", _converter_date)
+    )
+    """
+    The date and time the resource was last modified.
+
+    The date and time are returned as a UTC datetime.datetime object.
+    """
+
+    xmp_metadata_date = property(
+        _getter_single(XMP_NAMESPACE, "MetadataDate", _converter_date)
+    )
+    """
+    The date and time that any metadata for this resource was last changed.
+
+    The date and time are returned as a UTC datetime.datetime object.
+    """
+
+    xmp_creator_tool = property(_getter_single(XMP_NAMESPACE, "CreatorTool"))
+    """The name of the first known tool used to create the resource."""
+
+    xmpmm_document_id = property(_getter_single(XMPMM_NAMESPACE, "DocumentID"))
+    """The common identifier for all versions and renditions of this resource."""
+
+    xmpmm_instance_id = property(_getter_single(XMPMM_NAMESPACE, "InstanceID"))
+    """An identifier for a specific incarnation of a document, updated each
+    time a file is saved."""
+
+    @property
+    def custom_properties(self) -> Dict[Any, Any]:
+        """
+        Retrieve custom metadata properties defined in the undocumented pdfx
+        metadata schema.
+
+        Returns:
+            A dictionary of key/value items for custom metadata properties.
+        """
+        if not hasattr(self, "_custom_properties"):
+            self._custom_properties = {}
+            for node in self.get_nodes_in_namespace("", PDFX_NAMESPACE):
+                key = node.localName
+                while True:
+                    # see documentation about PDFX_NAMESPACE earlier in file
+                    idx = key.find("\u2182")
+                    if idx == -1:
+                        break
+                    key = (
+                        key[:idx]
+                        + chr(int(key[idx + 1 : idx + 5], base=16))
+                        + key[idx + 5 :]
+                    )
+                if node.nodeType == node.ATTRIBUTE_NODE:
+                    value = node.nodeValue
+                else:
+                    value = self._get_text(node)
+                self._custom_properties[key] = value
+        return self._custom_properties